Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
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);
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
/*
 * 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; 

}
Esempio n. 7
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 
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
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;
}
Esempio n. 11
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;
}
Esempio n. 12
0
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);
}
Esempio n. 13
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);
}