Example #1
0
/* set body by absorbing mb */
void
httpBodySet(HttpBody * body, MemBuf * mb)
{
    assert(body);
    assert(memBufIsNull(&body->mb));
    body->mb = *mb;		/* absorb */
}
Example #2
0
void
httpBodyClean(HttpBody * body)
{
    assert(body);
    if (!memBufIsNull(&body->mb))
	memBufClean(&body->mb);
}
Example #3
0
/* 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;
    }
}
Example #4
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;
}
Example #5
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;
}
Example #6
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);
}
Example #7
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);
}