Since we have no central place where the headers are upgraded I've had
to skip porting the upgrade_http0.9 hack in Squid-2 and go straight to
accepting ICY protocol as an accepted response protocol and handling it.
Somewhat primitive for now. It's limited to parsing and regenerating the
status line correctly, and skipping the HTTP/1.0 version override on
non-HTTP protocol replies.
Since it is on port 80 I've temporarily left the HTTP/1.1 required
header alterations happening. Some testing will be needed over the next
few days to ensure that the client software treats unknown headers
nicely. If needed overrides for those are easily done as well now.
Amos
=== modified file 'src/HttpReply.cc'
--- src/HttpReply.cc 2009-08-22 10:43:54 +0000
+++ src/HttpReply.cc 2009-11-01 10:17:45 +0000
@@ -458,24 +458,33 @@
return false;
}
+ int pos;
// catch missing or mismatched protocol identifier
- if (protoPrefix.cmp(buf->content(), protoPrefix.size()) != 0) {
- debugs(58, 3, "HttpReply::sanityCheckStartLine: missing protocol prefix (" << protoPrefix << ") in '" << buf->content() << "'");
- *error = HTTP_INVALID_HEADER;
- return false;
+ // allow special-case for ICY protocol (non-HTTP identifier) in response to faked HTTP request.
+ if (strncmp(buf->content(), "ICY", 3) == 0) {
+ protoPrefix = "ICY";
+ pos = protoPrefix.psize();
}
-
- // catch missing or negative status value (negative '-' is not a digit)
- int pos = protoPrefix.psize();
-
- // skip arbitrary number of digits and a dot in the verion portion
- while ( pos <= buf->contentSize() && (*(buf->content()+pos) == '.' || xisdigit(*(buf->content()+pos)) ) ) ++pos;
-
- // catch missing version info
- if (pos == protoPrefix.psize()) {
- debugs(58, 3, "HttpReply::sanityCheckStartLine: missing protocol version numbers (ie. " << protoPrefix << "/1.0) in '" << buf->content() << "'");
- *error = HTTP_INVALID_HEADER;
- return false;
+ else {
+
+ if (protoPrefix.cmp(buf->content(), protoPrefix.size()) != 0) {
+ debugs(58, 3, "HttpReply::sanityCheckStartLine: missing protocol prefix (" << protoPrefix << ") in '" << buf->content() << "'");
+ *error = HTTP_INVALID_HEADER;
+ return false;
+ }
+
+ // catch missing or negative status value (negative '-' is not a digit)
+ pos = protoPrefix.psize();
+
+ // skip arbitrary number of digits and a dot in the verion portion
+ while ( pos <= buf->contentSize() && (*(buf->content()+pos) == '.' || xisdigit(*(buf->content()+pos)) ) ) ++pos;
+
+ // catch missing version info
+ if (pos == protoPrefix.psize()) {
+ debugs(58, 3, "HttpReply::sanityCheckStartLine: missing protocol version numbers (ie. " << protoPrefix << "/1.0) in '" << buf->content() << "'");
+ *error = HTTP_INVALID_HEADER;
+ return false;
+ }
}
// skip arbitrary number of spaces...
=== modified file 'src/HttpStatusLine.cc'
--- src/HttpStatusLine.cc 2009-09-16 09:53:46 +0000
+++ src/HttpStatusLine.cc 2009-11-01 11:06:47 +0000
@@ -39,6 +39,7 @@
/* local constants */
/* AYJ: see bug 2469 - RFC2616 confirms stating 'SP characters' plural! */
const char *HttpStatusLineFormat = "HTTP/%d.%d %3d %s\r\n";
+const char *IcyStatusLineFormat = "ICY %3d %s\r\n";
void
httpStatusLineInit(HttpStatusLine * sline)
@@ -59,17 +60,31 @@
httpStatusLineSet(HttpStatusLine * sline, HttpVersion version, http_status status, const char *reason)
{
assert(sline);
+ sline->protocol = PROTO_HTTP;
sline->version = version;
sline->status = status;
/* Note: no xstrdup for 'reason', assumes constant 'reasons' */
sline->reason = reason;
}
-/** write HTTP version and status structures into a Packer buffer for output as HTTP status line. */
+/**
+ * Write HTTP version and status structures into a Packer buffer for output as HTTP status line.
+ * Special exemption made for ICY response status lines.
+ */
void
httpStatusLinePackInto(const HttpStatusLine * sline, Packer * p)
{
assert(sline && p);
+
+ /* handle ICY protocol status line specially. Pass on the bad format. */
+ if (sline->protocol == PROTO_ICY) {
+ debugs(57, 9, "packing sline " << sline << " using " << p << ":");
+ debugs(57, 9, "FORMAT=" << IcyStatusLineFormat );
+ debugs(57, 9, "ICY " << sline->status << " " << (sline->reason ? sline->reason : httpStatusString(sline->status)) );
+ packerPrintf(p, IcyStatusLineFormat, sline->status, httpStatusLineReason(sline));
+ return;
+ }
+
debugs(57, 9, "packing sline " << sline << " using " << p << ":");
debugs(57, 9, "FORMAT=" << HttpStatusLineFormat );
debugs(57, 9, "HTTP/" << sline->version.major << "." << sline->version.minor <<
@@ -91,17 +106,24 @@
// XXX: HttpMsg::parse() has a similar check but is using
// casesensitive comparison (which is required by HTTP errata?)
- if (protoPrefix.caseCmp(start, protoPrefix.size()) != 0)
- return 0;
-
- start += protoPrefix.size();
-
- if (!xisdigit(*start))
- return 0;
-
- if (sscanf(start, "%d.%d", &sline->version.major, &sline->version.minor) != 2) {
- debugs(57, 7, "httpStatusLineParse: Invalid HTTP identifier.");
- }
+ if (protoPrefix.cmp("ICY", 3) == 0) {
+ debugs(57, 3, "httpStatusLineParse: Invalid HTTP identifier. Detected ICY protocol istead.");
+ sline->protocol = PROTO_ICY;
+ start += protoPrefix.size();
+ }
+ else if (protoPrefix.caseCmp(start, protoPrefix.size()) != 0) {
+
+ start += protoPrefix.size();
+
+ if (!xisdigit(*start))
+ return 0;
+
+ if (sscanf(start, "%d.%d", &sline->version.major, &sline->version.minor) != 2) {
+ debugs(57, 7, "httpStatusLineParse: Invalid HTTP identifier.");
+ }
+ }
+ else
+ return 0;
if (!(start = strchr(start, ' ')))
return 0;
=== modified file 'src/HttpStatusLine.h'
--- src/HttpStatusLine.h 2009-01-21 03:47:47 +0000
+++ src/HttpStatusLine.h 2009-11-01 08:20:01 +0000
@@ -39,20 +39,32 @@
/* for SQUIDCEXTERN */
#include "config.h"
-/* for http_status */
+/* for http_status and protocol_t */
#include "enums.h"
-/* for class variables */
#include "HttpVersion.h"
+#include "SquidString.h"
+/**
+ * Holds the values parsed from an HTTP reply status line.
+ *
+ * For example: HTTP/1.1 200 Okay
+ */
class HttpStatusLine
{
-
public:
/* public, read only */
- HttpVersion version;
- const char *reason; /**< points to a _constant_ string (default or supplied), never free()d */
- http_status status;
+
+ /**
+ * By rights protocol name should be a constant "HTTP", with no need for this field to exist.
+ * However there are protocols which violate HTTP by sending their wn custom formats
+ * back with other protocol names (ICY streaming format being the current major problem)
+ */
+ protocol_t protocol;
+
+ HttpVersion version; ///< breakdown of protocol version labels: 0.9 1.0 1.1
+ http_status status; ///< status code. ie 200 404
+ const char *reason; ///< points to a _constant_ string (default or supplied), never free()d */
};
/* init/clean */
=== modified file 'src/URLScheme.cc'
--- src/URLScheme.cc 2009-01-21 03:47:47 +0000
+++ src/URLScheme.cc 2009-11-01 11:25:59 +0000
@@ -52,6 +52,6 @@
"whois",
"internal",
"https",
+ "icy",
"TOTAL"
};
-
=== modified file 'src/client_side_reply.cc'
--- src/client_side_reply.cc 2009-09-18 20:40:02 +0000
+++ src/client_side_reply.cc 2009-11-01 10:40:59 +0000
@@ -1440,8 +1440,10 @@
reply = HTTPMSGLOCK(rep);
- /* enforce 1.0 reply version */
- reply->sline.version = HttpVersion(1,0);
+ if (reply->sline.protocol == PROTO_HTTP) {
+ /* enforce 1.0 reply version (but only on real HTTP traffic) */
+ reply->sline.version = HttpVersion(1,0);
+ }
/* do header conversions */
buildReplyHeader();
=== modified file 'src/enums.h'
--- src/enums.h 2009-08-23 05:13:09 +0000
+++ src/enums.h 2009-11-01 08:18:48 +0000
@@ -152,6 +152,7 @@
PROTO_WHOIS,
PROTO_INTERNAL,
PROTO_HTTPS,
+ PROTO_ICY,
PROTO_MAX
} protocol_t;