squid-1677

Version:

2.6

Bug link:

http://bugs.squid-cache.org/show_bug.cgi?id=1677

Patch link:

http://bugs.squid-cache.org/attachment.cgi?id=1111&action=diff

Symptom:

When the request to Squid contains duplicate "If-None-Match:" headers, squid will blindly duplicate two, which when passed to lighthttpd, will return a 400 error. Although it’s triggered by lighthttpd’s bug, squid should also merge the header if necessary.

Root cause:

Squid forgot to handle the “If-None-Match” case, resulting a swith statement fall-through.

httpBuildRequestHeader(...)

{
    const HttpHeaderEntry *e;
    String strFwd;
    HttpHeaderPos pos = HttpHeaderInitPos;
+    String etags = StringNull;
+    
    httpHeaderInit(hdr_out, hoRequest);
    /* append our IMS header */
    if (request->lastmod > -1)
        httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, request->lastmod);
-    if (request->etag)

<--here if-none-match is added to the request header once
-        httpHeaderPutStr(hdr_out, HDR_IF_NONE_MATCH, request->etag);        
+    if (request->etag) {
+        etags = httpHeaderGetList(hdr_in, HDR_IF_NONE_MATCH);
+        strListAdd(&etags, request->etag, ',');
+    }
    else if (request->etags)
        …

   ...
   while ((e = httpHeaderGetEntry(hdr_in, &pos))) {

        debug(11, 5) ("httpBuildRequestHeader: %s: %s\n",

            strBuf(e->name), strBuf(e->value));

        if (!httpRequestHdrAllowed(e, &strConnection)) {

            debug(11, 2) ("'%s' header is a hop-by-hop connections header\n",

                strBuf(e->name));

            continue;

        }

        switch (e->id) {

        …

        case HDR_IF_MODIFIED_SINCE:
            if (!httpHeaderHas(hdr_out, HDR_IF_MODIFIED_SINCE))
                httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
            break;
+        case HDR_IF_NONE_MATCH:
+            /* append unless we added our own;
+             * note: at most one client's ims header can pass through */
+            if (
!httpHeaderHas(hdr_out, HDR_IF_NONE_MATCH))
+                httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
+            break;
        …

        case HDR_REQUEST_RANGE:

            if (!we_do_ranges)

                httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));

            break;

        ...

        default:

            <--here the switch falls through, and if-none-match is added to the request header twice!

            /* pass on all other header fields */

            httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));

}

Is there Error Message?

No

Can developer/Errlog anticipate the error msg?

Yes. It belongs to the pattern: default switch!