re-send the mail about "HTTP/1.1 100 Continue"

From: ShuXin Zheng <zhengshuxin@dont-contact.us>
Date: Thu, 26 Oct 2006 09:40:12 +0800

I'm so sorry about last mail "HTTP/1.1 100 Continue". The mail seems
to unreadable because my
yahoo mail changed the format of mail content and the mail system of
squid sites can't explain
the multipart mail format. So, I change to use the gmail to send the
email again. Is there any
unreadable format existing? Oh, mygod, the ugly yahoo mail system ....

zsx
2006.10.26

Hi, I've completed the codes for 'HTTP/1.1 100 Continue', and the
squid with these codes worked well,
I've test some cases for it. Can anybody else give me some suggest to
do it better?
Thanks
zsx
2006.10.25

The codes added or changed for squid are below:

1) struct.h
struct _HttpStateData {
    StoreEntry *entry;
    request_t *request;
    MemBuf reply_hdr;
+ MemBuf reply_hdr_buf; /* add by zsx for HTTP1.1---10.1.1 */
    ......

2) HttpReply.c
static int
httpReplyParseStep(HttpReply * rep, const char *buf, int atEnd)
{
    const char *parse_start = buf;
    const char *blk_start, *blk_end;
    const char **parse_end_ptr = &blk_end;
    assert(rep);
    assert(parse_start);
    assert(rep->pstate < psParsed);

    *parse_end_ptr = parse_start;
    if (rep->pstate == psReadyToParseStartLine) {
        if (!httpReplyIsolateStart(&parse_start, &blk_start, &blk_end))
            return 0;
        if (!httpStatusLineParse(&rep->sline, blk_start, blk_end))
            return httpReplyParseError(rep);

        *parse_end_ptr = parse_start;
        rep->hdr_sz = *parse_end_ptr - buf;
+ /* changed by zsx for http1.1--10.1.1 */
- rep->pstate++;
+ if (rep->sline.status != HTTP_CONTINUE)
+ rep->pstate++;

    ......

3) http.c
3.1) I changed the old function from "httpProcessReplyHeader()" to
"httpProcessReplyHeader()"
and "httpProcessReplyHeader2()", as below:

static void
httpProcessReplyHeader2(HttpStateData * httpState)
{
    StoreEntry *entry = httpState->entry;
    MemObject *mem = entry->mem_obj;
    HttpReply *reply = mem->reply;

    if (!peer_supports_connection_pinning(httpState))
    httpState->orig_request->flags.no_connection_auth = 1;
    storeTimestampsSet(entry);

    if (httpHeaderHas(&reply->header, HDR_VARY)
#if X_ACCELERATOR_VARY
    || httpHeaderHas(&reply->header, HDR_X_ACCELERATOR_VARY)
#endif
    ) {
    const char *vary = NULL;
    if (Config.onoff.cache_vary)
        vary = httpMakeVaryMark(httpState->orig_request, reply);
    if (!vary) {
        httpMakePrivate(entry);
        goto no_cache;
    }
    entry->mem_obj->vary_headers = xstrdup(vary);

    if (strBuf(httpState->orig_request->vary_encoding))
        entry->mem_obj->vary_encoding =
xstrdup(strBuf(httpState->orig_request->vary_encoding));
    }

    switch (httpCachableReply(httpState)) {
    case 1:
    httpMakePublic(entry);
    break;
    case 0:
    httpMakePrivate(entry);
    break;
    case -1:
    if (Config.negativeTtl > 0)
        httpCacheNegatively(entry);
    else
        httpMakePrivate(entry);
    break;
    default:
    assert(0);
    break;
    }
  no_cache:
    if (reply->cache_control) {
    if (EBIT_TEST(reply->cache_control->mask, CC_PROXY_REVALIDATE))
        EBIT_SET(entry->flags, ENTRY_REVALIDATE);
    else if (EBIT_TEST(reply->cache_control->mask, CC_MUST_REVALIDATE))
        EBIT_SET(entry->flags, ENTRY_REVALIDATE);
    }
    if (neighbors_do_private_keys && !Config.onoff.collapsed_forwarding)
    httpMaybeRemovePublic(entry, reply->sline.status);
    if (httpState->flags.keepalive)
    if (httpState->peer)
        httpState->peer->stats.n_keepalives_sent++;
    if (reply->keep_alive) {
    if (httpState->peer)
        httpState->peer->stats.n_keepalives_recv++;
    if (Config.onoff.detect_broken_server_pconns &&
httpReplyBodySize(httpState->request->method, reply) == -1) {
        debug(11, 1) ("httpProcessReplyHeader: Impossible keep-alive
header from '%s'\n", storeUrl(entry));
        debug(11, 2) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
        httpState->reply_hdr.buf);
        httpState->flags.keepalive_broken = 1;
    }
    }
    if (reply->date > -1 && !httpState->peer) {
    int skew = abs(reply->date - squid_curtime);
    if (skew > 86400)
        debug(11, 3) ("%s's clock is skewed by %d seconds!\n",
        httpState->request->host, skew);
    }
#if HEADERS_LOG
    headersLog(1, 0, httpState->request->method, reply);
#endif
}

