]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/http/StatusLine.cc
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 57 HTTP Status-line */
12 #include "base/Packable.h"
13 #include "debug/Stream.h"
14 #include "http/one/ResponseParser.h"
15 #include "http/StatusLine.h"
16 #include "parser/forward.h"
17 #include "parser/Tokenizer.h"
22 Http::StatusLine::init()
24 set(Http::ProtocolVersion(), Http::scNone
, nullptr);
28 Http::StatusLine::clean()
30 set(Http::ProtocolVersion(), Http::scInternalServerError
, nullptr);
35 Http::StatusLine::set(const AnyP::ProtocolVersion
&newVersion
, const Http::StatusCode newStatus
, const char *newReason
)
39 /* Note: no xstrdup for 'reason', assumes constant 'reasons' */
44 Http::StatusLine::reason() const
46 return reason_
? reason_
: Http::StatusCodeString(status());
50 Http::StatusLine::packedLength() const
52 // Keep in sync with packInto(). TODO: Refactor to avoid code duplication.
54 auto packedStatus
= status();
55 auto packedReason
= reason();
57 if (packedStatus
== scNone
) {
58 packedStatus
= scInternalServerError
;
59 packedReason
= StatusCodeString(packedStatus
);
63 if (version
.protocol
== AnyP::PROTO_ICY
) {
67 + 3 // %3d (packedStatus)
69 + strlen(packedReason
) // %s
73 // "HTTP/%d.%d %3d %s\r\n"
77 + 3 // %d.%d (version.major and version.minor)
79 + 3 // %3d (packedStatus)
81 + strlen(packedReason
) // %s
86 Http::StatusLine::packInto(Packable
* p
) const
88 // Keep in sync with packedLength().
92 auto packedStatus
= status();
93 auto packedReason
= reason();
95 if (packedStatus
== Http::scNone
) {
96 static unsigned int reports
= 0;
98 debugs(57, DBG_IMPORTANT
, "ERROR: Squid BUG: the internalized response lacks status-code");
99 packedStatus
= Http::scInternalServerError
;
100 packedReason
= Http::StatusCodeString(packedStatus
); // ignore custom reason_ (if any)
103 /* local constants */
104 /* AYJ: see bug 2469 - RFC2616 confirms stating 'SP characters' plural! */
105 static const char *Http1StatusLineFormat
= "HTTP/%d.%d %3d %s\r\n";
106 static const char *IcyStatusLineFormat
= "ICY %3d %s\r\n";
108 /* handle ICY protocol status line specially. Pass on the bad format. */
109 if (version
.protocol
== AnyP::PROTO_ICY
) {
110 debugs(57, 9, "packing sline " << this << " using " << p
<< ":");
111 debugs(57, 9, "FORMAT=" << IcyStatusLineFormat
);
112 debugs(57, 9, "ICY " << packedStatus
<< " " << packedReason
);
113 p
->appendf(IcyStatusLineFormat
, packedStatus
, packedReason
);
117 debugs(57, 9, "packing sline " << this << " using " << p
<< ":");
118 debugs(57, 9, "FORMAT=" << Http1StatusLineFormat
);
119 debugs(57, 9, "HTTP/" << version
.major
<< "." << version
.minor
<< " " << packedStatus
<< " " << packedReason
);
120 p
->appendf(Http1StatusLineFormat
, version
.major
, version
.minor
, packedStatus
, packedReason
);
124 Http::StatusLine::parse(const String
&protoPrefix
, const char *start
, const char *end
)
126 status_
= Http::scInvalidHeader
; /* Squid header parsing error */
128 // XXX: Http::Message::parse() has a similar check but is using
129 // casesensitive comparison (which is required by HTTP errata?)
131 if (protoPrefix
.cmp("ICY", 3) == 0) {
132 debugs(57, 3, "Invalid HTTP identifier. Detected ICY protocol instead.");
133 version
= AnyP::ProtocolVersion(AnyP::PROTO_ICY
, 1, 0);
134 start
+= protoPrefix
.size();
135 } else if (protoPrefix
.caseCmp(start
, protoPrefix
.size()) == 0) {
137 start
+= protoPrefix
.size();
139 if (!xisdigit(*start
))
142 // XXX: HTTPbis have defined this to be single-digit version numbers. no need to sscanf()
143 // XXX: furthermore, only HTTP/1 will be using ASCII format digits
145 if (sscanf(start
, "%d.%d", &version
.major
, &version
.minor
) != 2) {
146 debugs(57, 7, "Invalid HTTP identifier.");
152 if (!(start
= strchr(start
, ' ')))
155 ++start
; // skip SP between HTTP-version and status-code
157 assert(start
<= end
);
158 const auto stdStatusAreaLength
= 4; // status-code length plus SP
159 const auto unparsedLength
= end
- start
;
160 const auto statusAreaLength
= std::min
<size_t>(stdStatusAreaLength
, unparsedLength
);
162 static SBuf statusBuf
;
163 statusBuf
.assign(start
, statusAreaLength
);
164 Parser::Tokenizer
tok(statusBuf
);
166 One::ResponseParser::ParseResponseStatus(tok
, status_
);
167 } catch (const Parser::InsufficientInput
&) {
168 debugs(57, 7, "need more; have " << unparsedLength
);
171 debugs(57, 3, "cannot parse status-code area: " << CurrentException
);
175 // XXX check if the given 'reason' is the default status string, if not save to reason_
177 /* we ignore 'reason-phrase' */
178 /* Should assert start < end ? */
179 return true; /* success */