From: Amos Jeffries Date: Mon, 18 Mar 2013 04:55:51 +0000 (-0600) Subject: SourceLayout: shuffle HttpStatusLine into http/libsquid-http.la X-Git-Tag: SQUID_3_4_0_1~233 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9b769c6702f1596fc4ba9e27d4514ae414a98319;p=thirdparty%2Fsquid.git SourceLayout: shuffle HttpStatusLine into http/libsquid-http.la * moves HttpStatusLine.* to http/StatusLine.* * renames HttpStatusLine to Http::StatusLine * renames httpStatusLine*() functions as members of Http::StatusLine * shuffles StatusCode string conversion function into http/StatusCode * makes reason parameter of StatusLine::set() function optional. There is no logic change involved but callers now no longer need to set it to the status code string explicitly, nor need to set it to NULL explicitly unless intending to replace an existing status string. * adds const-correctness and documentation to StatusLine symbols. --- diff --git a/src/HttpReply.cc b/src/HttpReply.cc index 7965ce5728..1a646a8e65 100644 --- a/src/HttpReply.cc +++ b/src/HttpReply.cc @@ -98,7 +98,7 @@ void HttpReply::init() { hdrCacheInit(); - httpStatusLineInit(&sline); + sline.init(); pstate = psReadyToParseStartLine; do_clean = true; } @@ -126,14 +126,14 @@ HttpReply::clean() body.clear(); hdrCacheClean(); header.clean(); - httpStatusLineClean(&sline); + sline.clean(); bodySizeMax = -2; // hack: make calculatedBodySizeMax() false } void HttpReply::packHeadersInto(Packer * p) const { - httpStatusLinePackInto(&sline, p); + sline.packInto(p); header.packInto(p); packerAppend(p, "\r\n", 2); } @@ -188,7 +188,7 @@ HttpReply::make304() const /* rv->cache_control */ /* rv->content_range */ /* rv->keep_alive */ - httpStatusLineSet(&rv->sline, Http::ProtocolVersion(1,1), Http::scNotModified, NULL); + rv->sline.set(Http::ProtocolVersion(1,1), Http::scNotModified, NULL); for (t = 0; ImsEntries[t] != HDR_OTHER; ++t) if ((e = header.findEntry(ImsEntries[t]))) @@ -215,7 +215,7 @@ HttpReply::setHeaders(Http::StatusCode status, const char *reason, const char *ctype, int64_t clen, time_t lmt, time_t expiresTime) { HttpHeader *hdr; - httpStatusLineSet(&sline, Http::ProtocolVersion(1,1), status, reason); + sline.set(Http::ProtocolVersion(1,1), status, reason); hdr = &header; hdr->putStr(HDR_SERVER, visible_appname_string); hdr->putStr(HDR_MIME_VERSION, "1.0"); @@ -249,7 +249,7 @@ void HttpReply::redirect(Http::StatusCode status, const char *loc) { HttpHeader *hdr; - httpStatusLineSet(&sline, Http::ProtocolVersion(1,1), status, httpStatusString(status)); + sline.set(Http::ProtocolVersion(1,1), status, NULL); hdr = &header; hdr->putStr(HDR_SERVER, APP_FULLNAME); hdr->putTime(HDR_DATE, squid_curtime); @@ -427,13 +427,13 @@ HttpReply::bodySize(const HttpRequestMethod& method) const return -1; else if (method.id() == Http::METHOD_HEAD) return 0; - else if (sline.status == Http::scOkay) + else if (sline.status() == Http::scOkay) (void) 0; /* common case, continue */ - else if (sline.status == Http::scNoContent) + else if (sline.status() == Http::scNoContent) return 0; - else if (sline.status == Http::scNotModified) + else if (sline.status() == Http::scNotModified) return 0; - else if (sline.status < Http::scOkay) + else if (sline.status() < Http::scOkay) return 0; return content_length; @@ -500,14 +500,10 @@ HttpReply::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, Http::StatusC return true; } -void HttpReply::packFirstLineInto(Packer *p, bool unused) const -{ - httpStatusLinePackInto(&sline, p); -} - -bool HttpReply::parseFirstLine(const char *blk_start, const char *blk_end) +bool +HttpReply::parseFirstLine(const char *blk_start, const char *blk_end) { - return httpStatusLineParse(&sline, protoPrefix, blk_start, blk_end); + return sline.parse(protoPrefix, blk_start, blk_end); } /* handy: resets and returns -1 */ @@ -516,7 +512,7 @@ HttpReply::httpMsgParseError() { int result(HttpMsg::httpMsgParseError()); /* indicate an error in the status line */ - sline.status = Http::scInvalidHeader; + sline.set(Http::ProtocolVersion(1,1), Http::scInvalidHeader); return result; } @@ -531,11 +527,11 @@ HttpReply::expectingBody(const HttpRequestMethod& req_method, int64_t& theSize) if (req_method == Http::METHOD_HEAD) expectBody = false; - else if (sline.status == Http::scNoContent) + else if (sline.status() == Http::scNoContent) expectBody = false; - else if (sline.status == Http::scNotModified) + else if (sline.status() == Http::scNotModified) expectBody = false; - else if (sline.status < Http::scOkay) + else if (sline.status() < Http::scOkay) expectBody = false; else expectBody = true; diff --git a/src/HttpReply.h b/src/HttpReply.h index 3718a0eaf8..04e95d70ed 100644 --- a/src/HttpReply.h +++ b/src/HttpReply.h @@ -33,7 +33,7 @@ #include "HttpBody.h" #include "HttpMsg.h" #include "HttpRequest.h" -#include "HttpStatusLine.h" +#include "http/StatusLine.h" void httpReplyInitModule(void); @@ -83,7 +83,7 @@ public: short int keep_alive; /** \par public, writable, but use httpReply* interfaces when possible */ - HttpStatusLine sline; + Http::StatusLine sline; HttpBody body; /**< for small constant memory-resident text bodies only */ @@ -163,7 +163,7 @@ private: mutable int64_t bodySizeMax; /**< cached result of calcMaxBodySize */ protected: - virtual void packFirstLineInto(Packer * p, bool) const; + virtual void packFirstLineInto(Packer * p, bool) const { sline.packInto(p); } virtual bool parseFirstLine(const char *start, const char *end); diff --git a/src/HttpStatusLine.cc b/src/HttpStatusLine.cc deleted file mode 100644 index f3835fba8e..0000000000 --- a/src/HttpStatusLine.cc +++ /dev/null @@ -1,345 +0,0 @@ - -/* - * DEBUG: section 57 HTTP Status-line - * AUTHOR: Alex Rousskov - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#include "Debug.h" -#include "HttpStatusLine.h" -#include "Packer.h" - -/* 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) -{ - httpStatusLineSet(sline, Http::ProtocolVersion(), Http::scNone, NULL); -} - -void -httpStatusLineClean(HttpStatusLine * sline) -{ - httpStatusLineSet(sline, Http::ProtocolVersion(), Http::scInternalServerError, NULL); -} - -/* set values */ -void -httpStatusLineSet(HttpStatusLine * sline, Http::ProtocolVersion version, Http::StatusCode status, const char *reason) -{ - assert(sline); - sline->protocol = AnyP::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. - * 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 == AnyP::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 << - " " << sline->status << " " << (sline->reason ? sline->reason : httpStatusString(sline->status)) ); - packerPrintf(p, HttpStatusLineFormat, sline->version.major, - sline->version.minor, sline->status, httpStatusLineReason(sline)); -} - -/* - * Parse character string into 'sline'. Note 'end' currently unused, - * so NULL-termination assumed. - */ -int -httpStatusLineParse(HttpStatusLine * sline, const String &protoPrefix, const char *start, const char *end) -{ - assert(sline); - sline->status = Http::scInvalidHeader; /* Squid header parsing error */ - - // XXX: HttpMsg::parse() has a similar check but is using - // casesensitive comparison (which is required by HTTP errata?) - - if (protoPrefix.cmp("ICY", 3) == 0) { - debugs(57, 3, "httpStatusLineParse: Invalid HTTP identifier. Detected ICY protocol istead."); - sline->protocol = AnyP::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; - - sline->status = static_cast(atoi(++start)); - - /* we ignore 'reason-phrase' */ - /* Should assert start < end ? */ - return 1; /* success */ -} - -const char * -httpStatusLineReason(const HttpStatusLine * sline) -{ - assert(sline); - return sline->reason ? sline->reason : httpStatusString(sline->status); -} - -const char * -httpStatusString(Http::StatusCode status) -{ - /* why not to return matching string instead of using "p" ? @?@ */ - const char *p = NULL; - - switch (status) { - - case 0: - p = "Init"; /* we init .status with code 0 */ - break; - - case Http::scContinue: - p = "Continue"; - break; - - case Http::scSwitchingProtocols: - p = "Switching Protocols"; - break; - - case Http::scOkay: - p = "OK"; - break; - - case Http::scCreated: - p = "Created"; - break; - - case Http::scAccepted: - p = "Accepted"; - break; - - case Http::scNonAuthoritativeInformation: - p = "Non-Authoritative Information"; - break; - - case Http::scNoContent: - p = "No Content"; - break; - - case Http::scResetContent: - p = "Reset Content"; - break; - - case Http::scPartialContent: - p = "Partial Content"; - break; - - case Http::scMultiStatus: - p = "Multi-Status"; - break; - - case Http::scMultipleChoices: - p = "Multiple Choices"; - break; - - case Http::scMovedPermanently: - p = "Moved Permanently"; - break; - - case Http::scMovedTemporarily: - p = "Moved Temporarily"; - break; - - case Http::scSeeOther: - p = "See Other"; - break; - - case Http::scNotModified: - p = "Not Modified"; - break; - - case Http::scUseProxy: - p = "Use Proxy"; - break; - - case Http::scTemporaryRedirect: - p = "Temporary Redirect"; - break; - - case Http::scPermanentRedirect: - p = "Permanent Redirect"; - break; - - case Http::scBadRequest: - p = "Bad Request"; - break; - - case Http::scUnauthorized: - p = "Unauthorized"; - break; - - case Http::scPaymentRequired: - p = "Payment Required"; - break; - - case Http::scForbidden: - p = "Forbidden"; - break; - - case Http::scNotFound: - p = "Not Found"; - break; - - case Http::scMethodNotAllowed: - p = "Method Not Allowed"; - break; - - case Http::scNotAcceptable: - p = "Not Acceptable"; - break; - - case Http::scProxyAuthenticationRequired: - p = "Proxy Authentication Required"; - break; - - case Http::scRequestTimeout: - p = "Request Time-out"; - break; - - case Http::scConflict: - p = "Conflict"; - break; - - case Http::scGone: - p = "Gone"; - break; - - case Http::scLengthRequired: - p = "Length Required"; - break; - - case Http::scPreconditionFailed: - p = "Precondition Failed"; - break; - - case Http::scRequestEntityTooLarge: - p = "Request Entity Too Large"; - break; - - case Http::scRequestUriTooLarge: - p = "Request-URI Too Large"; - break; - - case Http::scUnsupportedMediaType: - p = "Unsupported Media Type"; - break; - - case Http::scRequestedRangeNotSatisfied: - p = "Requested Range Not Satisfiable"; - break; - - case Http::scExpectationFailed: - p = "Expectation Failed"; - break; - - case Http::scInternalServerError: - p = "Internal Server Error"; - break; - - case Http::scNotImplemented: - p = "Not Implemented"; - break; - - case Http::scBadGateway: - p = "Bad Gateway"; - break; - - case Http::scServiceUnavailable: - p = "Service Unavailable"; - break; - - case Http::scGateway_Timeout: - p = "Gateway Time-out"; - break; - - case Http::scHttpVersionNotSupported: - p = "HTTP Version not supported"; - break; - - // RFC 6585 - case Http::scPreconditionRequired: // 428 - p = "Precondition Required"; - break; - - case Http::scTooManyFields: // 429 - p = "Too Many Requests"; - break; - - case Http::scRequestHeaderFieldsTooLarge: // 431 - p = "Request Header Fields Too Large"; - break; - - case Http::scNetworkAuthenticationRequired: // 511 - p = "Network Authentication Required"; - break; - - default: - p = "Unknown"; - debugs(57, 3, "Unknown HTTP status code: " << status); - break; - } - - return p; -} diff --git a/src/Makefile.am b/src/Makefile.am index 050176fdba..8cab7437f9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -371,9 +371,6 @@ squid_SOURCES = \ HttpStateFlags.h \ http.cc \ http.h \ - http/StatusCode.h \ - HttpStatusLine.cc \ - HttpStatusLine.h \ HttpHeaderFieldStat.h \ HttpHdrCc.h \ HttpHdrCc.cc \ @@ -1153,9 +1150,6 @@ tests_testHttpReply_SOURCES=\ HttpMsg.h \ HttpReply.cc \ HttpReply.h \ - http/StatusCode.h \ - HttpStatusLine.cc \ - HttpStatusLine.h \ Mem.h \ mem.cc \ RegexList.h \ @@ -1203,6 +1197,7 @@ nodist_tests_testHttpReply_SOURCES=\ $(TESTSOURCES) tests_testHttpReply_LDFLAGS = $(LIBADD_DL) tests_testHttpReply_LDADD=\ + http/libsquid-http.la \ acl/libacls.la \ acl/libapi.la \ acl/libstate.la \ @@ -1479,7 +1474,6 @@ tests_testCacheManager_SOURCES = \ HttpHdrScTarget.cc \ HttpMsg.cc \ HttpReply.cc \ - HttpStatusLine.cc \ icp_v2.cc \ icp_v3.cc \ $(IPC_SOURCE) \ @@ -1665,7 +1659,6 @@ tests_testDiskIO_SOURCES = \ HttpMsg.cc \ HttpReply.cc \ HttpRequestMethod.cc \ - HttpStatusLine.cc \ int.h \ int.cc \ SquidList.h \ @@ -1895,7 +1888,6 @@ tests_testEvent_SOURCES = \ RequestFlags.cc \ HttpRequest.cc \ HttpRequestMethod.cc \ - HttpStatusLine.cc \ icp_v2.cc \ icp_v3.cc \ $(IPC_SOURCE) \ @@ -2142,7 +2134,6 @@ tests_testEventLoop_SOURCES = \ RequestFlags.cc \ HttpRequest.cc \ HttpRequestMethod.cc \ - HttpStatusLine.cc \ icp_v2.cc \ icp_v3.cc \ $(IPC_SOURCE) \ @@ -2386,7 +2377,6 @@ tests_test_http_range_SOURCES = \ RequestFlags.cc \ HttpRequest.cc \ HttpRequestMethod.cc \ - HttpStatusLine.cc \ icp_v2.cc \ icp_v3.cc \ int.h \ @@ -2674,7 +2664,6 @@ tests_testHttpRequest_SOURCES = \ HttpHdrScTarget.cc \ HttpMsg.cc \ HttpReply.cc \ - HttpStatusLine.cc \ icp_v2.cc \ icp_v3.cc \ $(IPC_SOURCE) \ @@ -3077,7 +3066,6 @@ tests_testUfs_SOURCES = \ HttpBody.h \ HttpBody.cc \ HttpReply.cc \ - HttpStatusLine.cc \ int.h \ int.cc \ RequestFlags.h \ @@ -3267,7 +3255,6 @@ tests_testRock_SOURCES = \ HttpMsg.cc \ HttpReply.cc \ HttpRequestMethod.cc \ - HttpStatusLine.cc \ int.h \ int.cc \ SquidList.h \ @@ -3419,7 +3406,6 @@ tests_testCoss_SOURCES = \ HttpBody.h \ HttpBody.cc \ HttpReply.cc \ - HttpStatusLine.cc \ int.h \ int.cc \ SquidList.h \ @@ -3646,7 +3632,6 @@ tests_testURL_SOURCES = \ RequestFlags.cc \ HttpRequest.cc \ HttpRequestMethod.cc \ - HttpStatusLine.cc \ icp_v2.cc \ icp_v3.cc \ $(IPC_SOURCE) \ diff --git a/src/Server.cc b/src/Server.cc index 8bfb6a3ac6..41d4a36c32 100644 --- a/src/Server.cc +++ b/src/Server.cc @@ -508,7 +508,7 @@ ServerStateData::maybePurgeOthers() return; // and probably only if the response was successful - if (theFinalReply->sline.status >= 400) + if (theFinalReply->sline.status() >= 400) return; // XXX: should we use originalRequest() here? diff --git a/src/acl/Asn.cc b/src/acl/Asn.cc index d2a9b941b9..43fe185973 100644 --- a/src/acl/Asn.cc +++ b/src/acl/Asn.cc @@ -296,7 +296,7 @@ asHandleReply(void *data, StoreIOBuffer result) debugs(53, DBG_IMPORTANT, "asHandleReply: Called with Error set and size=" << (unsigned int) result.length); asStateFree(asState); return; - } else if (Http::scOkay != e->getReply()->sline.status) { + } else if (e->getReply()->sline.status() != Http::scOkay) { debugs(53, DBG_IMPORTANT, "WARNING: AS " << asState->as_number << " whois request failed"); asStateFree(asState); return; diff --git a/src/acl/HttpStatus.cc b/src/acl/HttpStatus.cc index c5582b999a..a20120cfa9 100644 --- a/src/acl/HttpStatus.cc +++ b/src/acl/HttpStatus.cc @@ -156,11 +156,11 @@ aclParseHTTPStatusList(SplayNode **curlist) int ACLHTTPStatus::match(ACLChecklist *checklist) { - return aclMatchHTTPStatus(&data, Filled(checklist)->reply->sline.status); + return aclMatchHTTPStatus(&data, Filled(checklist)->reply->sline.status()); } int -aclMatchHTTPStatus(SplayNode **dataptr, Http::StatusCode status) +aclMatchHTTPStatus(SplayNode **dataptr, const Http::StatusCode status) { acl_httpstatus_data X(status); diff --git a/src/adaptation/ecap/MessageRep.cc b/src/adaptation/ecap/MessageRep.cc index ecdea7d703..cb97ac1064 100644 --- a/src/adaptation/ecap/MessageRep.cc +++ b/src/adaptation/ecap/MessageRep.cc @@ -292,29 +292,26 @@ Adaptation::Ecap::StatusLineRep::StatusLineRep(HttpReply &aMessage): void Adaptation::Ecap::StatusLineRep::statusCode(int code) { - // TODO: why is .status a enum? Do we not support unknown statuses? - theMessage.sline.status = static_cast(code); + theMessage.sline.set(theMessage.sline.version, static_cast(code), theMessage.sline.reason()); } int Adaptation::Ecap::StatusLineRep::statusCode() const { - // TODO: see statusCode(code) TODO above - return static_cast(theMessage.sline.status); + // TODO: remove cast when possible + return static_cast(theMessage.sline.status()); } void -Adaptation::Ecap::StatusLineRep::reasonPhrase(const Area &) +Adaptation::Ecap::StatusLineRep::reasonPhrase(const Area &str) { - // Squid does not support custom reason phrases - theMessage.sline.reason = NULL; + theMessage.sline.set(theMessage.sline.version, theMessage.sline.status(), str.c_str()); } Adaptation::Ecap::StatusLineRep::Area Adaptation::Ecap::StatusLineRep::reasonPhrase() const { - return theMessage.sline.reason ? - Area::FromTempString(std::string(theMessage.sline.reason)) : Area(); + return Area::FromTempString(std::string(theMessage.sline.reason())); } libecap::Version diff --git a/src/adaptation/icap/Launcher.cc b/src/adaptation/icap/Launcher.cc index a4c1f62142..1355a9cca0 100644 --- a/src/adaptation/icap/Launcher.cc +++ b/src/adaptation/icap/Launcher.cc @@ -130,8 +130,10 @@ bool Adaptation::Icap::Launcher::canRepeat(Adaptation::Icap::XactAbortInfo &info if (!info.icapReply) // did not get to read an ICAP reply; a timeout? return true; - debugs(93,9, HERE << info.icapReply->sline.status); - if (!info.icapReply->sline.status) // failed to parse the reply; I/O err + debugs(93,9, info.icapReply->sline.status()); + // XXX: Http::scNone is not the only sign of parse error + // XXX: if there is a specific HTTP error code describing the problem, that may be set + if (info.icapReply->sline.status() == Http::scNone) // failed to parse the reply; I/O err return true; ACLFilledChecklist *cl = diff --git a/src/adaptation/icap/ModXact.cc b/src/adaptation/icap/ModXact.cc index 3d19e20632..dde83bc645 100644 --- a/src/adaptation/icap/ModXact.cc +++ b/src/adaptation/icap/ModXact.cc @@ -779,14 +779,14 @@ void Adaptation::Icap::ModXact::parseIcapHead() reuseConnection = false; } - switch (icapReply->sline.status) { + switch (icapReply->sline.status()) { - case 100: + case Http::scContinue: handle100Continue(); break; - case 200: - case 201: // Symantec Scan Engine 5.0 and later when modifying HTTP msg + case Http::scOkay: + case Http::scCreated: // Symantec Scan Engine 5.0 and later when modifying HTTP msg if (!validate200Ok()) { throw TexcHere("Invalid ICAP Response"); @@ -796,16 +796,16 @@ void Adaptation::Icap::ModXact::parseIcapHead() break; - case 204: + case Http::scNoContent: handle204NoContent(); break; - case 206: + case Http::scPartialContent: handle206PartialContent(); break; default: - debugs(93, 5, HERE << "ICAP status " << icapReply->sline.status); + debugs(93, 5, "ICAP status " << icapReply->sline.status()); handleUnknownScode(); break; } @@ -1294,7 +1294,7 @@ void Adaptation::Icap::ModXact::finalizeLogInfo() } if (reply_) { - al.http.code = reply_->sline.status; + al.http.code = reply_->sline.status(); al.http.content_type = reply_->content_type.termedBuf(); if (replyHttpBodySize >= 0) { al.cache.replySize = replyHttpBodySize + reply_->hdr_sz; diff --git a/src/adaptation/icap/Options.cc b/src/adaptation/icap/Options.cc index 219589c1de..e219a3751c 100644 --- a/src/adaptation/icap/Options.cc +++ b/src/adaptation/icap/Options.cc @@ -75,7 +75,7 @@ void Adaptation::Icap::Options::configure(const HttpReply *reply) const HttpHeader *h = &reply->header; - if (reply->sline.status != 200) + if (reply->sline.status() != Http::scOkay) error = "unsupported status code of OPTIONS response"; // Methods diff --git a/src/adaptation/icap/Xaction.cc b/src/adaptation/icap/Xaction.cc index a7a80e76a5..9fcc83bcb1 100644 --- a/src/adaptation/icap/Xaction.cc +++ b/src/adaptation/icap/Xaction.cc @@ -577,7 +577,7 @@ void Adaptation::Icap::Xaction::finalizeLogInfo() if (icapReply != NULL) { al.icap.reply = icapReply.getRaw(); HTTPMSGLOCK(al.icap.reply); - al.icap.resStatus = icapReply->sline.status; + al.icap.resStatus = icapReply->sline.status(); } } diff --git a/src/auth/UserRequest.cc b/src/auth/UserRequest.cc index ff38b8780c..899e381964 100644 --- a/src/auth/UserRequest.cc +++ b/src/auth/UserRequest.cc @@ -479,7 +479,7 @@ Auth::UserRequest::addReplyAuthHeader(HttpReply * rep, Auth::UserRequest::Pointe { http_hdr_type type; - switch (rep->sline.status) { + switch (rep->sline.status()) { case Http::scProxyAuthenticationRequired: /* Proxy authorisation needed */ @@ -500,8 +500,8 @@ Auth::UserRequest::addReplyAuthHeader(HttpReply * rep, Auth::UserRequest::Pointe debugs(29, 9, HERE << "headertype:" << type << " authuser:" << auth_user_request); - if (((rep->sline.status == Http::scProxyAuthenticationRequired) - || (rep->sline.status == Http::scUnauthorized)) && internal) + if (((rep->sline.status() == Http::scProxyAuthenticationRequired) + || (rep->sline.status() == Http::scUnauthorized)) && internal) /* this is a authenticate-needed response */ { diff --git a/src/auth/digest/UserRequest.cc b/src/auth/digest/UserRequest.cc index 98f97d5529..3074d10c84 100644 --- a/src/auth/digest/UserRequest.cc +++ b/src/auth/digest/UserRequest.cc @@ -200,8 +200,8 @@ Auth::Digest::UserRequest::addAuthenticationInfoHeader(HttpReply * rep, int acce http_hdr_type type; /* don't add to authentication error pages */ - if ((!accel && rep->sline.status == Http::scProxyAuthenticationRequired) - || (accel && rep->sline.status == Http::scUnauthorized)) + if ((!accel && rep->sline.status() == Http::scProxyAuthenticationRequired) + || (accel && rep->sline.status() == Http::scUnauthorized)) return; type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO; @@ -233,8 +233,8 @@ Auth::Digest::UserRequest::addAuthenticationInfoTrailer(HttpReply * rep, int acc return; /* don't add to authentication error pages */ - if ((!accel && rep->sline.status == Http::scProxyAuthenticationRequired) - || (accel && rep->sline.status == Http::scUnauthorized)) + if ((!accel && rep->sline.status() == Http::scProxyAuthenticationRequired) + || (accel && rep->sline.status() == Http::scUnauthorized)) return; type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO; diff --git a/src/auth/negotiate/UserRequest.cc b/src/auth/negotiate/UserRequest.cc index c24fe9cd56..d4f08a7f36 100644 --- a/src/auth/negotiate/UserRequest.cc +++ b/src/auth/negotiate/UserRequest.cc @@ -385,8 +385,8 @@ Auth::Negotiate::UserRequest::addAuthenticationInfoHeader(HttpReply * rep, int a return; /* don't add to authentication error pages */ - if ((!accel && rep->sline.status == Http::scProxyAuthenticationRequired) - || (accel && rep->sline.status == Http::scUnauthorized)) + if ((!accel && rep->sline.status() == Http::scProxyAuthenticationRequired) + || (accel && rep->sline.status() == Http::scUnauthorized)) return; type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO; diff --git a/src/cache_manager.cc b/src/cache_manager.cc index 4f2f8a11d2..9d881b5cf4 100644 --- a/src/cache_manager.cc +++ b/src/cache_manager.cc @@ -411,7 +411,7 @@ CacheManager::Start(const Comm::ConnectionPointer &client, HttpRequest * request err.url = xstrdup(entry->url()); HttpReply *rep = err.BuildHttpReply(); if (strncmp(rep->body.content(),"Internal Error:", 15) == 0) - rep->sline.status = Http::scNotFound; + rep->sline.set(Http::ProtocolVersion(1,1), Http::scNotFound); // Allow cachemgr and other XHR scripts access to our version string if (request->header.has(HDR_ORIGIN)) { rep->header.putExt("Access-Control-Allow-Origin",request->header.getStr(HDR_ORIGIN)); diff --git a/src/client_side.cc b/src/client_side.cc index b2422fd574..626018be25 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -649,10 +649,10 @@ ClientHttpRequest::logRequest() debugs(33, 9, "clientLogRequest: al.url='" << al->url << "'"); if (al->reply) { - al->http.code = al->reply->sline.status; + al->http.code = al->reply->sline.status(); al->http.content_type = al->reply->content_type.termedBuf(); } else if (loggingEntry() && loggingEntry()->mem_obj) { - al->http.code = loggingEntry()->mem_obj->getReply()->sline.status; + al->http.code = loggingEntry()->mem_obj->getReply()->sline.status(); al->http.content_type = loggingEntry()->mem_obj->getReply()->content_type.termedBuf(); } @@ -1278,7 +1278,7 @@ ClientSocketContext::buildRangeHeader(HttpReply * rep) if (!rep) range_err = "no [parse-able] reply"; - else if ((rep->sline.status != Http::scOkay) && (rep->sline.status != Http::scPartialContent)) + else if ((rep->sline.status() != Http::scOkay) && (rep->sline.status() != Http::scPartialContent)) range_err = "wrong status code"; else if (hdr->has(HDR_CONTENT_RANGE)) range_err = "origin server does ranges"; @@ -1310,8 +1310,8 @@ ClientSocketContext::buildRangeHeader(HttpReply * rep) delete http->request->range; http->request->range = NULL; } else { - /* XXX: TODO: Review, this unconditional set may be wrong. - TODO: review. */ - httpStatusLineSet(&rep->sline, rep->sline.version, Http::scPartialContent, NULL); + /* XXX: TODO: Review, this unconditional set may be wrong. */ + rep->sline.set(rep->sline.version, Http::scPartialContent); // web server responded with a valid, but unexpected range. // will (try-to) forward as-is. //TODO: we should cope with multirange request/responses diff --git a/src/client_side_reply.cc b/src/client_side_reply.cc index e78b2132bc..f5b16aefa5 100644 --- a/src/client_side_reply.cc +++ b/src/client_side_reply.cc @@ -376,7 +376,7 @@ clientReplyContext::handleIMSReply(StoreIOBuffer result) /* update size of the request */ reqsize = result.length + reqofs; - const Http::StatusCode status = http->storeEntry()->getReply()->sline.status; + const Http::StatusCode status = http->storeEntry()->getReply()->sline.status(); // request to origin was aborted if (EBIT_TEST(http->storeEntry()->flags, ENTRY_ABORTED)) { @@ -405,7 +405,7 @@ clientReplyContext::handleIMSReply(StoreIOBuffer result) } else { // send existing entry, it's still valid debugs(88, 3, "handleIMSReply: origin replied 304, revalidating existing entry and sending " << - old_rep->sline.status << " to client"); + old_rep->sline.status() << " to client"); sendClientOldEntry(); } } @@ -428,7 +428,7 @@ clientReplyContext::handleIMSReply(StoreIOBuffer result) // ignore and let client have old entry http->logType = LOG_TCP_REFRESH_FAIL_OLD; debugs(88, 3, "handleIMSReply: origin replied with error " << - status << ", sending old entry (" << old_rep->sline.status << ") to client"); + status << ", sending old entry (" << old_rep->sline.status() << ") to client"); sendClientOldEntry(); } } @@ -714,9 +714,9 @@ clientReplyContext::processConditional(StoreIOBuffer &result) { StoreEntry *const e = http->storeEntry(); - if (e->getReply()->sline.status != Http::scOkay) { + if (e->getReply()->sline.status() != Http::scOkay) { debugs(88, 4, "clientReplyContext::processConditional: Reply code " << - e->getReply()->sline.status << " != 200"); + e->getReply()->sline.status() << " != 200"); http->logType = LOG_TCP_MISS; processMiss(); return; @@ -1430,8 +1430,8 @@ clientReplyContext::buildReplyHeader() #if USE_AUTH /* Handle authentication headers */ if (http->logType == LOG_TCP_DENIED && - ( reply->sline.status == Http::scProxyAuthenticationRequired || - reply->sline.status == Http::scUnauthorized) + ( reply->sline.status() == Http::scProxyAuthenticationRequired || + reply->sline.status() == Http::scUnauthorized) ) { /* Add authentication header */ /*! \todo alter errorstate to be accel on|off aware. The 0 on the next line @@ -1461,7 +1461,7 @@ clientReplyContext::buildReplyHeader() (request->http_ver >= Http::ProtocolVersion(1, 1)); /* Check whether we should send keep-alive */ - if (!Config.onoff.error_pconns && reply->sline.status >= 400 && !request->flags.mustKeepalive) { + if (!Config.onoff.error_pconns && reply->sline.status() >= 400 && !request->flags.mustKeepalive) { debugs(33, 3, "clientBuildReplyHeader: Error, don't keep-alive"); request->flags.proxyKeepalive = false; } else if (!Config.onoff.client_pconns && !request->flags.mustKeepalive) { @@ -1936,7 +1936,7 @@ clientReplyContext::processReplyAccess () /** Don't block our own responses or HTTP status messages */ if (http->logType == LOG_TCP_DENIED || http->logType == LOG_TCP_DENIED_REPLY || - alwaysAllowResponse(reply->sline.status)) { + alwaysAllowResponse(reply->sline.status())) { headers_sz = reply->hdr_sz; processReplyAccessResult(ACCESS_ALLOWED); return; @@ -2018,8 +2018,8 @@ clientReplyContext::processReplyAccessResult(const allow_t &accessAllowed) #if USE_SQUID_ESI - if (http->flags.accel && reply->sline.status != Http::scForbidden && - !alwaysAllowResponse(reply->sline.status) && + if (http->flags.accel && reply->sline.status() != Http::scForbidden && + !alwaysAllowResponse(reply->sline.status()) && esiEnableProcessing(reply)) { debugs(88, 2, "Enabling ESI processing for " << http->uri); clientStreamInsertHead(&http->client_stream, esiStreamRead, diff --git a/src/esi/Esi.cc b/src/esi/Esi.cc index af2b7f793c..939ee507dc 100644 --- a/src/esi/Esi.cc +++ b/src/esi/Esi.cc @@ -888,7 +888,7 @@ ESIContextNew (HttpReply *rep, clientStreamNode *thisNode, ClientHttpRequest *ht rv->rep = rep; rv->cbdataLocker = rv; - if (esiAlwaysPassthrough(rep->sline.status)) { + if (esiAlwaysPassthrough(rep->sline.status())) { rv->flags.passthrough = 1; } else { /* remove specific headers for ESI to prevent diff --git a/src/esi/Include.cc b/src/esi/Include.cc index 837056e068..2bb907f71f 100644 --- a/src/esi/Include.cc +++ b/src/esi/Include.cc @@ -114,7 +114,7 @@ esiBufferRecipient (clientStreamNode *node, ClientHttpRequest *http, HttpReply * assert(rep == NULL); } else { if (rep) { - if (rep->sline.status != Http::scOkay) { + if (rep->sline.status() != Http::scOkay) { rep = NULL; esiStream->include->includeFail (esiStream); esiStream->finished = 1; diff --git a/src/forward.cc b/src/forward.cc index 18a357de02..5d594e0197 100644 --- a/src/forward.cc +++ b/src/forward.cc @@ -399,7 +399,7 @@ FwdState::startConnectionOrFail() void FwdState::fail(ErrorState * errorState) { - debugs(17, 3, HERE << err_type_str[errorState->type] << " \"" << httpStatusString(errorState->httpStatus) << "\"\n\t" << entry->url() ); + debugs(17, 3, err_type_str[errorState->type] << " \"" << Http::StatusCodeString(errorState->httpStatus) << "\"\n\t" << entry->url()); delete err; err = errorState; @@ -455,16 +455,16 @@ FwdState::unregister(int fd) void FwdState::complete() { - debugs(17, 3, HERE << entry->url() << "\n\tstatus " << entry->getReply()->sline.status ); + debugs(17, 3, HERE << entry->url() << "\n\tstatus " << entry->getReply()->sline.status()); #if URL_CHECKSUM_DEBUG entry->mem_obj->checkUrlChecksum(); #endif - logReplyStatus(n_tries, entry->getReply()->sline.status); + logReplyStatus(n_tries, entry->getReply()->sline.status()); if (reforward()) { - debugs(17, 3, HERE << "re-forwarding " << entry->getReply()->sline.status << " " << entry->url()); + debugs(17, 3, HERE << "re-forwarding " << entry->getReply()->sline.status() << " " << entry->url()); if (Comm::IsConnOpen(serverConn)) unregister(serverConn); @@ -477,9 +477,9 @@ FwdState::complete() } else { if (Comm::IsConnOpen(serverConn)) - debugs(17, 3, HERE << "server FD " << serverConnection()->fd << " not re-forwarding status " << entry->getReply()->sline.status); + debugs(17, 3, HERE << "server FD " << serverConnection()->fd << " not re-forwarding status " << entry->getReply()->sline.status()); else - debugs(17, 3, HERE << "server (FD closed) not re-forwarding status " << entry->getReply()->sline.status); + debugs(17, 3, HERE << "server (FD closed) not re-forwarding status " << entry->getReply()->sline.status()); EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); entry->complete(); @@ -1380,7 +1380,7 @@ FwdState::reforward() return 0; } - const Http::StatusCode s = e->getReply()->sline.status; + const Http::StatusCode s = e->getReply()->sline.status(); debugs(17, 3, HERE << "status " << s); return reforwardableStatus(s); } diff --git a/src/http.cc b/src/http.cc index 7dc88aa28e..685204132f 100644 --- a/src/http.cc +++ b/src/http.cc @@ -442,7 +442,7 @@ HttpStateData::cacheableReply() return 0; } - switch (rep->sline.status) { + switch (rep->sline.status()) { /* Responses that are cacheable */ case Http::scOkay: @@ -464,7 +464,7 @@ HttpStateData::cacheableReply() debugs(22, 3, "NO because refreshIsCachable() returned non-cacheable.."); return 0; } else { - debugs(22, 3, HERE << "YES because HTTP status " << rep->sline.status); + debugs(22, 3, HERE << "YES because HTTP status " << rep->sline.status()); return 1; } /* NOTREACHED */ @@ -475,14 +475,14 @@ HttpStateData::cacheableReply() case Http::scMovedTemporarily: case Http::scTemporaryRedirect: if (rep->date <= 0) { - debugs(22, 3, HERE << "NO because HTTP status " << rep->sline.status << " and Date missing/invalid"); + debugs(22, 3, HERE << "NO because HTTP status " << rep->sline.status() << " and Date missing/invalid"); return 0; } if (rep->expires > rep->date) { - debugs(22, 3, HERE << "YES because HTTP status " << rep->sline.status << " and Expires > Date"); + debugs(22, 3, HERE << "YES because HTTP status " << rep->sline.status() << " and Expires > Date"); return 1; } else { - debugs(22, 3, HERE << "NO because HTTP status " << rep->sline.status << " and Expires <= Date"); + debugs(22, 3, HERE << "NO because HTTP status " << rep->sline.status() << " and Expires <= Date"); return 0; } /* NOTREACHED */ @@ -513,7 +513,7 @@ HttpStateData::cacheableReply() case Http::scServiceUnavailable: case Http::scGateway_Timeout: - debugs(22, 3, HERE << "MAYBE because HTTP status " << rep->sline.status); + debugs(22, 3, HERE << "MAYBE because HTTP status " << rep->sline.status()); return -1; /* NOTREACHED */ @@ -550,12 +550,12 @@ HttpStateData::cacheableReply() case Http::scRequestedRangeNotSatisfied: case Http::scExpectationFailed: - debugs(22, 3, HERE << "NO because HTTP status " << rep->sline.status); + debugs(22, 3, HERE << "NO because HTTP status " << rep->sline.status()); return 0; default: /* RFC 2616 section 6.1.1: an unrecognized response MUST NOT be cached. */ - debugs (11, 3, HERE << "NO because unknown HTTP status code " << rep->sline.status); + debugs (11, 3, HERE << "NO because unknown HTTP status code " << rep->sline.status()); return 0; /* NOTREACHED */ @@ -714,8 +714,9 @@ HttpStateData::processReplyHeader() if (!parsed && error > 0) { // unrecoverable parsing error debugs(11, 3, "processReplyHeader: Non-HTTP-compliant header: '" << readBuf->content() << "'"); flags.headers_parsed = true; - newrep->sline.version = Http::ProtocolVersion(1,1); - newrep->sline.status = error; + // XXX: when sanityCheck is gone and Http::StatusLine is used to parse, + // the sline should be already set the appropriate values during that parser stage + newrep->sline.set(Http::ProtocolVersion(1,1), error); HttpReply *vrep = setVirginReply(newrep); entry->replaceHttpReply(vrep); ctx_exit(ctx); @@ -739,7 +740,7 @@ HttpStateData::processReplyHeader() newrep->removeStaleWarnings(); - if (newrep->sline.protocol == AnyP::PROTO_HTTP && newrep->sline.status >= 100 && newrep->sline.status < 200) { + if (newrep->sline.protocol == AnyP::PROTO_HTTP && newrep->sline.status() >= 100 && newrep->sline.status() < 200) { handle1xx(newrep); ctx_exit(ctx); return; @@ -763,7 +764,7 @@ HttpStateData::processReplyHeader() processSurrogateControl (vrep); - request->hier.peer_reply_status = newrep->sline.status; + request->hier.peer_reply_status = newrep->sline.status(); ctx_exit(ctx); } @@ -848,7 +849,7 @@ bool HttpStateData::peerSupportsConnectionPinning() const /*The peer supports connection pinning and the http reply status is not unauthorized, so the related connection can be pinned */ - if (rep->sline.status != Http::scUnauthorized) + if (rep->sline.status() != Http::scUnauthorized) return true; /*The server respond with Http::scUnauthorized and the peer configured @@ -897,17 +898,16 @@ HttpStateData::haveParsedReplyHeaders() Ctx ctx = ctx_enter(entry->mem_obj->url); HttpReply *rep = finalReply(); - if (rep->sline.status == Http::scPartialContent && - rep->content_range) + if (rep->sline.status() == Http::scPartialContent && rep->content_range) currentOffset = rep->content_range->spec.offset; entry->timestampsSet(); /* Check if object is cacheable or not based on reply code */ - debugs(11, 3, "haveParsedReplyHeaders: HTTP CODE: " << rep->sline.status); + debugs(11, 3, "HTTP CODE: " << rep->sline.status()); if (neighbors_do_private_keys) - httpMaybeRemovePublic(entry, rep->sline.status); + httpMaybeRemovePublic(entry, rep->sline.status()); if (rep->header.has(HDR_VARY) #if X_ACCELERATOR_VARY @@ -918,7 +918,7 @@ HttpStateData::haveParsedReplyHeaders() if (!vary) { entry->makePrivate(); - if (!fwd->reforwardableStatus(rep->sline.status)) + if (!fwd->reforwardableStatus(rep->sline.status())) EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); goto no_cache; } @@ -930,7 +930,7 @@ HttpStateData::haveParsedReplyHeaders() * If its not a reply that we will re-forward, then * allow the client to get it. */ - if (!fwd->reforwardableStatus(rep->sline.status)) + if (!fwd->reforwardableStatus(rep->sline.status())) EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); switch (cacheableReply()) { @@ -1260,7 +1260,7 @@ HttpStateData::continueAfterParsingHeader() if (flags.headers_parsed) { // parsed headers, possibly with errors // check for header parsing errors if (HttpReply *vrep = virginReply()) { - const Http::StatusCode s = vrep->sline.status; + const Http::StatusCode s = vrep->sline.status(); const Http::ProtocolVersion &v = vrep->sline.version; if (s == Http::scInvalidHeader && v != Http::ProtocolVersion(0,9)) { debugs(11, DBG_IMPORTANT, "WARNING: HTTP: Invalid Response: Bad header encountered from " << entry->url() << " AKA " << request->GetHost() << request->urlpath.termedBuf() ); @@ -2322,7 +2322,7 @@ HttpStateData::handleMoreRequestBodyAvailable() flags.abuse_detected = true; debugs(11, DBG_IMPORTANT, "http handleMoreRequestBodyAvailable: Likely proxy abuse detected '" << request->client_addr << "' -> '" << entry->url() << "'" ); - if (virginReply()->sline.status == Http::scInvalidHeader) { + if (virginReply()->sline.status() == Http::scInvalidHeader) { serverConnection->close(); return; } diff --git a/src/http/Makefile.am b/src/http/Makefile.am index a887316ff6..7c7530bd1a 100644 --- a/src/http/Makefile.am +++ b/src/http/Makefile.am @@ -7,7 +7,10 @@ libsquid_http_la_SOURCES = \ MethodType.cc \ MethodType.h \ ProtocolVersion.h \ - StatusCode.h + StatusCode.cc \ + StatusCode.h \ + StatusLine.cc \ + StatusLine.h MethodType.cc: MethodType.h $(top_srcdir)/src/mk-string-arrays.awk ($(AWK) -f $(top_srcdir)/src/mk-string-arrays.awk < $(srcdir)/MethodType.h | \ diff --git a/src/http/StatusCode.cc b/src/http/StatusCode.cc new file mode 100644 index 0000000000..f9e2aa82a6 --- /dev/null +++ b/src/http/StatusCode.cc @@ -0,0 +1,203 @@ +#include "squid.h" +#include "Debug.h" +#include "http/StatusCode.h" + +const char * +Http::StatusCodeString(const Http::StatusCode status) +{ + switch (status) { + + case Http::scNone: + return "Init"; /* we init .status with code 0 */ + break; + + case Http::scContinue: + return "Continue"; + break; + + case Http::scSwitchingProtocols: + return "Switching Protocols"; + break; + + case Http::scOkay: + return "OK"; + break; + + case Http::scCreated: + return "Created"; + break; + + case Http::scAccepted: + return "Accepted"; + break; + + case Http::scNonAuthoritativeInformation: + return "Non-Authoritative Information"; + break; + + case Http::scNoContent: + return "No Content"; + break; + + case Http::scResetContent: + return "Reset Content"; + break; + + case Http::scPartialContent: + return "Partial Content"; + break; + + case Http::scMultiStatus: + return "Multi-Status"; + break; + + case Http::scMultipleChoices: + return "Multiple Choices"; + break; + + case Http::scMovedPermanently: + return "Moved Permanently"; + break; + + case Http::scMovedTemporarily: + return "Moved Temporarily"; + break; + + case Http::scSeeOther: + return "See Other"; + break; + + case Http::scNotModified: + return "Not Modified"; + break; + + case Http::scUseProxy: + return "Use Proxy"; + break; + + case Http::scTemporaryRedirect: + return "Temporary Redirect"; + break; + + case Http::scPermanentRedirect: + return "Permanent Redirect"; + break; + + case Http::scBadRequest: + return "Bad Request"; + break; + + case Http::scUnauthorized: + return "Unauthorized"; + break; + + case Http::scPaymentRequired: + return "Payment Required"; + break; + + case Http::scForbidden: + return "Forbidden"; + break; + + case Http::scNotFound: + return "Not Found"; + break; + + case Http::scMethodNotAllowed: + return "Method Not Allowed"; + break; + + case Http::scNotAcceptable: + return "Not Acceptable"; + break; + + case Http::scProxyAuthenticationRequired: + return "Proxy Authentication Required"; + break; + + case Http::scRequestTimeout: + return "Request Time-out"; + break; + + case Http::scConflict: + return "Conflict"; + break; + + case Http::scGone: + return "Gone"; + break; + + case Http::scLengthRequired: + return "Length Required"; + break; + + case Http::scPreconditionFailed: + return "Precondition Failed"; + break; + + case Http::scRequestEntityTooLarge: + return "Request Entity Too Large"; + break; + + case Http::scRequestUriTooLarge: + return "Request-URI Too Large"; + break; + + case Http::scUnsupportedMediaType: + return "Unsupported Media Type"; + break; + + case Http::scRequestedRangeNotSatisfied: + return "Requested Range Not Satisfiable"; + break; + + case Http::scExpectationFailed: + return "Expectation Failed"; + break; + + case Http::scInternalServerError: + return "Internal Server Error"; + break; + + case Http::scNotImplemented: + return "Not Implemented"; + break; + + case Http::scBadGateway: + return "Bad Gateway"; + break; + + case Http::scServiceUnavailable: + return "Service Unavailable"; + break; + + case Http::scGateway_Timeout: + return "Gateway Time-out"; + break; + + case Http::scHttpVersionNotSupported: + return "HTTP Version not supported"; + break; + + // RFC 6585 + case Http::scPreconditionRequired: // 428 + return "Precondition Required"; + break; + + case Http::scTooManyFields: // 429 + return "Too Many Requests"; + break; + + case Http::scRequestHeaderFieldsTooLarge: // 431 + return "Request Header Fields Too Large"; + break; + + case Http::scNetworkAuthenticationRequired: // 511 + return "Network Authentication Required"; + break; + + default: + debugs(57, 3, "Unknown HTTP status code: " << status); + return "Unknown"; + } +} diff --git a/src/http/StatusCode.h b/src/http/StatusCode.h index d95b0092da..6d73844a0d 100644 --- a/src/http/StatusCode.h +++ b/src/http/StatusCode.h @@ -68,6 +68,8 @@ typedef enum { scHeaderTooLarge = 601 /* Header too large to process */ } StatusCode; +const char *StatusCodeString(const Http::StatusCode status); + } // namespace Http #endif /* _SQUID_SRC_HTTP_STATUSCODE_H */ diff --git a/src/http/StatusLine.cc b/src/http/StatusLine.cc new file mode 100644 index 0000000000..d6443e0529 --- /dev/null +++ b/src/http/StatusLine.cc @@ -0,0 +1,136 @@ +/* + * DEBUG: section 57 HTTP Status-line + * AUTHOR: Alex Rousskov + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "Debug.h" +#include "http/StatusLine.h" +#include "Packer.h" + +void +Http::StatusLine::init() +{ + set(Http::ProtocolVersion(), Http::scNone, NULL); +} + +void +Http::StatusLine::clean() +{ + set(Http::ProtocolVersion(), Http::scInternalServerError, NULL); +} + +/* set values */ +void +Http::StatusLine::set(const Http::ProtocolVersion &newVersion, const Http::StatusCode newStatus, const char *newReason) +{ + protocol = AnyP::PROTO_HTTP; + version = newVersion; + status_ = newStatus; + /* Note: no xstrdup for 'reason', assumes constant 'reasons' */ + reason_ = newReason; +} + +const char * +Http::StatusLine::reason() const +{ + return reason_ ? reason_ : Http::StatusCodeString(status()); +} + +void +Http::StatusLine::packInto(Packer * p) const +{ + assert(p); + + /* local constants */ + /* AYJ: see bug 2469 - RFC2616 confirms stating 'SP characters' plural! */ + static const char *Http1StatusLineFormat = "HTTP/%d.%d %3d %s\r\n"; + static const char *IcyStatusLineFormat = "ICY %3d %s\r\n"; + + /* handle ICY protocol status line specially. Pass on the bad format. */ + if (protocol == AnyP::PROTO_ICY) { + debugs(57, 9, "packing sline " << this << " using " << p << ":"); + debugs(57, 9, "FORMAT=" << IcyStatusLineFormat ); + debugs(57, 9, "ICY " << status() << " " << reason()); + packerPrintf(p, IcyStatusLineFormat, status(), reason()); + return; + } + + debugs(57, 9, "packing sline " << this << " using " << p << ":"); + debugs(57, 9, "FORMAT=" << Http1StatusLineFormat ); + debugs(57, 9, "HTTP/" << version.major << "." << version.minor << " " << status() << " " << reason()); + packerPrintf(p, Http1StatusLineFormat, version.major, version.minor, status(), reason()); +} + +/* + * Parse character string. + * XXX: Note 'end' currently unused, so NULL-termination assumed. + */ +bool +Http::StatusLine::parse(const String &protoPrefix, const char *start, const char *end) +{ + status_ = Http::scInvalidHeader; /* Squid header parsing error */ + + // XXX: HttpMsg::parse() has a similar check but is using + // casesensitive comparison (which is required by HTTP errata?) + + if (protoPrefix.cmp("ICY", 3) == 0) { + debugs(57, 3, "Invalid HTTP identifier. Detected ICY protocol istead."); + protocol = AnyP::PROTO_ICY; + start += protoPrefix.size(); + } else if (protoPrefix.caseCmp(start, protoPrefix.size()) == 0) { + + start += protoPrefix.size(); + + if (!xisdigit(*start)) + return false; + + // XXX: HTTPbis have defined this to be single-digit version numbers. no need to sscanf() + // XXX: furthermore, only HTTP/1 will be using ASCII format digits + + if (sscanf(start, "%d.%d", &version.major, &version.minor) != 2) { + debugs(57, 7, "Invalid HTTP identifier."); + return false; + } + } else + return false; + + if (!(start = strchr(start, ' '))) + return false; + + // XXX: should we be using xstrtoui() or xatoui() ? + status_ = static_cast(atoi(++start)); + + // XXX check if the given 'reason' is the default status string, if not save to reason_ + + /* we ignore 'reason-phrase' */ + /* Should assert start < end ? */ + return true; /* success */ +} diff --git a/src/HttpStatusLine.h b/src/http/StatusLine.h similarity index 59% rename from src/HttpStatusLine.h rename to src/http/StatusLine.h index f98586c771..1cad667d97 100644 --- a/src/HttpStatusLine.h +++ b/src/http/StatusLine.h @@ -28,8 +28,8 @@ * * Copyright (c) 2003, Robert Collins */ -#ifndef SQUID_HTTPSTATUSLINE_H -#define SQUID_HTTPSTATUSLINE_H +#ifndef SQUID_HTTP_STATUSLINE_H +#define SQUID_HTTP_STATUSLINE_H #include "http/ProtocolVersion.h" #include "http/StatusCode.h" @@ -38,13 +38,42 @@ class Packer; class String; +namespace Http +{ + /** * Holds the values parsed from an HTTP reply status line. * - * For example: HTTP/1.1 200 Okay + * For example: HTTP/1.1 200 OK */ -class HttpStatusLine +class StatusLine { +public: + /// reset this status-line back to empty state + void init(); + + /// reset this status-line back to Internal Server Error state + void clean(); + + /// set this status-line to the given values + /// when reason is NULL the default message text for this StatusCode will be used + void set(const Http::ProtocolVersion &newVersion, Http::StatusCode newStatus, const char *newReason = NULL); + + /// retrieve the status code for this status line + const Http::StatusCode status() const { return status_; } + + /// retrieve the reason string for this status line + const char *reason() const; + + /// pack fields using Packer + void packInto(Packer * p) const; + + /** + * Parse a buffer and fill internal structures; + * \return true on success, false otherwise + */ + bool parse(const String &protoPrefix, const char *start, const char *end); + public: /* public, read only */ @@ -53,27 +82,19 @@ public: * However there are protocols which violate HTTP by sending their own custom formats * back with other protocol names (ICY streaming format being the current major problem). */ + // XXX: protocol is part of Http::ProtocolVersion. We should be able to use version.protocol instead now. AnyP::ProtocolType protocol; - Http::ProtocolVersion version; ///< breakdown of protocol version labels: 0.9 1.0 1.1 - Http::StatusCode status; ///< status code. ie 200 404 - const char *reason; ///< points to a _constant_ string (default or supplied), never free()d */ + Http::ProtocolVersion version; ///< breakdown of protocol version label: (HTTP/ICY) and (0.9/1.0/1.1) + +private: + /// status code. ie 100 ... 200 ... 404 ... 599 + Http::StatusCode status_; + + /// points to a _constant_ string (default or supplied), never free()d + const char *reason_; }; -/* init/clean */ -void httpStatusLineInit(HttpStatusLine * sline); -void httpStatusLineClean(HttpStatusLine * sline); -/* set/get values */ -void httpStatusLineSet(HttpStatusLine * sline, Http::ProtocolVersion version, - Http::StatusCode status, const char *reason); -const char *httpStatusLineReason(const HttpStatusLine * sline); -/* parse/pack */ -/* parse a 0-terminating buffer and fill internal structires; returns true on success */ -int httpStatusLineParse(HttpStatusLine * sline, const String &protoPrefix, - const char *start, const char *end); -/* pack fields using Packer */ -void httpStatusLinePackInto(const HttpStatusLine * sline, Packer * p); - -const char *httpStatusString(Http::StatusCode status); - -#endif /* SQUID_HTTPSTATUSLINE_H */ +} // namespace Http + +#endif /* SQUID_HTTP_STATUSLINE_H */ diff --git a/src/icmp/net_db.cc b/src/icmp/net_db.cc index 1361437fb0..504e5b023c 100644 --- a/src/icmp/net_db.cc +++ b/src/icmp/net_db.cc @@ -742,10 +742,10 @@ netdbExchangeHandleReply(void *data, StoreIOBuffer receivedData) if ((hdr_sz = headersEnd(p, ex->buf_ofs))) { debugs(38, 5, "netdbExchangeHandleReply: hdr_sz = " << hdr_sz); rep = ex->e->getReply(); - assert (0 != rep->sline.status); - debugs(38, 3, "netdbExchangeHandleReply: reply status " << rep->sline.status); + assert(rep->sline.status() != Http::scNone); + debugs(38, 3, "netdbExchangeHandleReply: reply status " << rep->sline.status()); - if (Http::scOkay != rep->sline.status) { + if (rep->sline.status() != Http::scOkay) { netdbExchangeDone(ex); return; } diff --git a/src/log/access_log.cc b/src/log/access_log.cc index b4775bf9ca..7ab4cb9c05 100644 --- a/src/log/access_log.cc +++ b/src/log/access_log.cc @@ -531,7 +531,6 @@ headersLog(int cs, int pq, const HttpRequestMethod& method, void *data) HttpRequest *req; unsigned short magic = 0; unsigned char M = (unsigned char) m; - unsigned short S; char *hmask; int ccmask = 0; @@ -566,10 +565,9 @@ headersLog(int cs, int pq, const HttpRequestMethod& method, void *data) magic = htons(magic); ccmask = htonl(ccmask); + unsigned short S = 0; if (0 == pq) - S = (unsigned short) rep->sline.status; - else - S = (unsigned short) Http::scNone; + S = static_cast(rep->sline.status()); logfileWrite(headerslog, &magic, sizeof(magic)); logfileWrite(headerslog, &M, sizeof(M)); diff --git a/src/peer_digest.cc b/src/peer_digest.cc index 749bff28c8..a00e26f3ac 100644 --- a/src/peer_digest.cc +++ b/src/peer_digest.cc @@ -546,11 +546,10 @@ peerDigestFetchReply(void *data, char *buf, ssize_t size) return -1; if ((hdr_size = headersEnd(buf, size))) { - Http::StatusCode status; HttpReply const *reply = fetch->entry->getReply(); assert(reply); - assert (reply->sline.status != 0); - status = reply->sline.status; + assert(reply->sline.status() != Http::scNone); + const Http::StatusCode status = reply->sline.status(); debugs(72, 3, "peerDigestFetchReply: " << pd->host << " status: " << status << ", expires: " << (long int) reply->expires << " (" << std::showpos << (int) (reply->expires - squid_curtime) << ")"); @@ -598,7 +597,7 @@ peerDigestFetchReply(void *data, char *buf, ssize_t size) } } else { /* some kind of a bug */ - peerDigestFetchAbort(fetch, buf, httpStatusLineReason(&reply->sline)); + peerDigestFetchAbort(fetch, buf, reply->sline.reason()); return -1; /* XXX -1 will abort stuff in ReadReply! */ } @@ -638,11 +637,11 @@ peerDigestSwapInHeaders(void *data, char *buf, ssize_t size) if ((hdr_size = headersEnd(buf, size))) { assert(fetch->entry->getReply()); - assert (fetch->entry->getReply()->sline.status != 0); + assert(fetch->entry->getReply()->sline.status() != Http::scNone); - if (fetch->entry->getReply()->sline.status != Http::scOkay) { + if (fetch->entry->getReply()->sline.status() != Http::scOkay) { debugs(72, DBG_IMPORTANT, "peerDigestSwapInHeaders: " << fetch->pd->host << - " status " << fetch->entry->getReply()->sline.status << + " status " << fetch->entry->getReply()->sline.status() << " got cached!"); peerDigestFetchAbort(fetch, buf, "internal status error"); diff --git a/src/store.cc b/src/store.cc index 2df2322480..bed4525af8 100644 --- a/src/store.cc +++ b/src/store.cc @@ -1402,10 +1402,10 @@ StoreEntry::validLength() const return 1; } - if (reply->sline.status == Http::scNotModified) + if (reply->sline.status() == Http::scNotModified) return 1; - if (reply->sline.status == Http::scNoContent) + if (reply->sline.status() == Http::scNoContent) return 1; diff = reply->hdr_sz + reply->content_length - objectLen(); diff --git a/src/store_client.cc b/src/store_client.cc index 56ce3c6d45..3c6c4186f1 100644 --- a/src/store_client.cc +++ b/src/store_client.cc @@ -495,7 +495,7 @@ store_client::readBody(const char *buf, ssize_t len) assert(_callback.pending()); debugs(90, 3, "storeClientReadBody: len " << len << ""); - if (copyInto.offset == 0 && len > 0 && entry->getReply()->sline.status == 0) { + if (copyInto.offset == 0 && len > 0 && entry->getReply()->sline.status() == Http::scNone) { /* Our structure ! */ HttpReply *rep = (HttpReply *) entry->getReply(); // bypass const diff --git a/src/store_log.cc b/src/store_log.cc index 9464857f32..c4b32217ae 100644 --- a/src/store_log.cc +++ b/src/store_log.cc @@ -93,7 +93,7 @@ storeLog(int tag, const StoreEntry * e) e->swap_dirn, e->swap_filen, e->getMD5Text(), - reply->sline.status, + reply->sline.status(), (int) reply->date, (int) reply->last_modified, (int) reply->expires, diff --git a/src/tests/stub_HttpReply.cc b/src/tests/stub_HttpReply.cc index 21eff0fd7e..a361b8d64e 100644 --- a/src/tests/stub_HttpReply.cc +++ b/src/tests/stub_HttpReply.cc @@ -16,7 +16,6 @@ HttpReply::HttpReply() : HttpMsg(hoReply), date (0), last_modified (0), bool HttpReply::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, Http::StatusCode *error) STUB_RETVAL(false) int HttpReply::httpMsgParseError() STUB_RETVAL(0) bool HttpReply::expectingBody(const HttpRequestMethod&, int64_t&) const STUB_RETVAL(false) - void HttpReply::packFirstLineInto(Packer * p, bool) const STUB bool HttpReply::parseFirstLine(const char *start, const char *end) STUB_RETVAL(false) void HttpReply::hdrCacheInit() STUB HttpReply * HttpReply::clone() const STUB_RETVAL(NULL) diff --git a/src/urn.cc b/src/urn.cc index a85ccb8a7c..28dfa1e5a3 100644 --- a/src/urn.cc +++ b/src/urn.cc @@ -372,9 +372,9 @@ urnHandleReply(void *data, StoreIOBuffer result) assert(urlres_e->getReply()); rep = new HttpReply; rep->parseCharBuf(buf, k); - debugs(52, 3, "reply exists, code=" << rep->sline.status << "."); + debugs(52, 3, "reply exists, code=" << rep->sline.status() << "."); - if (rep->sline.status != Http::scOkay) { + if (rep->sline.status() != Http::scOkay) { debugs(52, 3, "urnHandleReply: failed."); err = new ErrorState(ERR_URN_RESOLVE, Http::scNotFound, urnState->request); err->url = xstrdup(e->url());