static size_t parseM3u8(char *buf, ssize_t len, request_param *r,mod_config *cfg) { debug(207, 3)("parse_M3u8 input buf len=[%zd],input_buf=[%s]",len,buf); char *p_read=NULL, *p_begin, *p_end; char *line = NULL; bool has_crlf = false; char url[MAX_URL]={'\0'}; assert(buf); if (memBufIsNull(&(r->prevBuf))) { memBufDefInit(&(r->prevBuf)); } MemBuf curBuf; memBufDefInit(&curBuf); memBufAppend(&curBuf, r->prevBuf.buf, r->prevBuf.size); memBufReset(&(r->prevBuf)); memBufAppend(&curBuf, buf, len); debug(207, 3)("cfg->beforeAdding=%s,Before_flag=%d\n",cfg->beforeAdding,cfg->Before_flag); p_begin = curBuf.buf; p_end = p_begin + curBuf.size; while ((line = ReadLine(p_begin, p_end - p_begin, &p_read, &has_crlf)) != NULL) { p_begin = p_read; if (has_crlf) { if (line[0] == '#') continue; if (cfg->Before_flag == true) { snprintf(url, MAX_URL, "%s%s",cfg->beforeAdding,line); debug(207, 3)("has beforeAdding url=%s\n",url); } else { snprintf(url, MAX_URL, "%s%s",r->default_prefix,line); debug(207, 3)("default url=%s\n", url); } //asyncPrefetchTs(url); sendUrlToM3u8Helper(r,url); debug(207, 3)("parseLine line = %s,has_crlf=%d\n",line,has_crlf); } else { debug(207, 3)("prevbuf line= %s,has_crlf=%d,len(line)=%zu\n", line,has_crlf,strlen(line)); memBufAppend(&(r->prevBuf), line, strlen(line)); } xfree(line); } debug(207, 3) ("parseLine p_read = %s,has_crlf=%d\n",p_read, has_crlf); memBufClean(&curBuf); return 0; }
void storeLog(int tag, const StoreEntry * e) { MemBuf mb; MemObject *mem = e->mem_obj; HttpReply *reply; if (storelog_fd < 0) return; if (mem == NULL) return; if (EBIT_TEST(e->flags, ENTRY_DONT_LOG)) return; if (mem->log_url == NULL) { debug(20, 1) ("storeLog: NULL log_url for %s\n", mem->url); storeMemObjectDump(mem); mem->log_url = xstrdup(mem->url); } memBufDefInit(&mb); reply = mem->reply; memBufPrintf(&mb, "%9d.%03d %-7s %08X %4d %9d %9d %9d %s %d/%d %s %s\n", (int) current_time.tv_sec, (int) current_time.tv_usec / 1000, storeLogTags[tag], e->swap_file_number, reply->sline.status, (int) reply->date, (int) reply->last_modified, (int) reply->expires, strLen(reply->content_type) ? strBuf(reply->content_type) : "unknown", reply->content_length, (int) (mem->inmem_hi - mem->reply->hdr_sz), RequestMethodStr[mem->method], mem->log_url); file_write_mbuf(storelog_fd, -1, mb, NULL, NULL); }
static void sslProxyConnected(int fd, void *data) { SslStateData *sslState = data; MemBuf mb; HttpHeader hdr_out; Packer p; http_state_flags flags; debug(26, 3) ("sslProxyConnected: FD %d sslState=%p\n", fd, sslState); memset(&flags, '\0', sizeof(flags)); memBufDefInit(&mb); memBufPrintf(&mb, "CONNECT %s HTTP/1.0\r\n", sslState->url); httpBuildRequestHeader(sslState->request, sslState->request, NULL, /* StoreEntry */ &hdr_out, sslState->client.fd, flags); /* flags */ packerToMemInit(&p, &mb); httpHeaderPackInto(&hdr_out, &p); httpHeaderClean(&hdr_out); packerClean(&p); memBufAppend(&mb, "\r\n", 2); xstrncpy(sslState->client.buf, mb.buf, SQUID_TCP_SO_RCVBUF); debug(26, 3) ("sslProxyConnected: Sending {%s}\n", sslState->client.buf); sslState->client.len = mb.size; memBufClean(&mb); commSetTimeout(sslState->server.fd, Config.Timeout.read, sslTimeout, sslState); sslSetSelect(sslState); }
static void identConnectDone(int fd, int status, void *data) { IdentStateData *state = data; IdentClient *c; MemBuf mb; if (status != COMM_OK) { /* Failed to connect */ comm_close(fd); return; } /* * see if our clients still care */ for (c = state->clients; c; c = c->next) { if (cbdataValid(c->callback_data)) break; } if (c == NULL) { /* no clients care */ comm_close(fd); return; } memBufDefInit(&mb); memBufPrintf(&mb, "%d, %d\r\n", ntohs(state->my_peer.sin_port), ntohs(state->me.sin_port)); comm_write_mbuf(fd, mb, NULL, state); commSetSelect(fd, COMM_SELECT_READ, identReadReply, state, 0); commSetTimeout(fd, Config.Timeout.ident, identTimeout, state); }
void refreshCheckSubmit(StoreEntry * entry, REFRESHCHECK * callback, void *callback_data) { MemBuf buf; const char *key; refresh_check_helper *def = Config.Program.refresh_check; refreshCheckState *state; dlink_node *node; refreshCheckState *oldstate = NULL; if (!def) { callback(callback_data, 0, NULL); return; } key = makeRefreshCheckRequest(entry, def->format); if (!key) { callback(callback_data, 0, NULL); return; } debug(84, 2) ("refreshCheckSubmit: for '%s'\n", key); /* Check for a pending lookup to hook into */ for (node = def->queue.head; node; node = node->next) { refreshCheckState *oldstatetmp = node->data; if (entry == oldstatetmp->entry) { oldstate = oldstatetmp; break; } } state = cbdataAlloc(refreshCheckState); state->def = def; cbdataLock(state->def); state->entry = entry; storeLockObject(entry); state->callback = callback; state->callback_data = callback_data; cbdataLock(state->callback_data); if (oldstate) { /* Hook into pending lookup */ state->queue = oldstate->queue; oldstate->queue = state; } else { /* No pending lookup found. Sumbit to helper */ /* Check for queue overload */ if (refreshCheckOverload(def)) { debug(84, 1) ("refreshCheckSubmit: queue overload\n"); cbdataFree(state); callback(callback_data, 0, "Overload"); return; } /* Send it off to the helper */ memBufDefInit(&buf); memBufPrintf(&buf, "%s\n", key); helperSubmit(def->helper, buf.buf, refreshCheckHandleReply, state); dlinkAdd(state, &state->list, &def->queue); memBufClean(&buf); } }
/* used by httpHeaderPutStrf */ static void httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs) { MemBuf mb; memBufDefInit(&mb); memBufVPrintf(&mb, fmt, vargs); httpHeaderPutStr(hdr, id, mb.buf); memBufClean(&mb); }
/* create MIME Header for Gopher Data */ static void gopherMimeCreate(GopherStateData * gopherState) { MemBuf mb; memBufDefInit(&mb); memBufPrintf(&mb, "HTTP/1.0 200 OK Gatewaying\r\n" "Server: Squid/%s\r\n" "Date: %s\r\n" "MIME-version: 1.0\r\n", version_string, mkrfc1123(squid_curtime)); switch (gopherState->type_id) { case GOPHER_DIRECTORY: case GOPHER_INDEX: case GOPHER_HTML: case GOPHER_WWW: case GOPHER_CSO: memBufPrintf(&mb, "Content-Type: text/html\r\n"); break; case GOPHER_GIF: case GOPHER_IMAGE: case GOPHER_PLUS_IMAGE: memBufPrintf(&mb, "Content-Type: image/gif\r\n"); break; case GOPHER_SOUND: case GOPHER_PLUS_SOUND: memBufPrintf(&mb, "Content-Type: audio/basic\r\n"); break; case GOPHER_PLUS_MOVIE: memBufPrintf(&mb, "Content-Type: video/mpeg\r\n"); break; case GOPHER_MACBINHEX: case GOPHER_DOSBIN: case GOPHER_UUENCODED: case GOPHER_BIN: /* Rightnow We have no idea what it is. */ gopher_mime_content(&mb, gopherState->request, def_gopher_bin); break; case GOPHER_FILE: default: gopher_mime_content(&mb, gopherState->request, def_gopher_text); break; } memBufPrintf(&mb, "\r\n"); EBIT_CLR(gopherState->entry->flags, ENTRY_FWD_HDR_WAIT); storeAppend(gopherState->entry, mb.buf, mb.size); memBufClean(&mb); }
/* create memBuf, create mem-based packer, pack, destroy packer, return MemBuf */ MemBuf httpReplyPack(const HttpReply * rep) { MemBuf mb; Packer p; assert(rep); memBufDefInit(&mb); packerToMemInit(&p, &mb); httpReplyPackInto(rep, &p); packerClean(&p); return mb; }
/* * parses a given string then packs compiled headers and compares the result * with the original, reports discrepancies */ void httpHeaderTestParser(const char *hstr) { static int bug_count = 0; int hstr_len; int parse_success; HttpHeader hdr; int pos; Packer p; MemBuf mb; assert(hstr); /* skip start line if any */ if (!strncasecmp(hstr, "HTTP/", 5)) { const char *p = strchr(hstr, '\n'); if (p) hstr = p + 1; } /* skip invalid first line if any */ if (xisspace(*hstr)) { const char *p = strchr(hstr, '\n'); if (p) hstr = p + 1; } hstr_len = strlen(hstr); /* skip terminator if any */ if (strstr(hstr, "\n\r\n")) hstr_len -= 2; else if (strstr(hstr, "\n\n")) hstr_len -= 1; httpHeaderInit(&hdr, hoReply); /* debugLevels[55] = 8; */ parse_success = httpHeaderParse(&hdr, hstr, hstr + hstr_len); /* debugLevels[55] = 2; */ if (!parse_success) { debug(66, 2) ("TEST (%d): failed to parsed a header: {\n%s}\n", bug_count, hstr); return; } /* we think that we parsed it, veryfy */ memBufDefInit(&mb); packerToMemInit(&p, &mb); httpHeaderPackInto(&hdr, &p); if ((pos = abs(httpHeaderStrCmp(hstr, mb.buf, hstr_len)))) { bug_count++; debug(66, 2) ("TEST (%d): hdr parsing bug (pos: %d near '%s'): expected: {\n%s} got: {\n%s}\n", bug_count, pos, hstr + pos, hstr, mb.buf); } httpHeaderClean(&hdr); packerClean(&p); memBufClean(&mb); }
/* cleans the buffer without changing its capacity * if called with a Null buffer, calls memBufDefInit() */ void memBufReset(MemBuf * mb) { assert(mb); if (memBufIsNull(mb)) { memBufDefInit(mb); } else { assert(!mb->stolen); /* not frozen */ /* reset */ memset(mb->buf, 0, mb->capacity); mb->size = 0; } }
wordlist * aclDumpExternal(void *data) { external_acl_data *acl = data; wordlist *result = NULL; wordlist *arg; MemBuf mb; memBufDefInit(&mb); memBufPrintf(&mb, "%s", acl->def->name); for (arg = acl->arguments; arg; arg = arg->next) { memBufPrintf(&mb, " %s", arg->key); } wordlistAdd(&result, mb.buf); memBufClean(&mb); return result; }
void httpHeaderPutRange(HttpHeader * hdr, const HttpHdrRange * range) { MemBuf mb; Packer p; assert(hdr && range); /* remove old directives if any */ httpHeaderDelById(hdr, HDR_RANGE); /* pack into mb */ memBufDefInit(&mb); packerToMemInit(&p, &mb); httpHdrRangePackInto(range, &p); /* put */ httpHeaderAddEntry(hdr, httpHeaderEntryCreate(HDR_RANGE, NULL, mb.buf)); /* cleanup */ packerClean(&p); memBufClean(&mb); }
void httpHeaderPutCc(HttpHeader * hdr, const HttpHdrCc * cc) { MemBuf mb; Packer p; assert(hdr && cc); /* remove old directives if any */ httpHeaderDelById(hdr, HDR_CACHE_CONTROL); /* pack into mb */ memBufDefInit(&mb); packerToMemInit(&p, &mb); httpHdrCcPackInto(cc, &p); /* put */ httpHeaderAddEntry(hdr, httpHeaderEntryCreate(HDR_CACHE_CONTROL, NULL, mb.buf)); /* cleanup */ packerClean(&p); memBufClean(&mb); }
MemBuf httpPacked304Reply(const HttpReply * rep) { static const http_hdr_type ImsEntries[] = {HDR_DATE, HDR_CONTENT_TYPE, HDR_EXPIRES, HDR_LAST_MODIFIED, /* eof */ HDR_OTHER}; int t; MemBuf mb; Packer p; HttpHeaderEntry *e; assert(rep); memBufDefInit(&mb); packerToMemInit(&p, &mb); memBufPrintf(&mb, "%s", "HTTP/1.0 304 Not Modified\r\n"); for (t = 0; ImsEntries[t] != HDR_OTHER; ++t) if ((e = httpHeaderFindEntry(&rep->header, ImsEntries[t]))) httpHeaderEntryPackInto(e, &p); memBufAppend(&mb, "\r\n", 2); packerClean(&p); return mb; }
/* * httpReplyParse takes character buffer of HTTP headers (buf), * which may not be NULL-terminated, and fills in an HttpReply * structure (rep). The parameter 'end' specifies the offset to * the end of the reply headers. The caller may know where the * end is, but is unable to NULL-terminate the buffer. This function * returns true on success. */ int httpReplyParse(HttpReply * rep, const char *buf, size_t end) { /* * this extra buffer/copy will be eliminated when headers become * meta-data in store. Currently we have to xstrncpy the buffer * becuase somebody may feed a non NULL-terminated buffer to * us. */ MemBuf mb = MemBufNull; int success; /* reset current state, because we are not used in incremental fashion */ httpReplyReset(rep); /* put a string terminator. s is how many bytes to touch in * 'buf' including the terminating NULL. */ memBufDefInit(&mb); memBufAppend(&mb, buf, end); memBufAppend(&mb, "\0", 1); success = httpReplyParseStep(rep, mb.buf, 0); memBufClean(&mb); return success == 1; }
static MemBuf errorBuildContent(ErrorState * err) { MemBuf content; const char *m; const char *p; const char *t; assert(err != NULL); assert(err->page_id > ERR_NONE && err->page_id < error_page_count); memBufDefInit(&content); m = error_text[err->page_id]; assert(m); while ((p = strchr(m, '%'))) { memBufAppend(&content, m, p - m); /* copy */ t = errorConvert(*++p, err); /* convert */ memBufPrintf(&content, "%s", t); /* copy */ m = p + 1; /* advance */ } if (*m) memBufPrintf(&content, "%s", m); /* copy tail */ assert(content.size == strlen(content.buf)); return content; }
void externalAclLookup(aclCheck_t * ch, void *acl_data, EAH * callback, void *callback_data) { MemBuf buf; external_acl_data *acl = acl_data; external_acl *def = acl->def; const char *key; external_acl_entry *entry; externalAclState *state; if (acl->def->require_auth) { int ti; /* Make sure the user is authenticated */ if ((ti = aclAuthenticated(ch)) != 1) { debug(82, 1) ("externalAclLookup: %s user authentication failure (%d)\n", acl->def->name, ti); callback(callback_data, NULL); return; } } key = makeExternalAclKey(ch, acl); if (!key) { debug(82, 1) ("externalAclLookup: lookup in '%s', prerequisit failure\n", def->name); callback(callback_data, NULL); return; } debug(82, 2) ("externalAclLookup: lookup in '%s' for '%s'\n", def->name, key); entry = hash_lookup(def->cache, key); state = cbdataAlloc(externalAclState); state->def = def; cbdataLock(state->def); state->callback = callback; state->callback_data = callback_data; state->key = xstrdup(key); cbdataLock(state->callback_data); if (entry && !external_acl_entry_expired(def, entry)) { if (entry->result == -1) { /* There is a pending lookup. Hook into it */ dlink_node *node; for (node = def->queue.head; node; node = node->next) { externalAclState *oldstate = node->data; if (strcmp(state->key, oldstate->key) == 0) { state->queue = oldstate->queue; oldstate->queue = state; return; } } } else { /* There is a cached valid result.. use it */ /* This should not really happen, but what the heck.. */ callback(callback_data, entry); cbdataFree(state); return; } } /* Check for queue overload */ if (def->helper->stats.queue_size >= def->helper->n_running) { int result = -1; external_acl_entry *entry = hash_lookup(def->cache, key); debug(82, 1) ("externalAclLookup: '%s' queue overload\n", def->name); if (entry) result = entry->result; cbdataFree(state); callback(callback_data, entry); return; } /* Send it off to the helper */ memBufDefInit(&buf); memBufPrintf(&buf, "%s\n", key); helperSubmit(def->helper, buf.buf, externalAclHandleReply, state); external_acl_cache_add(def, key, -1, NULL, NULL); dlinkAdd(state, &state->list, &def->queue); memBufClean(&buf); }
void icapSendRespMod(IcapStateData * icap, char *buf, int len, int theEnd) { MemBuf mb; #if ICAP_PREVIEW int size; const int preview_size = icap->preview_size; #endif debug(81, 5) ("icapSendRespMod: FD %d, len %d, theEnd %d\n", icap->icap_fd, len, theEnd); if (icap->flags.no_content) { /* * ICAP server said there are no modifications to make, so * just append this data to the StoreEntry */ if (icap->respmod.resp_copy.size) { /* * first copy the data that we already sent to the ICAP server */ memBufAppend(&icap->chunk_buf, icap->respmod.resp_copy.buf, icap->respmod.resp_copy.size); icap->respmod.resp_copy.size = 0; } debug(81, 5) ("icapSendRepMod: len=%d theEnd=%d write_pending=%d\n", len, theEnd, icap->flags.write_pending); if (len) { /* * also copy any new data from the HTTP side */ memBufAppend(&icap->chunk_buf, buf, len); } (void) icapReadReply2(icap); return; } if (theEnd) { if (icap->respmod.res_body_sz) icap->flags.send_zero_chunk = 1; icap->flags.http_server_eof = 1; } /* * httpReadReply is going to call us with a chunk and then * right away again with an EOF if httpPconnTransferDone() is true. * Since the first write is already dispatched, we'll have to * hack this in somehow. */ if (icap->flags.write_pending) { debug(81, 3) ("icapSendRespMod: oops, write_pending=1\n"); assert(theEnd); assert(len == 0); return; } if (!cbdataValid(icap)) { debug(81, 3) ("icapSendRespMod: failed to establish connection?\n"); return; } memBufDefInit(&mb); #if SUPPORT_ICAP_204 || ICAP_PREVIEW /* * make a copy of the response in case ICAP server gives us a 204 */ /* * This piece of code is problematic for 204 responces outside preview. * The icap->respmod.resp_copy continues to filled until we had responce * If the icap server waits to gets all data before sends its responce * then we are puting all downloading object to the main system memory. * My opinion is that 204 responces outside preview must be disabled ..... * /chtsanti */ if (len && icap->flags.copy_response) { if (memBufIsNull(&icap->respmod.resp_copy)) memBufDefInit(&icap->respmod.resp_copy); memBufAppend(&icap->respmod.resp_copy, buf, len); } #endif if (icap->sc == 0) { /* No data sent yet. Start with headers */ if((icap->sc = buildRespModHeader(&mb, icap, buf, len, theEnd))>0){ buf += icap->sc; len -= icap->sc; } /* * Then we do not have http responce headers. All data (previous and those in buf) * now are exist to icap->respmod.req_hdr_copy. Lets get them back....... */ if(icap->sc <0){ memBufAppend(&icap->respmod.buffer, icap->respmod.req_hdr_copy.buf, icap->respmod.req_hdr_copy.size); icap->sc=icap->respmod.req_hdr_copy.size; icap->respmod.req_hdr_copy.size=0; buf=NULL; len=0; } } if (0 == icap->sc) { /* check again; bail if we're not ready to send ICAP/HTTP hdrs */ debug(81, 5) ("icapSendRespMod: dont have full HTTP response hdrs\n"); memBufClean(&mb); return; } #if ICAP_PREVIEW if (preview_size < 0 || !Config.icapcfg.preview_enable) /* preview feature off */ icap->flags.preview_done = 1; if (!icap->flags.preview_done) { /* preview not yet sent */ if (icap->sc > 0 && icap->respmod.buffer.size <= preview_size && len > 0) { /* Try to collect at least preview_size+1 bytes */ /* By collecting one more byte than needed for preview we know best */ /* whether we have to send the ieof chunk extension */ size = icap->respmod.buffer.size + len; if (size > preview_size + 1) size = preview_size + 1; size -= icap->respmod.buffer.size; debug(81, 3) ("icapSendRespMod: FD %d: copy %d more bytes to preview buffer.\n", icap->icap_fd, size); memBufAppend(&icap->respmod.buffer, buf, size); buf = ((char *) buf) + size; len -= size; } if (icap->respmod.buffer.size > preview_size || theEnd) { /* we got enough bytes for preview or this is the last call */ /* add preview preview now */ if (icap->respmod.buffer.size > 0) { size = icap->respmod.buffer.size; if (size > preview_size) size = preview_size; memBufPrintf(&mb, "%x\r\n", size); memBufAppend(&mb, icap->respmod.buffer.buf, size); memBufAppend(&mb, crlf, 2); icap->sc += size; } if (icap->respmod.buffer.size <= preview_size) { /* content length is less than preview size+1 */ if (icap->respmod.res_body_sz) memBufAppend(&mb, "0; ieof\r\n\r\n", 11); memBufReset(&icap->respmod.buffer); /* will now be used for other data */ } else { char ch; memBufAppend(&mb, "0\r\n\r\n", 5); /* end of preview, wait for continue or 204 signal */ /* copy the extra byte and all other data to the icap buffer */ /* so that it can be handled next time */ ch = icap->respmod.buffer.buf[preview_size]; memBufReset(&icap->respmod.buffer); /* will now be used for other data */ memBufAppend(&icap->respmod.buffer, &ch, 1); debug(81, 3) ("icapSendRespMod: FD %d: sending preview and keeping %d bytes in internal buf.\n", icap->icap_fd, len + 1); if (len > 0) memBufAppend(&icap->respmod.buffer, buf, len); } icap->flags.preview_done = 1; icap->flags.wait_for_preview_reply = 1; } } else if (icap->flags.wait_for_preview_reply) { /* received new data while waiting for preview response */ /* add data to internal buffer and send later */ debug(81, 3) ("icapSendRespMod: FD %d: add %d more bytes to internal buf while waiting for preview-response.\n", icap->icap_fd, len); if (len > 0) memBufAppend(&icap->respmod.buffer, buf, len); /* do not send any data now while waiting for preview response */ /* but prepare for read more data on the HTTP connection */ memBufClean(&mb); return; } else #endif { /* after preview completed and ICAP preview response received */ /* there may still be some data in the buffer */ if (icap->respmod.buffer.size > 0) { memBufPrintf(&mb, "%x\r\n", icap->respmod.buffer.size); memBufAppend(&mb, icap->respmod.buffer.buf, icap->respmod.buffer.size); memBufAppend(&mb, crlf, 2); icap->sc += icap->respmod.buffer.size; memBufReset(&icap->respmod.buffer); } if (len > 0) { memBufPrintf(&mb, "%x\r\n", len); memBufAppend(&mb, buf, len); memBufAppend(&mb, crlf, 2); icap->sc += len; } if (icap->flags.send_zero_chunk) { /* send zero end chunk */ icap->flags.send_zero_chunk = 0; icap->flags.http_server_eof = 1; memBufAppend(&mb, "0\r\n\r\n", 5); } /* wait for data coming from ICAP server as soon as we sent something */ /* but of course only until we got the response header */ if (!icap->flags.got_reply) icap->flags.wait_for_reply = 1; } commSetTimeout(icap->icap_fd, -1, NULL, NULL); if (!mb.size) { memBufClean(&mb); return; } debug(81, 5) ("icapSendRespMod: FD %d writing {%s}\n", icap->icap_fd, mb.buf); icap->flags.write_pending = 1; comm_write_mbuf(icap->icap_fd, mb, icapSendRespModDone, icap); }
IcapStateData * icapRespModStart(icap_service_t type, request_t * request, StoreEntry * entry, http_state_flags http_flags) { IcapStateData *icap = NULL; CNCB *theCallback = NULL; icap_service *service = NULL; debug(81, 3) ("icapRespModStart: type=%d\n", (int) type); assert(type >= 0 && type < ICAP_SERVICE_MAX); service = icapService(type, request); if (!service) { debug(81, 3) ("icapRespModStart: no service found\n"); return NULL; /* no service found */ } if (service->unreachable) { if (service->bypass) { debug(81, 5) ("icapRespModStart: BYPASS because service unreachable: %s\n", service->uri); return NULL; } else { debug(81, 5) ("icapRespModStart: ERROR because service unreachable: %s\n", service->uri); return (IcapStateData *) - 1; } } switch (type) { /* TODO: When we support more than ICAP_SERVICE_RESPMOD_PRECACHE, we needs to change * this switch, because callbacks isn't keep */ case ICAP_SERVICE_RESPMOD_PRECACHE: theCallback = icapConnectOver; break; default: fatalf("icapRespModStart: unsupported service type '%s'\n", icap_service_type_str[type]); break; } icap = icapAllocate(); if (!icap) { debug(81, 3) ("icapRespModStart: icapAllocate() failed\n"); return NULL; } icap->request = requestLink(request); icap->respmod.entry = entry; if (entry) storeLockObject(entry); icap->http_flags = http_flags; memBufDefInit(&icap->respmod.buffer); memBufDefInit(&icap->chunk_buf); icap->current_service = service; icap->preview_size = service->preview; /* * Don't create socket to the icap server now, but only for the first * packet receive from the http server. This will resolve all timeout * between the web server and icap server. */ debug(81, 3) ("icapRespModStart: setting connect_requested to 0\n"); icap->flags.connect_requested = 0; /* * make a copy the HTTP response that we send to the ICAP server in * case it turns out to be a 204 */ #ifdef SUPPORT_ICAP_204 icap->flags.copy_response = 1; #elif ICAP_PREVIEW if(preview_size < 0 || !Config.icapcfg.preview_enable) icap->flags.copy_response = 0; else icap->flags.copy_response = 1; #else icap->flags.copy_response = 0; #endif statCounter.icap.all.requests++; debug(81, 3) ("icapRespModStart: returning %p\n", icap); return icap; }
static int buildRespModHeader(MemBuf * mb, IcapStateData * icap, char *buf, ssize_t len, int theEnd) { MemBuf mb_hdr; char *client_addr; int o2=0; int o3=0; int hlen; int consumed; icap_service *service; HttpReply *r; if (memBufIsNull(&icap->respmod.req_hdr_copy)) memBufDefInit(&icap->respmod.req_hdr_copy); memBufAppend(&icap->respmod.req_hdr_copy, buf, len); if (icap->respmod.req_hdr_copy.size > 4 && strncmp(icap->respmod.req_hdr_copy.buf, "HTTP/", 5)) { debug(81, 3) ("buildRespModHeader: Non-HTTP-compliant header: '%s'\n", buf); /* *Possible we can consider that we did not have http responce headers *(maybe HTTP 0.9 protocol), lets returning -1... */ consumed=-1; o2=-1; memBufDefInit(&mb_hdr); } else{ hlen = headersEnd(icap->respmod.req_hdr_copy.buf, icap->respmod.req_hdr_copy.size); debug(81, 3) ("buildRespModHeader: headersEnd = %d(%s)\n", hlen,buf); if (0 == hlen) return 0; /* * calc how many bytes from this 'buf' went towards the * reply header. */ consumed = hlen - (icap->respmod.req_hdr_copy.size - len); debug(81, 3) ("buildRespModHeader: consumed = %d\n", consumed); /* * now, truncate our req_hdr_copy at the header end. * this 'if' statement might be unncessary? */ if (hlen < icap->respmod.req_hdr_copy.size) icap->respmod.req_hdr_copy.size = hlen; /* Copy request header */ memBufDefInit(&mb_hdr); httpBuildRequestPrefix(icap->request, icap->request, icap->respmod.entry, &mb_hdr, icap->http_flags); o2 = mb_hdr.size; } /* Copy response header - Append to request header mbuffer */ memBufAppend(&mb_hdr, icap->respmod.req_hdr_copy.buf, icap->respmod.req_hdr_copy.size); o3 = mb_hdr.size; service = icap->current_service; assert(service); client_addr = inet_ntoa(icap->request->client_addr); r = httpReplyCreate(); httpReplyParse(r, icap->respmod.req_hdr_copy.buf, icap->respmod.req_hdr_copy.size); icap->respmod.res_body_sz = httpReplyBodySize(icap->request->method, r); httpReplyDestroy(r); if (icap->respmod.res_body_sz) getICAPRespModString(mb, 0, o2, o3, client_addr, icap, service); else getICAPRespModString(mb, 0, o2, -o3, client_addr, icap, service); if (Config.icapcfg.preview_enable) if (icap->preview_size >= 0) { memBufPrintf(mb, "Preview: %d\r\n", icap->preview_size); icap->flags.preview_done = 0; } if(service->keep_alive){ icap->flags.keep_alive = 1; memBufAppend(mb, "Connection: keep-alive\r\n", 24); } else{ icap->flags.keep_alive = 0; memBufAppend(mb, "Connection: close\r\n", 19); } memBufAppend(mb, crlf, 2); memBufAppend(mb, mb_hdr.buf, mb_hdr.size); memBufClean(&mb_hdr); return consumed; }
/* * The helper program receives queries on stdin, one * per line, and must return the result on on stdout */ static void refreshCheckHandleReply(void *data, char *reply) { refreshCheckState *state = data; refreshCheckState *next; int freshness = -1; char *log = NULL; MemBuf hdrs = MemBufNULL; debug(84, 2) ("refreshCheckHandleReply: reply=\"%s\"\n", reply); if (reply) { char *t = NULL; char *token = strwordtok(reply, &t); if (token && strcmp(token, "FRESH") == 0) freshness = 0; else if (token && strcmp(token, "OK") == 0) freshness = 0; while ((token = strwordtok(NULL, &t))) { char *value = strchr(token, '='); if (value) { *value++ = '\0'; /* terminate the token, and move up to the value */ rfc1738_unescape(value); if (strcmp(token, "freshness") == 0) freshness = atoi(value); else if (strcmp(token, "log") == 0) log = value; else if (strncmp(token, "res{", 4) == 0) { char *header, *t; header = token + 4; t = strrchr(header, '}'); if (!t) continue; *t = '\0'; if (!hdrs.buf) memBufDefInit(&hdrs); memBufPrintf(&hdrs, "%s: %s\r\n", header, value); } } } } if (freshness >= 0) { if (hdrs.size) { HttpReply *rep = httpReplyCreate(); httpHeaderParse(&rep->header, hdrs.buf, hdrs.buf + hdrs.size); httpReplyUpdateOnNotModified(state->entry->mem_obj->reply, rep); storeTimestampsSet(state->entry); if (!httpHeaderHas(&rep->header, HDR_DATE)) { state->entry->timestamp = squid_curtime; state->entry->expires = squid_curtime + freshness; } else if (freshness) { state->entry->expires = squid_curtime + freshness; } httpReplyDestroy(rep); storeUpdate(state->entry, NULL); } else { state->entry->timestamp = squid_curtime; state->entry->expires = squid_curtime + freshness; } } if (hdrs.buf) memBufClean(&hdrs); dlinkDelete(&state->list, &state->def->queue); do { cbdataUnlock(state->def); state->def = NULL; if (state->callback && cbdataValid(state->callback_data)) state->callback(state->callback_data, freshness >= 0, log); cbdataUnlock(state->callback_data); state->callback_data = NULL; next = state->queue; cbdataFree(state); state = next; } while (state); }
static void urnHandleReply(void *data, char *buf, ssize_t size) { UrnState *urnState = data; StoreEntry *e = urnState->entry; StoreEntry *urlres_e = urnState->urlres_e; char *s = NULL; size_t k; HttpReply *rep; url_entry *urls; url_entry *u; url_entry *min_u; MemBuf mb; ErrorState *err; int i; int urlcnt = 0; http_version_t version; debug(52, 3) ("urnHandleReply: Called with size=%d.\n", (int) size); if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED)) { memFree(buf, MEM_4K_BUF); return; } if (size == 0) { memFree(buf, MEM_4K_BUF); return; } else if (size < 0) { memFree(buf, MEM_4K_BUF); return; } if (urlres_e->store_status == STORE_PENDING && size < SM_PAGE_SIZE) { storeClientCopy(urnState->sc, urlres_e, size, 0, SM_PAGE_SIZE, buf, urnHandleReply, urnState); return; } /* we know its STORE_OK */ k = headersEnd(buf, size); if (0 == k) { debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %s\n", storeUrl(e)); return; } s = buf + k; assert(urlres_e->mem_obj->reply); httpReplyParse(urlres_e->mem_obj->reply, buf, k); debug(52, 3) ("mem->reply exists, code=%d.\n", urlres_e->mem_obj->reply->sline.status); if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) { debug(52, 3) ("urnHandleReply: failed.\n"); err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND); err->request = requestLink(urnState->request); err->url = xstrdup(storeUrl(e)); errorAppendEntry(e, err); return; } while (xisspace(*s)) s++; urls = urnParseReply(s, urnState->request->method); for (i = 0; NULL != urls[i].url; i++) urlcnt++; debug(53, 3) ("urnFindMinRtt: Counted %d URLs\n", i); if (urls == NULL) { /* unkown URN error */ debug(52, 3) ("urnTranslateDone: unknown URN %s\n", storeUrl(e)); err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND); err->request = requestLink(urnState->request); err->url = xstrdup(storeUrl(e)); errorAppendEntry(e, err); return; } min_u = urnFindMinRtt(urls, urnState->request->method, NULL); qsort(urls, urlcnt, sizeof(*urls), url_entry_sort); storeBuffer(e); memBufDefInit(&mb); memBufPrintf(&mb, "<TITLE>Select URL for %s</TITLE>\n" "<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n" "<H2>Select URL for %s</H2>\n" "<TABLE BORDER=\"0\" WIDTH=\"100%%\">\n", storeUrl(e), storeUrl(e)); for (i = 0; i < urlcnt; i++) { u = &urls[i]; debug(52, 3) ("URL {%s}\n", u->url); memBufPrintf(&mb, "<TR><TD><A HREF=\"%s\">%s</A></TD>", u->url, u->url); if (urls[i].rtt > 0) memBufPrintf(&mb, "<TD align=\"right\">%4d <it>ms</it></TD>", u->rtt); else memBufPrintf(&mb, "<TD align=\"right\">Unknown</TD>"); memBufPrintf(&mb, "<TD>%s</TD></TR>\n", u->flags.cached ? " [cached]" : " "); } memBufPrintf(&mb, "</TABLE>" "<HR noshade size=\"1px\">\n" "<ADDRESS>\n" "Generated by %s@%s\n" "</ADDRESS>\n", full_appname_string, getMyHostname()); rep = e->mem_obj->reply; httpReplyReset(rep); httpBuildVersion(&version, 1, 0); httpReplySetHeaders(rep, version, HTTP_MOVED_TEMPORARILY, NULL, "text/html", mb.size, 0, squid_curtime); if (urnState->flags.force_menu) { debug(51, 3) ("urnHandleReply: forcing menu\n"); } else if (min_u) { httpHeaderPutStr(&rep->header, HDR_LOCATION, min_u->url); } httpBodySet(&rep->body, &mb); httpReplySwapOut(rep, e); storeComplete(e); memFree(buf, MEM_4K_BUF); for (i = 0; i < urlcnt; i++) { safe_free(urls[i].url); safe_free(urls[i].host); } safe_free(urls); /* mb was absorbed in httpBodySet call, so we must not clean it */ storeUnregister(urnState->sc, urlres_e, urnState); storeUnlockObject(urlres_e); storeUnlockObject(urnState->entry); requestUnlink(urnState->request); requestUnlink(urnState->urlres_r); cbdataFree(urnState); }