static int
httpProcessReplyHeader(HttpStateData *httpState, const char *buf, int size)
{
    char myname[] = "httpProccessReplyHeader";
    StoreEntry *entry = httpState->entry;
    size_t hdr_len;
    size_t hdr_size;
    MemObject *mem = entry->mem_obj;
    HttpReply *reply = mem->reply;
    Ctx ctx = ctx_enter(mem->url);
    const char *ptr;
    int dlen;

#undef RETURN
#define RETURN(_x_) do { \
    ctx_exit(ctx); \
    return (_x_); \
} while (0)

    assert(httpState->reply_hdr_state == 0);

    debug(11, 3) ("%s: key '%s'\n",
    myname, storeKeyText(entry->hash.key));
    if (memBufIsNull(&httpState->reply_hdr))
    memBufDefInit(&httpState->reply_hdr);

    if (memBufIsNull(&httpState->reply_hdr_buf))
    memBufDefInit(&httpState->reply_hdr_buf);

    safe_free(entry->mem_obj->vary_headers);
    safe_free(entry->mem_obj->vary_encoding);

    /* loop parse the header data, just in order to ignore
     * the "HTTP/1.1 100 Continue" header, http1.1--10.1.1
     */
    ptr = buf;
    dlen = size;
    while (1) {
    memBufAppend(&httpState->reply_hdr, ptr, dlen);
    memBufAppend(&httpState->reply_hdr_buf, ptr, dlen);
    hdr_len = httpState->reply_hdr.size;
    if (hdr_len > 4 && strncmp(httpState->reply_hdr.buf, "HTTP/", 5)) {
        debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant
header: '%s'\n", httpState->reply_hdr.buf);
        httpState->reply_hdr_state += 2;
        memBufClean(&httpState->reply_hdr);
        httpBuildVersion(&reply->sline.version, 0, 9);
        reply->sline.status = HTTP_INVALID_HEADER;
        if (!memBufIsNull(&httpState->reply_hdr_buf))
        memBufClean(&httpState->reply_hdr_buf);
        RETURN (-1);
    }
    hdr_size = headersEnd(httpState->reply_hdr.buf, hdr_len);
    /* if "hdr_size == 0", the data in buf is not a complete http reply header,
     * else the http reply header is complete.
     */
    if (hdr_size)
        hdr_len = hdr_size;
    if (hdr_len > Config.maxReplyHeaderSize) {
        debug(11, 1) ("httpProcessReplyHeader: Too large reply header\n");
        if (!memBufIsNull(&httpState->reply_hdr))
        memBufClean(&httpState->reply_hdr);
        if (!memBufIsNull(&httpState->reply_hdr_buf))
        memBufClean(&httpState->reply_hdr_buf);
        reply->sline.status = HTTP_HEADER_TOO_LARGE;
        httpState->reply_hdr_state += 2;
        RETURN (-1);
    }
    /* headers can be incomplete only if object still arriving */
    if (!hdr_size) {
        if (httpState->eof)
        hdr_size = hdr_len;
        else
        RETURN (0); /* headers not complete */
    }

    /* Cut away any excess body data (only needed for debug?) */
    memBufAppend(&httpState->reply_hdr, "\0", 1);
    httpState->reply_hdr.buf[hdr_size] = '\0';
    httpState->reply_hdr_state++;
    assert(httpState->reply_hdr_state == 1);
    httpState->reply_hdr_state++;
    debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
        httpState->reply_hdr.buf);
    /* Parse headers into reply structure */
    /* what happens if we fail to parse here? */
    httpReplyParse(reply, httpState->reply_hdr.buf, hdr_size);

    if (reply->sline.status == HTTP_CONTINUE) {
        httpState->reply_hdr_state = 0;
        if (!memBufIsNull(&httpState->reply_hdr))
        memBufReset(&httpState->reply_hdr);
        if (!memBufIsNull(&httpState->reply_hdr_buf))
        memBufReset(&httpState->reply_hdr_buf);
    } else
        break;

    if (httpState->eof)
        break;

    ptr += hdr_size;
    dlen -= hdr_size;
    assert(dlen >= 0);
    } /* end while */

    /* the other http reply status */

    if (reply->sline.status >= HTTP_INVALID_HEADER) {
    debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header:
'%s'\n", httpState->reply_hdr.buf);
    memBufClean(&httpState->reply_hdr);
    if (!memBufIsNull(&httpState->reply_hdr_buf))
        memBufClean(&httpState->reply_hdr_buf);
    RETURN (-1);
    }

    /* Check if object is cacheable or not based on reply code */
    debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n",
reply->sline.status);

    httpProcessReplyHeader2(httpState);

    RETURN (0);
}

3.2) in httpReadReply() function
static void
httpReadReply(int fd, void *data)
{
    ......

    } else if (len == 0) {
    /* Connection closed; retrieval done. */
    httpState->eof = 1;
    if (httpState->reply_hdr_state < 2)
        /*
         * Yes Henrik, there is a point to doing this. When we
         * called httpProcessReplyHeader() before, we didn't find
         * the end of headers, but now we are definately at EOF, so
         * we want to process the reply headers.
         */
        /* hexun: changed by zsx for HTTP-ZIP, http1.1-10.1.1, 2006.10.24 */
        /* httpProcessReplyHeader(httpState, buf, len); */
        httpProcessReplyHeader(httpState, buf, len);
        /* end changed */
    if (entry->mem_obj->reply->sline.status == HTTP_HEADER_TOO_LARGE) {
        storeEntryReset(entry);
        fwdFail(httpState->fwd, errorCon(ERR_TOO_BIG, HTTP_BAD_GATEWAY));
        httpState->fwd->flags.dont_retry = 1;
    } else if (entry->mem_obj->reply->sline.status ==
HTTP_INVALID_HEADER && !(entry->mem_obj->reply->sline.version.major

== 0 && entry->mem_obj->reply->sline.version.minor == 9)) {
        storeEntryReset(entry);
        fwdFail(httpState->fwd, errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY));
        httpState->fwd->flags.dont_retry = 1;
    } else {
        fwdComplete(httpState->fwd);
    }
    comm_close(fd);
    return;
    } else {
+ int store_reply_hdr = 0;

    if (httpState->reply_hdr_state < 2) {
        httpProcessReplyHeader(httpState, buf, len);
    ......

+ if (store_reply_hdr == 1)
+ storeAppend(entry, httpState->reply_hdr_buf.buf,
httpState->reply_hdr_buf.size);
+ else if (httpState->reply_hdr_state == 2)
+ storeAppend(entry, buf, len);

    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
        /*
         * the above storeAppend() call could ABORT this entry,
         * in that case, the server FD should already be closed.
         * there's nothing for us to do.
         */
        return;
    }

+ if (httpState->reply_hdr_state < 2) {
+ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
+ return;
+ }

    switch (httpPconnTransferDone(httpState)) {
    ......
}

3.3) in httpStateFree()
static void
httpStateFree(int fd, void *data)
{
    ......

    if (!memBufIsNull(&httpState->reply_hdr)) {
    memBufClean(&httpState->reply_hdr);
    }
+ if (!memBufIsNull(&httpState->reply_hdr_buf)) {
+ memBufClean(&httpState->reply_hdr_buf);
+ }
    ......
}
Received on Thu Oct 26 2006 - 02:14:58 MDT

This archive was generated by hypermail pre-2.1.9 : Wed Nov 01 2006 - 12:00:06 MST