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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors