Beispiel #1
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;
}
Beispiel #2
0
void
storeLog(int tag, const StoreEntry * e)
{
    MemBuf mb;
    MemObject *mem = e->mem_obj;
    HttpReply *reply;
    if (storelog_fd < 0)
        return;
    if (mem == NULL)
        return;
    if (EBIT_TEST(e->flags, ENTRY_DONT_LOG))
        return;
    if (mem->log_url == NULL) {
        debug(20, 1) ("storeLog: NULL log_url for %s\n", mem->url);
        storeMemObjectDump(mem);
        mem->log_url = xstrdup(mem->url);
    }
    memBufDefInit(&mb);
    reply = mem->reply;
    memBufPrintf(&mb, "%9d.%03d %-7s %08X %4d %9d %9d %9d %s %d/%d %s %s\n",
                 (int) current_time.tv_sec,
                 (int) current_time.tv_usec / 1000,
                 storeLogTags[tag],
                 e->swap_file_number,
                 reply->sline.status,
                 (int) reply->date,
                 (int) reply->last_modified,
                 (int) reply->expires,
                 strLen(reply->content_type) ? strBuf(reply->content_type) : "unknown",
                 reply->content_length,
                 (int) (mem->inmem_hi - mem->reply->hdr_sz),
                 RequestMethodStr[mem->method],
                 mem->log_url);
    file_write_mbuf(storelog_fd, -1, mb, NULL, NULL);
}
Beispiel #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);
}
Beispiel #4
0
static void
identConnectDone(int fd, int status, void *data)
{
	IdentStateData *state = data;
	IdentClient *c;
	MemBuf mb;
	if (status != COMM_OK)
	{
		/* Failed to connect */
		comm_close(fd);
		return;
	}
	/*
	 * see if our clients still care
	 */
	for (c = state->clients; c; c = c->next)
	{
		if (cbdataValid(c->callback_data))
			break;
	}
	if (c == NULL)
	{
		/* no clients care */
		comm_close(fd);
		return;
	}
	memBufDefInit(&mb);
	memBufPrintf(&mb, "%d, %d\r\n",
				 ntohs(state->my_peer.sin_port),
				 ntohs(state->me.sin_port));
	comm_write_mbuf(fd, mb, NULL, state);
	commSetSelect(fd, COMM_SELECT_READ, identReadReply, state, 0);
	commSetTimeout(fd, Config.Timeout.ident, identTimeout, state);
}
Beispiel #5
0
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);
}
Beispiel #7
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);
}
Beispiel #8
0
/* create memBuf, create mem-based packer,  pack, destroy packer, return MemBuf */
MemBuf
httpReplyPack(const HttpReply * rep)
{
    MemBuf mb;
    Packer p;
    assert(rep);

    memBufDefInit(&mb);
    packerToMemInit(&p, &mb);
    httpReplyPackInto(rep, &p);
    packerClean(&p);
    return mb;
}
/*
 * parses a given string then packs compiled headers and compares the result
 * with the original, reports discrepancies
 */
