Message.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 74 HTTP Message */
10
11#include "squid.h"
12#include "debug/Stream.h"
14#include "http/Message.h"
15#include "http/one/Parser.h"
16#include "HttpHdrCc.h"
17#include "HttpHeaderTools.h"
18#include "MemBuf.h"
19#include "mime_header.h"
20#include "SquidConfig.h"
21
23 http_ver(Http::ProtocolVersion()),
24 header(owner)
25{}
26
28{
29 assert(!body_pipe);
30}
31
32void
34{
35 // get rid of the old CC, if any
36 if (cache_control) {
37 delete cache_control;
38 cache_control = nullptr;
39 if (!otherCc)
40 header.delById(Http::HdrType::CACHE_CONTROL);
41 // else it will be deleted inside putCc() below
42 }
43
44 // add new CC, if any
45 if (otherCc) {
46 cache_control = new HttpHdrCc(*otherCc);
47 header.putCc(cache_control);
48 }
49}
50
51/* find first CRLF */
52static int
53httpMsgIsolateStart(const char **parse_start, const char **blk_start, const char **blk_end)
54{
55 int slen = strcspn(*parse_start, "\r\n");
56
57 if (!(*parse_start)[slen]) /* no CRLF found */
58 return 0;
59
60 *blk_start = *parse_start;
61
62 *blk_end = *blk_start + slen;
63
64 while (**blk_end == '\r') /* CR */
65 ++(*blk_end);
66
67 if (**blk_end == '\n') /* LF */
68 ++(*blk_end);
69
70 *parse_start = *blk_end;
71
72 return 1;
73}
74
75// negative return is the negated Http::StatusCode error code
76// zero return means need more data
77// positive return is the size of parsed headers
78bool
79Http::Message::parse(const char *buf, const size_t sz, bool eof, Http::StatusCode *error)
80{
83
84 // find the end of headers
85 const size_t hdr_len = headersEnd(buf, sz);
86
87 if (hdr_len > Config.maxReplyHeaderSize || (hdr_len == 0 && sz > Config.maxReplyHeaderSize)) {
88 debugs(58, 3, "input too large: " << hdr_len << " or " << sz << " > " << Config.maxReplyHeaderSize);
90 return false;
91 }
92
93 // sanity check the start line to see if this is in fact an HTTP message
94 if (!sanityCheckStartLine(buf, hdr_len, error)) {
95 // NP: sanityCheck sets *error and sends debug warnings on syntax errors.
96 // if we have seen the connection close, this is an error too
97 if (eof && *error == Http::scNone)
99
100 return false;
101 }
102
103 assert(hdr_len > 0); // sanityCheckStartLine() rejects buffers that cannot be parsed
104
105 const int res = httpMsgParseStep(buf, sz, eof);
106
107 if (res < 0) { // error
108 debugs(58, 3, "cannot parse isolated headers in '" << buf << "'");
110 return false;
111 }
112
113 if (res == 0) {
114 debugs(58, 2, "strange, need more data near '" << buf << "'");
116 return false; // but this should not happen due to headersEnd() above
117 }
118
119 assert(res > 0);
120 debugs(58, 9, "success (" << hdr_len << " bytes) near '" << buf << "'");
121
122 if (hdr_sz != (int)hdr_len) {
123 debugs(58, DBG_IMPORTANT, "ERROR: internal Http::Message::parse vs. headersEnd failure: " <<
124 hdr_sz << " != " << hdr_len);
125 hdr_sz = (int)hdr_len; // because old http.cc code used hdr_len
126 }
127
128 return true;
129}
130
139bool
140Http::Message::parseCharBuf(const char *buf, ssize_t end)
141{
142 MemBuf mb;
143 int success;
144 /* reset current state, because we are not used in incremental fashion */
145 reset();
146 mb.init();
147 mb.append(buf, end);
148 mb.terminate();
149 success = httpMsgParseStep(mb.buf, mb.size, 0);
150 mb.clean();
151 return success == 1;
152}
153
161int
162Http::Message::httpMsgParseStep(const char *buf, int len, int atEnd)
163{
164 const char *parse_start = buf;
165 int parse_len = len;
166 const char *blk_start, *blk_end;
167 const char **parse_end_ptr = &blk_end;
168 assert(parse_start);
170
171 *parse_end_ptr = parse_start;
172
174 if (!httpMsgIsolateStart(&parse_start, &blk_start, &blk_end)) {
175 return 0;
176 }
177
178 if (!parseFirstLine(blk_start, blk_end)) {
179 return httpMsgParseError();
180 }
181
182 *parse_end_ptr = parse_start;
183
184 hdr_sz = *parse_end_ptr - buf;
185 parse_len = parse_len - hdr_sz;
186
188 }
189
190 /*
191 * XXX This code uses parse_start; but if we're incrementally parsing then
192 * this code might not actually be given parse_start at the right spot (just
193 * after headers.) Grr.
194 */
196 size_t hsize = 0;
198 configureContentLengthInterpreter(interpreter);
199 const int parsed = header.parse(parse_start, parse_len, atEnd, hsize, interpreter);
200 if (parsed <= 0) {
201 return !parsed ? 0 : httpMsgParseError();
202 }
203 hdr_sz += hsize;
204 hdrCacheInit();
206 }
207
208 return 1;
209}
210
211bool
213{
214 // HTTP/1 message contains "zero or more header fields"
215 // zero does not need parsing
216 // XXX: c_str() reallocates. performance regression.
217 configureContentLengthInterpreter(clen);
218 if (hp.headerBlockSize() && !header.parse(hp.mimeHeader().c_str(), hp.headerBlockSize(), clen)) {
219 pstate = Http::Message::psError;
220 return false;
221 }
222
223 // XXX: we are just parsing HTTP headers, not the whole message prefix here
224 hdr_sz = hp.messageHeaderSize();
226 hdrCacheInit();
227 return true;
228}
229
230/* handy: resets and returns -1 */
231int
233{
234 reset();
235 return -1;
236}
237
238void
240{
241 header.delById(Http::HdrType::CONTENT_LENGTH); // if any
242 header.putInt64(Http::HdrType::CONTENT_LENGTH, clen);
243 content_length = clen;
244}
245
246bool
248{
249 if (http_ver > Http::ProtocolVersion(1,0)) {
250 /*
251 * for modern versions of HTTP: persistent unless there is
252 * a "Connection: close" header.
253 */
254 static SBuf close("close", 5);
255 return !httpHeaderHasConnDir(&header, close);
256 } else {
257 /* for old versions of HTTP: persistent if has "keep-alive" */
258 static SBuf keepAlive("keep-alive", 10);
259 return httpHeaderHasConnDir(&header, keepAlive);
260 }
261}
262
263void
264Http::Message::packInto(Packable *p, bool full_uri) const
265{
266 packFirstLineInto(p, full_uri);
267 header.packInto(p);
268 p->append("\r\n", 2);
269}
270
271void
273{
274 content_length = header.getInt64(Http::HdrType::CONTENT_LENGTH);
275 assert(nullptr == cache_control);
276 cache_control = header.getCc();
277}
278
280void
282{
283 packFirstLineInto(&mb, true);
284}
285
bool httpHeaderHasConnDir(const HttpHeader *hdr, const SBuf &directive)
http_hdr_owner_type
Definition: HttpHeader.h:31
class SquidConfig Config
Definition: SquidConfig.cc:12
void error(char *format,...)
#define assert(EX)
Definition: assert.h:19
virtual void hdrCacheInit()
Definition: Message.cc:272
void packInto(Packable *, bool full_uri) const
produce a message copy, except for a few connection-specific settings
Definition: Message.cc:264
void setContentLength(int64_t)
[re]sets Content-Length header and cached value
Definition: Message.cc:239
bool persistent() const
Definition: Message.cc:247
int httpMsgParseStep(const char *buf, int len, int atEnd)
Definition: Message.cc:162
Message(http_hdr_owner_type)
Definition: Message.cc:22
virtual int httpMsgParseError()
Definition: Message.cc:232
void firstLineBuf(MemBuf &)
useful for debugging
Definition: Message.cc:281
@ psReadyToParseStartLine
Definition: Message.h:87
@ psReadyToParseHeaders
Definition: Message.h:88
bool parseHeader(Http1::Parser &, Http::ContentLengthInterpreter &)
Definition: Message.cc:212
virtual ~Message()
Definition: Message.cc:27
bool parse(const char *buf, const size_t sz, bool eol, Http::StatusCode *error)
Definition: Message.cc:79
bool parseCharBuf(const char *buf, ssize_t end)
Definition: Message.cc:140
void putCc(const HttpHdrCc *otherCc)
copies Cache-Control header to this message
Definition: Message.cc:33
size_type headerBlockSize() const
Definition: Parser.h:73
SBuf mimeHeader() const
buffer containing HTTP mime headers, excluding message first-line.
Definition: Parser.h:81
size_type messageHeaderSize() const
Definition: Parser.h:78
Definition: MemBuf.h:24
void clean()
Definition: MemBuf.cc:110
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:209
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
mb_size_t size
Definition: MemBuf.h:135
char * buf
Definition: MemBuf.h:134
void terminate()
Definition: MemBuf.cc:241
virtual void append(const char *buf, int size)=0
Appends a c-string to existing packed data.
Definition: SBuf.h:94
const char * c_str()
Definition: SBuf.cc:516
size_t maxReplyHeaderSize
Definition: SquidConfig.h:135
#define DBG_IMPORTANT
Definition: Stream.h:41
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
static int httpMsgIsolateStart(const char **parse_start, const char **blk_start, const char **blk_end)
Definition: Message.cc:53
size_t headersEnd(const char *mime, size_t l, bool &containsObsFold)
Definition: mime_header.cc:17
AnyP::ProtocolVersion ProtocolVersion()
Protocol version to use in Http::Message structures wrapping FTP messages.
Definition: Elements.cc:24
Definition: forward.h:22
StatusCode
Definition: StatusCode.h:20
@ scHeaderTooLarge
Definition: StatusCode.h:87
@ scInvalidHeader
Definition: StatusCode.h:86
@ scNone
Definition: StatusCode.h:21
@ CONTENT_LENGTH
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
void const char int sz
Definition: stub_cbdata.cc:16
int unsigned int
Definition: stub_fd.cc:19

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors