]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/http/StatusLine.cc
0db1db76118b1f827bd3135619c52de15fc740bc
2 * Copyright (C) 1996-2022 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::packInto(Packable
* p
) const
54 auto packedStatus
= status();
55 auto packedReason
= reason();
57 if (packedStatus
== Http::scNone
) {
58 static unsigned int reports
= 0;
60 debugs(57, DBG_IMPORTANT
, "ERROR: Squid BUG: the internalized response lacks status-code");
61 packedStatus
= Http::scInternalServerError
;
62 packedReason
= Http::StatusCodeString(packedStatus
); // ignore custom reason_ (if any)
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";
70 /* handle ICY protocol status line specially. Pass on the bad format. */
71 if (version
.protocol
== AnyP::PROTO_ICY
) {
72 debugs(57, 9, "packing sline " << this << " using " << p
<< ":");
73 debugs(57, 9, "FORMAT=" << IcyStatusLineFormat
);
74 debugs(57, 9, "ICY " << packedStatus
<< " " << packedReason
);
75 p
->appendf(IcyStatusLineFormat
, packedStatus
, packedReason
);
79 debugs(57, 9, "packing sline " << this << " using " << p
<< ":");
80 debugs(57, 9, "FORMAT=" << Http1StatusLineFormat
);
81 debugs(57, 9, "HTTP/" << version
.major
<< "." << version
.minor
<< " " << packedStatus
<< " " << packedReason
);
82 p
->appendf(Http1StatusLineFormat
, version
.major
, version
.minor
, packedStatus
, packedReason
);
86 Http::StatusLine::parse(const String
&protoPrefix
, const char *start
, const char *end
)
88 status_
= Http::scInvalidHeader
; /* Squid header parsing error */
90 // XXX: Http::Message::parse() has a similar check but is using
91 // casesensitive comparison (which is required by HTTP errata?)
93 if (protoPrefix
.cmp("ICY", 3) == 0) {
94 debugs(57, 3, "Invalid HTTP identifier. Detected ICY protocol instead.");
95 version
= AnyP::ProtocolVersion(AnyP::PROTO_ICY
, 1, 0);
96 start
+= protoPrefix
.size();
97 } else if (protoPrefix
.caseCmp(start
, protoPrefix
.size()) == 0) {
99 start
+= protoPrefix
.size();
101 if (!xisdigit(*start
))
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
107 if (sscanf(start
, "%d.%d", &version
.major
, &version
.minor
) != 2) {
108 debugs(57, 7, "Invalid HTTP identifier.");
114 if (!(start
= strchr(start
, ' ')))
117 ++start
; // skip SP between HTTP-version and status-code
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
);
124 static SBuf statusBuf
;
125 statusBuf
.assign(start
, statusAreaLength
);
126 Parser::Tokenizer
tok(statusBuf
);
128 One::ResponseParser::ParseResponseStatus(tok
, status_
);
129 } catch (const Parser::InsufficientInput
&) {
130 debugs(57, 7, "need more; have " << unparsedLength
);
133 debugs(57, 3, "cannot parse status-code area: " << CurrentException
);
137 // XXX check if the given 'reason' is the default status string, if not save to reason_
139 /* we ignore 'reason-phrase' */
140 /* Should assert start < end ? */
141 return true; /* success */