]>
Commit | Line | Data |
---|---|---|
9b769c67 | 1 | /* |
bf95c10a | 2 | * Copyright (C) 1996-2022 The Squid Software Foundation and contributors |
9b769c67 | 3 | * |
bbc27441 AJ |
4 | * Squid software is distributed under GPLv2+ license and includes |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
9b769c67 AJ |
7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 57 HTTP Status-line */ |
10 | ||
9b769c67 | 11 | #include "squid.h" |
0a647ffb | 12 | #include "base/Packable.h" |
675b8408 | 13 | #include "debug/Stream.h" |
38da9c24 | 14 | #include "http/one/ResponseParser.h" |
9b769c67 | 15 | #include "http/StatusLine.h" |
38da9c24 EB |
16 | #include "parser/forward.h" |
17 | #include "parser/Tokenizer.h" | |
18 | ||
19 | #include <algorithm> | |
9b769c67 AJ |
20 | |
21 | void | |
22 | Http::StatusLine::init() | |
23 | { | |
aee3523a | 24 | set(Http::ProtocolVersion(), Http::scNone, nullptr); |
9b769c67 AJ |
25 | } |
26 | ||
27 | void | |
28 | Http::StatusLine::clean() | |
29 | { | |
aee3523a | 30 | set(Http::ProtocolVersion(), Http::scInternalServerError, nullptr); |
9b769c67 AJ |
31 | } |
32 | ||
33 | /* set values */ | |
34 | void | |
2592bc70 | 35 | Http::StatusLine::set(const AnyP::ProtocolVersion &newVersion, const Http::StatusCode newStatus, const char *newReason) |
9b769c67 | 36 | { |
9b769c67 AJ |
37 | version = newVersion; |
38 | status_ = newStatus; | |
39 | /* Note: no xstrdup for 'reason', assumes constant 'reasons' */ | |
40 | reason_ = newReason; | |
41 | } | |
42 | ||
43 | const char * | |
44 | Http::StatusLine::reason() const | |
45 | { | |
46 | return reason_ ? reason_ : Http::StatusCodeString(status()); | |
47 | } | |
48 | ||
49 | void | |
17802cf1 | 50 | Http::StatusLine::packInto(Packable * p) const |
9b769c67 AJ |
51 | { |
52 | assert(p); | |
53 | ||
7f98aad5 CT |
54 | auto packedStatus = status(); |
55 | auto packedReason = reason(); | |
56 | ||
57 | if (packedStatus == Http::scNone) { | |
58 | static unsigned int reports = 0; | |
59 | if (++reports <= 100) | |
d816f28d | 60 | debugs(57, DBG_IMPORTANT, "ERROR: Squid BUG: the internalized response lacks status-code"); |
7f98aad5 CT |
61 | packedStatus = Http::scInternalServerError; |
62 | packedReason = Http::StatusCodeString(packedStatus); // ignore custom reason_ (if any) | |
63 | } | |
64 | ||
9b769c67 AJ |
65 | /* local constants */ |
66 | /* AYJ: see bug 2469 - RFC2616 confirms stating 'SP characters' plural! */ | |
67 | static const char *Http1StatusLineFormat = "HTTP/%d.%d %3d %s\r\n"; | |
68 | static const char *IcyStatusLineFormat = "ICY %3d %s\r\n"; | |
69 | ||
70 | /* handle ICY protocol status line specially. Pass on the bad format. */ | |
8774ca07 | 71 | if (version.protocol == AnyP::PROTO_ICY) { |
9b769c67 AJ |
72 | debugs(57, 9, "packing sline " << this << " using " << p << ":"); |
73 | debugs(57, 9, "FORMAT=" << IcyStatusLineFormat ); | |
7f98aad5 CT |
74 | debugs(57, 9, "ICY " << packedStatus << " " << packedReason); |
75 | p->appendf(IcyStatusLineFormat, packedStatus, packedReason); | |
9b769c67 AJ |
76 | return; |
77 | } | |
78 | ||
79 | debugs(57, 9, "packing sline " << this << " using " << p << ":"); | |
80 | debugs(57, 9, "FORMAT=" << Http1StatusLineFormat ); | |
7f98aad5 CT |
81 | debugs(57, 9, "HTTP/" << version.major << "." << version.minor << " " << packedStatus << " " << packedReason); |
82 | p->appendf(Http1StatusLineFormat, version.major, version.minor, packedStatus, packedReason); | |
9b769c67 AJ |
83 | } |
84 | ||
9b769c67 | 85 | bool |
38da9c24 | 86 | Http::StatusLine::parse(const String &protoPrefix, const char *start, const char *end) |
9b769c67 | 87 | { |
f53969cc | 88 | status_ = Http::scInvalidHeader; /* Squid header parsing error */ |
9b769c67 | 89 | |
63df1d28 | 90 | // XXX: Http::Message::parse() has a similar check but is using |
9b769c67 AJ |
91 | // casesensitive comparison (which is required by HTTP errata?) |
92 | ||
93 | if (protoPrefix.cmp("ICY", 3) == 0) { | |
61beade2 | 94 | debugs(57, 3, "Invalid HTTP identifier. Detected ICY protocol instead."); |
8774ca07 | 95 | version = AnyP::ProtocolVersion(AnyP::PROTO_ICY, 1, 0); |
9b769c67 AJ |
96 | start += protoPrefix.size(); |
97 | } else if (protoPrefix.caseCmp(start, protoPrefix.size()) == 0) { | |
98 | ||
99 | start += protoPrefix.size(); | |
100 | ||
101 | if (!xisdigit(*start)) | |
102 | return false; | |
103 | ||
104 | // XXX: HTTPbis have defined this to be single-digit version numbers. no need to sscanf() | |
105 | // XXX: furthermore, only HTTP/1 will be using ASCII format digits | |
106 | ||
107 | if (sscanf(start, "%d.%d", &version.major, &version.minor) != 2) { | |
108 | debugs(57, 7, "Invalid HTTP identifier."); | |
109 | return false; | |
110 | } | |
111 | } else | |
112 | return false; | |
113 | ||
114 | if (!(start = strchr(start, ' '))) | |
115 | return false; | |
116 | ||
38da9c24 EB |
117 | ++start; // skip SP between HTTP-version and status-code |
118 | ||
119 | assert(start <= end); | |
120 | const auto stdStatusAreaLength = 4; // status-code length plus SP | |
121 | const auto unparsedLength = end - start; | |
122 | const auto statusAreaLength = std::min<size_t>(stdStatusAreaLength, unparsedLength); | |
123 | ||
124 | static SBuf statusBuf; | |
125 | statusBuf.assign(start, statusAreaLength); | |
126 | Parser::Tokenizer tok(statusBuf); | |
127 | try { | |
128 | One::ResponseParser::ParseResponseStatus(tok, status_); | |
129 | } catch (const Parser::InsufficientInput &) { | |
130 | debugs(57, 7, "need more; have " << unparsedLength); | |
131 | return false; | |
132 | } catch (...) { | |
133 | debugs(57, 3, "cannot parse status-code area: " << CurrentException); | |
134 | return false; | |
135 | } | |
9b769c67 AJ |
136 | |
137 | // XXX check if the given 'reason' is the default status string, if not save to reason_ | |
138 | ||
139 | /* we ignore 'reason-phrase' */ | |
140 | /* Should assert start < end ? */ | |
f53969cc | 141 | return true; /* success */ |
9b769c67 | 142 | } |
f53969cc | 143 |