static char * makeRefreshCheckRequest(StoreEntry * entry, refresh_check_format * format) { static MemBuf mb = MemBufNULL; int first = 1; HttpReply *reply; String sb = StringNull; if (!entry->mem_obj) return NULL; reply = entry->mem_obj->reply; memBufReset(&mb); for (; format; format = format->next) { char buf[256]; const char *str = NULL; const char *quoted; switch (format->type) { case REFRESH_CHECK_URI: str = entry->mem_obj->url; break; case REFRESH_CHECK_AGE: snprintf(buf, sizeof(buf), "%ld", (long int) (squid_curtime - entry->timestamp)); str = buf; break; case REFRESH_CHECK_RESP_HEADER: sb = httpHeaderGetByName(&reply->header, format->header); str = strBuf(sb); break; case REFRESH_CHECK_RESP_HEADER_ID: sb = httpHeaderGetStrOrList(&reply->header, format->header_id); str = strBuf(sb); break; case REFRESH_CHECK_RESP_HEADER_MEMBER: sb = httpHeaderGetByNameListMember(&reply->header, format->header, format->member, format->separator); str = strBuf(sb); break; case REFRESH_CHECK_RESP_HEADER_ID_MEMBER: sb = httpHeaderGetListMember(&reply->header, format->header_id, format->member, format->separator); str = strBuf(sb); break; case REFRESH_CHECK_UNKNOWN: case REFRESH_CHECK_END: fatal("unknown refresh_check_program format error"); break; } if (!str || !*str) str = "-"; if (!first) memBufAppend(&mb, " ", 1); quoted = rfc1738_escape(str); memBufAppend(&mb, quoted, strlen(quoted)); stringClean(&sb); first = 0; } return mb.buf; }
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; }
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 idnsSendTcpQuery(int fd, int status, void *data) { MemBuf buf; idns_query *q = data; short nsz; if (status != COMM_OK) { int ns = (q->nsends - 1) % nns; debug(78, 1) ("idnsSendTcpQuery: Failed to connect to DNS server %d using TCP\n", ns + 1); idnsTcpCleanup(q); return; } memBufInit(&buf, q->sz + 2, q->sz + 2); nsz = htons(q->sz); memBufAppend(&buf, &nsz, 2); memBufAppend(&buf, q->buf, q->sz); comm_write_mbuf(q->tcp_socket, buf, idnsSendTcpQueryDone, q); }
/* * 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 int clientHandleErrorPage(clientHttpRequest *http) { debug(115, 4)("mod_customized_server_side_error_page clientHandleErrorPage\n"); request_t *request = http->request; int fd = http->conn->fd; if(fd_table[fd].cc_run_state[mod->slot] > 0) { error_page_private_data* pd=NULL; pd = error_page_private_data_pool_alloc(); mod_config* cfg = (mod_config*)cc_get_mod_param(fd,mod); pd->OfflineTimeToLive= cfg->OfflineTimeToLive; pd->TimeToTrigger = squid_curtime + cfg->TriggerTimeSec; pd->ResponseStatus = cfg->ResponseStatus; pd->recusive_time = 0; pd->old_status = 0; strncpy(pd->OptionalHttpStatusPattern,cfg->OptionalHttpStatusPattern, strlen(cfg->OptionalHttpStatusPattern)); cc_register_mod_private_data(REQUEST_PRIVATE_DATA,http, pd, free_error_page_private_data ,mod); //int *timeout = timeout_pool_alloc(); //*timeout = cfg->TriggerTimeSec; //debug(115,4)("clientHandleErrorPage: the timeout before register mod private data is: %d \n ",*timeout); //cc_register_mod_private_data(FDE_PRIVATE_DATA,&fd, timeout,free_timeout,mod); // add by xueye.zhao // 2013-4-18 if (!is_http_move_status(cfg->ResponseStatus)) { MemBuf * text = text_mb_pool_alloc(); memBufInit(text, cfg->customized_error_text.size+1, cfg->customized_error_text.size+1); memBufAppend(text, cfg->customized_error_text.buf, cfg->customized_error_text.size); debug(115,4)("mod_customized_server_side_error_page clientHanleErrorPage :before cc_register_mod_private_data and the request is: %p\n",request); cc_register_mod_private_data(REQUEST_T_PRIVATE_DATA,request,text,free_data,mod); } //end add } return 0; }
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; }
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 }
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; }
static char * makeExternalAclKey(aclCheck_t * ch, external_acl_data * acl_data) { static MemBuf mb = MemBufNULL; char buf[256]; int first = 1; wordlist *arg; external_acl_format *format; request_t *request = ch->request; String sb = StringNull; memBufReset(&mb); for (format = acl_data->def->format; format; format = format->next) { const char *str = NULL; switch (format->type) { case EXT_ACL_LOGIN: str = authenticateUserRequestUsername(request->auth_user_request); break; #if USE_IDENT case EXT_ACL_IDENT: str = ch->rfc931; if (!str || !*str) { ch->state[ACL_IDENT] = ACL_LOOKUP_NEEDED; return NULL; } break; #endif case EXT_ACL_SRC: str = inet_ntoa(ch->src_addr); break; case EXT_ACL_DST: str = request->host; break; case EXT_ACL_PROTO: str = ProtocolStr[request->protocol]; break; case EXT_ACL_PORT: snprintf(buf, sizeof(buf), "%d", request->port); str = buf; break; case EXT_ACL_METHOD: str = RequestMethodStr[request->method]; break; case EXT_ACL_HEADER: sb = httpHeaderGetByName(&request->header, format->header); str = strBuf(sb); break; case EXT_ACL_HEADER_ID: sb = httpHeaderGetStrOrList(&request->header, format->header_id); str = strBuf(sb); break; case EXT_ACL_HEADER_MEMBER: sb = httpHeaderGetByNameListMember(&request->header, format->header, format->member, format->separator); str = strBuf(sb); break; case EXT_ACL_HEADER_ID_MEMBER: sb = httpHeaderGetListMember(&request->header, format->header_id, format->member, format->separator); str = strBuf(sb); break; } if (str) if (!*str) str = NULL; if (!str) str = "-"; if (!first) memBufAppend(&mb, " ", 1); strwordquote(&mb, str); stringClean(&sb); first = 0; } for (arg = acl_data->arguments; arg; arg = arg->next) { if (!first) memBufAppend(&mb, " ", 1); strwordquote(&mb, arg->key); first = 0; } return mb.buf; }
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; }
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); }
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); }