void
httpHeaderTestParser(const char *hstr)
{
    static int bug_count = 0;
    int hstr_len;
    int parse_success;
    HttpHeader hdr;
    int pos;
    Packer p;
    MemBuf mb;
    assert(hstr);
    /* skip start line if any */
    if (!strncasecmp(hstr, "HTTP/", 5)) {
	const char *p = strchr(hstr, '\n');
	if (p)
	    hstr = p + 1;
    }
    /* skip invalid first line if any */
    if (xisspace(*hstr)) {
	const char *p = strchr(hstr, '\n');
	if (p)
	    hstr = p + 1;
    }
    hstr_len = strlen(hstr);
    /* skip terminator if any */
    if (strstr(hstr, "\n\r\n"))
	hstr_len -= 2;
    else if (strstr(hstr, "\n\n"))
	hstr_len -= 1;
    httpHeaderInit(&hdr, hoReply);
    /* debugLevels[55] = 8; */
    parse_success = httpHeaderParse(&hdr, hstr, hstr + hstr_len);
    /* debugLevels[55] = 2; */
    if (!parse_success) {
	debug(66, 2) ("TEST (%d): failed to parsed a header: {\n%s}\n", bug_count, hstr);
	return;
    }
    /* we think that we parsed it, veryfy */
    memBufDefInit(&mb);
    packerToMemInit(&p, &mb);
    httpHeaderPackInto(&hdr, &p);
    if ((pos = abs(httpHeaderStrCmp(hstr, mb.buf, hstr_len)))) {
	bug_count++;
	debug(66, 2) ("TEST (%d): hdr parsing bug (pos: %d near '%s'): expected: {\n%s} got: {\n%s}\n",
	    bug_count, pos, hstr + pos, hstr, mb.buf);
    }
    httpHeaderClean(&hdr);
    packerClean(&p);
    memBufClean(&mb);
}
Beispiel #10
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;
    }
}
wordlist *
aclDumpExternal(void *data)
{
    external_acl_data *acl = data;
    wordlist *result = NULL;
    wordlist *arg;
    MemBuf mb;
    memBufDefInit(&mb);
    memBufPrintf(&mb, "%s", acl->def->name);
    for (arg = acl->arguments; arg; arg = arg->next) {
	memBufPrintf(&mb, " %s", arg->key);
    }
    wordlistAdd(&result, mb.buf);
    memBufClean(&mb);
    return result;
}
void
httpHeaderPutRange(HttpHeader * hdr, const HttpHdrRange * range)
{
    MemBuf mb;
    Packer p;
    assert(hdr && range);
    /* remove old directives if any */
    httpHeaderDelById(hdr, HDR_RANGE);
    /* pack into mb */
    memBufDefInit(&mb);
    packerToMemInit(&p, &mb);
    httpHdrRangePackInto(range, &p);
    /* put */
    httpHeaderAddEntry(hdr, httpHeaderEntryCreate(HDR_RANGE, NULL, mb.buf));
    /* cleanup */
    packerClean(&p);
    memBufClean(&mb);
}
void
httpHeaderPutCc(HttpHeader * hdr, const HttpHdrCc * cc)
{
    MemBuf mb;
    Packer p;
    assert(hdr && cc);
    /* remove old directives if any */
    httpHeaderDelById(hdr, HDR_CACHE_CONTROL);
    /* pack into mb */
    memBufDefInit(&mb);
    packerToMemInit(&p, &mb);
    httpHdrCcPackInto(cc, &p);
    /* put */
    httpHeaderAddEntry(hdr, httpHeaderEntryCreate(HDR_CACHE_CONTROL, NULL, mb.buf));
    /* cleanup */
    packerClean(&p);
    memBufClean(&mb);
}
Beispiel #14
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;
}
Beispiel #15
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;
}
Beispiel #16
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;
}
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);
}
Beispiel #18
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);
}
Beispiel #19
0
IcapStateData *
icapRespModStart(icap_service_t type, request_t * request, StoreEntry * entry,
    http_state_flags http_flags)
{
    IcapStateData *icap = NULL;
    CNCB *theCallback = NULL;
    icap_service *service = NULL;

    debug(81, 3) ("icapRespModStart: type=%d\n", (int) type);
    assert(type >= 0 && type < ICAP_SERVICE_MAX);

    service = icapService(type, request);
    if (!service) {
	debug(81, 3) ("icapRespModStart: no service found\n");
	return NULL;		/* no service found */
    }
    if (service->unreachable) {
	if (service->bypass) {
	    debug(81,
		5)
		("icapRespModStart: BYPASS because service unreachable: %s\n",
		service->uri);
	    return NULL;
	} else {
	    debug(81,
		5)
		("icapRespModStart: ERROR  because service unreachable: %s\n",
		service->uri);
	    return (IcapStateData *) - 1;
	}
    }
    switch (type) {
	/* TODO: When we support more than ICAP_SERVICE_RESPMOD_PRECACHE, we needs to change
	 * this switch, because callbacks isn't keep */
    case ICAP_SERVICE_RESPMOD_PRECACHE:
	theCallback = icapConnectOver;
	break;
    default:
	fatalf("icapRespModStart: unsupported service type '%s'\n",
	    icap_service_type_str[type]);
	break;
    }

    icap = icapAllocate();
    if (!icap) {
	debug(81, 3) ("icapRespModStart: icapAllocate() failed\n");
	return NULL;
    }
    icap->request = requestLink(request);
    icap->respmod.entry = entry;
    if (entry)
	storeLockObject(entry);
    icap->http_flags = http_flags;
    memBufDefInit(&icap->respmod.buffer);
    memBufDefInit(&icap->chunk_buf);

    icap->current_service = service;
    icap->preview_size = service->preview;

    /* 
     * Don't create socket to the icap server now, but only for the first
     * packet receive from the http server. This will resolve all timeout
     * between the web server and icap server.
     */
    debug(81, 3) ("icapRespModStart: setting connect_requested to 0\n");
    icap->flags.connect_requested = 0;

    /*
     * make a copy the HTTP response that we send to the ICAP server in
     * case it turns out to be a 204
     */
#ifdef SUPPORT_ICAP_204
    icap->flags.copy_response = 1;
#elif ICAP_PREVIEW
    if(preview_size < 0 || !Config.icapcfg.preview_enable)
	 icap->flags.copy_response = 0;
    else
	 icap->flags.copy_response = 1;
#else
    icap->flags.copy_response = 0;
#endif
    
    statCounter.icap.all.requests++;
    debug(81, 3) ("icapRespModStart: returning %p\n", icap);
    return icap;
}
Beispiel #20
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;
}
Beispiel #21
0
/*
 * 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);
}
Beispiel #22
0
static void
urnHandleReply(void *data, char *buf, ssize_t size)
{
    UrnState *urnState = data;
    StoreEntry *e = urnState->entry;
    StoreEntry *urlres_e = urnState->urlres_e;
    char *s = NULL;
    size_t k;
    HttpReply *rep;
    url_entry *urls;
    url_entry *u;
    url_entry *min_u;
    MemBuf mb;
    ErrorState *err;
    int i;
    int urlcnt = 0;
    http_version_t version;

    debug(52, 3) ("urnHandleReply: Called with size=%d.\n", (int) size);
    if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED)) {
	memFree(buf, MEM_4K_BUF);
	return;
    }
    if (size == 0) {
	memFree(buf, MEM_4K_BUF);
	return;
    } else if (size < 0) {
	memFree(buf, MEM_4K_BUF);
	return;
    }
    if (urlres_e->store_status == STORE_PENDING && size < SM_PAGE_SIZE) {
	storeClientCopy(urnState->sc, urlres_e,
	    size,
	    0,
	    SM_PAGE_SIZE,
	    buf,
	    urnHandleReply,
	    urnState);
	return;
    }
    /* we know its STORE_OK */
    k = headersEnd(buf, size);
    if (0 == k) {
	debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %s\n",
	    storeUrl(e));
	return;
    }
    s = buf + k;
    assert(urlres_e->mem_obj->reply);
    httpReplyParse(urlres_e->mem_obj->reply, buf, k);
    debug(52, 3) ("mem->reply exists, code=%d.\n",
	urlres_e->mem_obj->reply->sline.status);
    if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) {
	debug(52, 3) ("urnHandleReply: failed.\n");
	err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
	err->request = requestLink(urnState->request);
	err->url = xstrdup(storeUrl(e));
	errorAppendEntry(e, err);
	return;
    }
    while (xisspace(*s))
	s++;
    urls = urnParseReply(s, urnState->request->method);
    for (i = 0; NULL != urls[i].url; i++)
	urlcnt++;
    debug(53, 3) ("urnFindMinRtt: Counted %d URLs\n", i);
    if (urls == NULL) {		/* unkown URN error */
	debug(52, 3) ("urnTranslateDone: unknown URN %s\n", storeUrl(e));
	err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
	err->request = requestLink(urnState->request);
	err->url = xstrdup(storeUrl(e));
	errorAppendEntry(e, err);
	return;
    }
    min_u = urnFindMinRtt(urls, urnState->request->method, NULL);
    qsort(urls, urlcnt, sizeof(*urls), url_entry_sort);
    storeBuffer(e);
    memBufDefInit(&mb);
    memBufPrintf(&mb,
	"<TITLE>Select URL for %s</TITLE>\n"
	"<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n"
	"<H2>Select URL for %s</H2>\n"
	"<TABLE BORDER=\"0\" WIDTH=\"100%%\">\n", storeUrl(e), storeUrl(e));
    for (i = 0; i < urlcnt; i++) {
	u = &urls[i];
	debug(52, 3) ("URL {%s}\n", u->url);
	memBufPrintf(&mb,
	    "<TR><TD><A HREF=\"%s\">%s</A></TD>", u->url, u->url);
	if (urls[i].rtt > 0)
	    memBufPrintf(&mb,
		"<TD align=\"right\">%4d <it>ms</it></TD>", u->rtt);
	else
	    memBufPrintf(&mb, "<TD align=\"right\">Unknown</TD>");
	memBufPrintf(&mb,
	    "<TD>%s</TD></TR>\n", u->flags.cached ? "    [cached]" : " ");
    }
    memBufPrintf(&mb,
	"</TABLE>"
	"<HR noshade size=\"1px\">\n"
	"<ADDRESS>\n"
	"Generated by %s@%s\n"
	"</ADDRESS>\n",
	full_appname_string, getMyHostname());
    rep = e->mem_obj->reply;
    httpReplyReset(rep);
    httpBuildVersion(&version, 1, 0);
    httpReplySetHeaders(rep, version, HTTP_MOVED_TEMPORARILY, NULL,
	"text/html", mb.size, 0, squid_curtime);
    if (urnState->flags.force_menu) {
	debug(51, 3) ("urnHandleReply: forcing menu\n");
    } else if (min_u) {
	httpHeaderPutStr(&rep->header, HDR_LOCATION, min_u->url);
    }
    httpBodySet(&rep->body, &mb);
    httpReplySwapOut(rep, e);
    storeComplete(e);
    memFree(buf, MEM_4K_BUF);
    for (i = 0; i < urlcnt; i++) {
	safe_free(urls[i].url);
	safe_free(urls[i].host);
    }
    safe_free(urls);
    /* mb was absorbed in httpBodySet call, so we must not clean it */
    storeUnregister(urnState->sc, urlres_e, urnState);
    storeUnlockObject(urlres_e);
    storeUnlockObject(urnState->entry);
    requestUnlink(urnState->request);
    requestUnlink(urnState->urlres_r);
    cbdataFree(urnState);
}