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); }
void httpBodyClean(HttpBody * body) { assert(body); if (!memBufIsNull(&body->mb)) memBufClean(&body->mb); }
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); }
static int free_request_param(void* data) { request_param *req_param = (request_param *) data; if(req_param != NULL){ close(req_param->m3u8_fd); memBufClean(&(req_param->prevBuf)); memPoolFree(request_param_pool, req_param); req_param = NULL; } return 0; }
static int free_mod_config(void *data) { mod_config* cfg = (mod_config*)data; if(cfg) { if(NULL != cfg->customized_error_text.buf) memBufClean(&cfg->customized_error_text); memPoolFree(mod_config_pool, cfg); cfg = NULL; } return 0; }
/* 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); }
/* * 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); }
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; }
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 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); }
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); }
static void errorTryLoadText(MemBuf * text, char *path) { int fd; struct stat sb; // char *text = NULL; //snprintf(path, sizeof(path), "%s/%s", dir, page_name); #ifdef _SQUID_MSWIN_ fd = open(path, O_RDONLY | O_BINARY); #else fd = open(path, O_RDONLY | O_TEXT); #endif if (fd < 0 || fstat(fd, &sb) < 0) { debug(115, 0) ("mod_customized_server_side_error_page errorTryLoadText: '%s': %s\n", path, xstrerror()); if (fd >= 0) file_close(fd); //return NULL; memBufInit(text, 1*sizeof(char), 1*sizeof(char)); memBufPrintf(text, "%s", ""); } else { memBufInit(text, (size_t)sb.st_size+2+1, (size_t)sb.st_size+2+1); if (read(fd, text->buf, (int) sb.st_size) != sb.st_size) { debug(115,0) ("mod_customized_server_side_error_page errorTryLoadText: failed to fully read: '%s': %s\n", path, xstrerror()); memBufClean(text); } text->size += sb.st_size; text->buf[text->size] = '\0'; debug(115,4)("mod_customized_server_side_error_page errorTryLoadText: the path is: %s point before end and text is: %s.....\n", path,text->buf); close(fd); } #ifndef CC_FRAMEWORK if (NULL != text->buf && strstr(text->buf, "%s") == NULL) memBufAppend(text,"%S", strlen("%S")); /* add signature */ #endif }
/* * 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 const char * errorConvert(char token, ErrorState * err) { request_t *r = err->request; static MemBuf mb = MemBufNULL; const char *p = NULL; /* takes priority over mb if set */ int do_quote = 1; memBufReset(&mb); switch (token) { case 'a': if (r && r->auth_user_request) p = authenticateUserRequestUsername(r->auth_user_request); if (!p) p = "-"; break; case 'B': p = r ? ftpUrlWith2f(r) : "[no URL]"; break; case 'c': p = errorPageName(err->type); break; case 'e': memBufPrintf(&mb, "%d", err->xerrno); break; case 'E': if (err->xerrno) memBufPrintf(&mb, "(%d) %s", err->xerrno, strerror(err->xerrno)); else memBufPrintf(&mb, "[No Error]"); break; case 'f': /* FTP REQUEST LINE */ if (err->ftp.request) p = err->ftp.request; else p = "nothing"; break; case 'F': /* FTP REPLY LINE */ if (err->ftp.request) p = err->ftp.reply; else p = "nothing"; break; case 'g': /* FTP SERVER MESSAGE */ wordlistCat(err->ftp.server_msg, &mb); break; case 'h': memBufPrintf(&mb, "%s", getMyHostname()); break; case 'H': if (r) { if (r->hier.host) p = r->hier.host; else p = r->host; } else p = "[unknown host]"; break; case 'i': memBufPrintf(&mb, "%s", inet_ntoa(err->src_addr)); break; case 'I': if (r && r->hier.host) { memBufPrintf(&mb, "%s", r->hier.host); } else p = "[unknown]"; break; case 'L': if (Config.errHtmlText) { memBufPrintf(&mb, "%s", Config.errHtmlText); do_quote = 0; } else p = "[not available]"; break; case 'm': p = authenticateAuthUserRequestMessage(err->auth_user_request) ? authenticateAuthUserRequestMessage(err->auth_user_request) : "[not available]"; break; case 'M': p = r ? RequestMethods[r->method].str : "[unknown method]"; break; case 'o': p = external_acl_message; if (!p) p = "[not available]"; break; case 'p': if (r) { memBufPrintf(&mb, "%d", (int) r->port); } else { p = "[unknown port]"; } break; case 'P': p = r ? ProtocolStr[r->protocol] : "[unkown protocol]"; break; case 'R': if (NULL != r) { Packer p; memBufPrintf(&mb, "%s %s HTTP/%d.%d\n", RequestMethods[r->method].str, strLen(r->urlpath) ? strBuf(r->urlpath) : "/", r->http_ver.major, r->http_ver.minor); packerToMemInit(&p, &mb); httpHeaderPackInto(&r->header, &p); packerClean(&p); } else if (err->request_hdrs) { p = err->request_hdrs; } else { p = "[no request]"; } break; case 's': p = visible_appname_string; break; case 'S': /* signature may contain %-escapes, recursion */ if (err->page_id != ERR_SQUID_SIGNATURE) { const int saved_id = err->page_id; MemBuf sign_mb; err->page_id = ERR_SQUID_SIGNATURE; sign_mb = errorBuildContent(err); memBufPrintf(&mb, "%s", sign_mb.buf); memBufClean(&sign_mb); err->page_id = saved_id; do_quote = 0; } else { /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */ p = "[%S]"; } break; case 't': memBufPrintf(&mb, "%s", mkhttpdlogtime(&squid_curtime)); break; case 'T': memBufPrintf(&mb, "%s", mkrfc1123(squid_curtime)); break; case 'U': p = r ? urlCanonicalClean(r) : err->url ? err->url : "[no URL]"; break; case 'u': p = r ? urlCanonical(r) : err->url ? err->url : "[no URL]"; break; case 'w': if (Config.adminEmail) memBufPrintf(&mb, "%s", Config.adminEmail); else p = "[unknown]"; break; case 'z': if (err->dnsserver_msg) p = err->dnsserver_msg; else p = "[unknown]"; break; case '%': p = "%"; break; default: memBufPrintf(&mb, "%%%c", token); do_quote = 0; break; } if (!p) p = mb.buf; /* do not use mb after this assignment! */ assert(p); debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p); if (do_quote) p = html_quote(p); return p; }
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); }
static void icapRespModReadReply(int fd, void *data) { IcapStateData *icap = data; int version_major, version_minor; const char *str_status; int x; int status = 0; int isIcap = 0; int directResponse = 0; ErrorState *err; const char *start; const char *end; debug(81, 5) ("icapRespModReadReply: FD %d data = %p\n", fd, data); statCounter.syscalls.sock.reads++; x = icapReadHeader(fd, icap, &isIcap); if (x < 0) { /* Did not find a proper ICAP response */ debug(81, 3) ("ICAP : Error path!\n"); err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); err->request = requestLink(icap->request); err->xerrno = errno; errorAppendEntry(icap->respmod.entry, err); comm_close(fd); return; } if (x == 0) { /* * Waiting for more headers. Schedule new read hander, but * don't reset timeout. */ commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0); return; } /* * Parse the ICAP header */ assert(icap->icap_hdr.size); debug(81, 3) ("Parse icap header : <%s>\n", icap->icap_hdr.buf); if ((status = icapParseStatusLine(icap->icap_hdr.buf, icap->icap_hdr.size, &version_major, &version_minor, &str_status)) < 0) { debug(81, 1) ("BAD ICAP status line <%s>\n", icap->icap_hdr.buf); /* is this correct in case of ICAP protocol error? */ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); err->request = requestLink(icap->request); err->xerrno = errno; errorAppendEntry(icap->respmod.entry, err); comm_close(fd); return; }; /* OK here we have responce. Lets stop filling the * icap->respmod.resp_copy buffer .... */ icap->flags.copy_response = 0; icapSetKeepAlive(icap, icap->icap_hdr.buf); #if ICAP_PREVIEW if (icap->flags.wait_for_preview_reply) { if (100 == status) { debug(81, 5) ("icapRespModReadReply: 100 Continue received\n"); icap->flags.wait_for_preview_reply = 0; /* if http_server_eof * call again icapSendRespMod to handle data that * was received while waiting for this ICAP response * else let http to call icapSendRespMod when new data arrived */ if (icap->flags.http_server_eof) icapSendRespMod(icap, NULL, 0, 0); /* * reset the header to send the rest of the preview */ if (!memBufIsNull(&icap->icap_hdr)) memBufReset(&icap->icap_hdr); /*We do n't need it any more .......*/ if (!memBufIsNull(&icap->respmod.resp_copy)) memBufClean(&icap->respmod.resp_copy); return; } if (204 == status) { debug(81, 5) ("icapRespModReadReply: 204 No modification received\n"); icap->flags.wait_for_preview_reply = 0; } } #endif /*ICAP_PREVIEW */ #if SUPPORT_ICAP_204 || ICAP_PREVIEW if (204 == status) { debug(81, 3) ("got 204 status from ICAP server\n"); debug(81, 3) ("setting icap->flags.no_content\n"); icap->flags.no_content = 1; /* * copy the response already written to the ICAP server */ debug(81, 3) ("copying %d bytes from resp_copy to chunk_buf\n", icap->respmod.resp_copy.size); memBufAppend(&icap->chunk_buf, icap->respmod.resp_copy.buf, icap->respmod.resp_copy.size); icap->respmod.resp_copy.size = 0; if (icapReadReply2(icap) < 0) comm_close(fd); /* * XXX ideally want to clean icap->respmod.resp_copy here * XXX ideally want to "close" ICAP server connection here * OK do it.... */ if (!memBufIsNull(&icap->respmod.resp_copy)) memBufClean(&icap->respmod.resp_copy); return; } #endif if (200 != status) { debug(81, 1) ("Unsupported status '%d' from ICAP server\n", status); /* Did not find a proper ICAP response */ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); err->request = requestLink(icap->request); err->xerrno = errno; errorAppendEntry(icap->respmod.entry, err); comm_close(fd); return; } if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) { icapParseEncapsulated(icap, start, end); } else { debug(81, 1) ("WARNING: icapRespModReadReply() did not find 'Encapsulated' header\n"); } if (icap->enc.res_hdr > -1) directResponse = 1; else if (icap->enc.res_body > -1) directResponse = 1; else directResponse = 0; /* * "directResponse" is the normal case here. If we don't have * a response header or body, it is an error. */ if (!directResponse) { /* Did not find a proper ICAP response */ debug(81, 3) ("ICAP : Error path!\n"); err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); err->request = requestLink(icap->request); err->xerrno = errno; errorAppendEntry(icap->respmod.entry, err); comm_close(fd); return; } /* got the reply, no need to come here again */ icap->flags.wait_for_reply = 0; icap->flags.got_reply = 1; /* Next, gobble any data before the HTTP response starts */ if (icap->enc.res_hdr > -1) icap->bytes_to_gobble = icap->enc.res_hdr; commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0); }
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); }