]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HttpRequest.cc
Add [] operator for offset-based access into String's.
[thirdparty/squid.git] / src / HttpRequest.cc
CommitLineData
99edd1c3 1
2/*
cc192b50 3 * $Id: HttpRequest.cc,v 1.78 2007/12/14 23:11:45 amosjeffries Exp $
99edd1c3 4 *
5 * DEBUG: section 73 HTTP Request
6 * AUTHOR: Duane Wessels
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
99edd1c3 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
99edd1c3 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
51ee7c82 34 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
99edd1c3 35 */
36
37#include "squid.h"
8596962e 38#include "HttpRequest.h"
f5691f9c 39#include "AuthUserRequest.h"
528b2c61 40#include "HttpHeaderRange.h"
0eb49b6d 41#include "MemBuf.h"
25b6a907 42#include "Store.h"
528b2c61 43
4a56ee8d 44HttpRequest::HttpRequest() : HttpMsg(hoRequest)
75faaa7a 45{
5cafad19 46 init();
47}
48
4a56ee8d 49HttpRequest::HttpRequest(method_t aMethod, protocol_t aProtocol, const char *aUrlpath) : HttpMsg(hoRequest)
5cafad19 50{
51 init();
0e8aad88 52 initHTTP(aMethod, aProtocol, aUrlpath);
5cafad19 53}
54
55HttpRequest::~HttpRequest()
56{
5cafad19 57 clean();
58}
59
60void
0e8aad88 61HttpRequest::initHTTP(method_t aMethod, protocol_t aProtocol, const char *aUrlpath)
5cafad19 62{
63 method = aMethod;
64 protocol = aProtocol;
65 urlpath = aUrlpath;
66}
67
68void
69HttpRequest::init()
70{
a3f28359 71 method = METHOD_NONE;
5cafad19 72 protocol = PROTO_NONE;
30abd221 73 urlpath = NULL;
a3f28359 74 login[0] = '\0';
75 host[0] = '\0';
76 auth_user_request = NULL;
77 port = 0;
78 canonical = NULL;
a3f28359 79 memset(&flags, '\0', sizeof(flags));
80 range = NULL;
81 ims = -1;
82 imslen = 0;
5cafad19 83 lastmod = -1;
84 max_forwards = -1;
cc192b50 85 client_addr.SetEmpty();
86 my_addr.SetEmpty();
5f8252d2 87 body_pipe = NULL;
a3f28359 88 // hier
89 errType = ERR_NONE;
5cafad19 90 peer_login = NULL; // not allocated/deallocated by this class
91 peer_domain = NULL; // not allocated/deallocated by this class
a3f28359 92 vary_headers = NULL;
5cafad19 93 tag = null_string;
94 extacl_user = null_string;
95 extacl_passwd = null_string;
96 extacl_log = null_string;
c99de607 97 pstate = psReadyToParseStartLine;
8596962e 98}
99
99edd1c3 100void
5cafad19 101HttpRequest::clean()
99edd1c3 102{
5f8252d2 103 // we used to assert that the pipe is NULL, but now the request only
104 // points to a pipe that is owned and initiated by another object.
105 body_pipe = NULL;
62e76326 106
4f0ef8e8 107 AUTHUSERREQUESTUNLOCK(auth_user_request, "request");
62e76326 108
8596962e 109 safe_free(canonical);
62e76326 110
8596962e 111 safe_free(vary_headers);
62e76326 112
30abd221 113 urlpath.clean();
62e76326 114
519e0948 115 header.clean();
62e76326 116
07947ad8 117 if (cache_control) {
8596962e 118 httpHdrCcDestroy(cache_control);
07947ad8 119 cache_control = NULL;
120 }
62e76326 121
5cafad19 122 if (range) {
8596962e 123 delete range;
5cafad19 124 range = NULL;
125 }
62e76326 126
30abd221 127 tag.clean();
abb929f0 128
30abd221 129 extacl_user.clean();
abb929f0 130
30abd221 131 extacl_passwd.clean();
abb929f0 132
30abd221 133 extacl_log.clean();
8596962e 134}
4a972fa2 135
5cafad19 136void
137HttpRequest::reset()
138{
139 clean();
140 init();
141}
142
c21ad0f5 143bool
144HttpRequest::sanityCheckStartLine(MemBuf *buf, http_status *error)
8596962e 145{
146 /*
147 * Just see if the request buffer starts with a known
148 * HTTP request method. NOTE this whole function is somewhat
149 * superfluous and could just go away.
150 */
151
985c86bc 152 if (METHOD_NONE == HttpRequestMethod(buf->content())) {
bf8fe701 153 debugs(73, 3, "HttpRequest::sanityCheckStartLine: did not find HTTP request method");
8596962e 154 return false;
155 }
156
157 return true;
158}
159
c21ad0f5 160bool
161HttpRequest::parseFirstLine(const char *start, const char *end)
8596962e 162{
863d85ee 163 const char *t = start + strcspn(start, w_space);
985c86bc 164 method = HttpRequestMethod(start, t);
863d85ee 165
166 if (METHOD_NONE == method)
167 return false;
168
169 start = t + strspn(t, w_space);
170
171 const char *ver = findTrailingHTTPVersion(start, end);
172
173 if (ver) {
174 end = ver - 1;
175
176 while (xisspace(*end)) // find prev non-space
177 end--;
178
179 end++; // back to space
180
181 if (2 != sscanf(ver + 5, "%d.%d", &http_ver.major, &http_ver.minor)) {
bf8fe701 182 debugs(73, 1, "parseRequestLine: Invalid HTTP identifier.");
863d85ee 183 return false;
184 }
185 } else {
186 http_ver.major = 0;
187 http_ver.minor = 9;
188 }
189
190 if (end < start) // missing URI
191 return false;
192
193 char save = *end;
194
195 * (char *) end = '\0'; // temp terminate URI, XXX dangerous?
196
197 HttpRequest *tmp = urlParse(method, (char *) start, this);
198
199 * (char *) end = save;
200
201 if (NULL == tmp)
202 return false;
203
204 return true;
99edd1c3 205}
206
99edd1c3 207int
666f514b 208HttpRequest::parseHeader(const char *parse_start, int len)
99edd1c3 209{
210 const char *blk_start, *blk_end;
62e76326 211
666f514b 212 if (!httpMsgIsolateHeaders(&parse_start, len, &blk_start, &blk_end))
62e76326 213 return 0;
214
a9925b40 215 int result = header.parse(blk_start, blk_end);
62e76326 216
528b2c61 217 if (result)
07947ad8 218 hdrCacheInit();
62e76326 219
528b2c61 220 return result;
99edd1c3 221}
222
a00a7c85 223/* swaps out request using httpRequestPack */
99edd1c3 224void
5cafad19 225HttpRequest::swapOut(StoreEntry * e)
99edd1c3 226{
a00a7c85 227 Packer p;
5cafad19 228 assert(e);
a00a7c85 229 packerToStoreInit(&p, e);
5cafad19 230 pack(&p);
a00a7c85 231 packerClean(&p);
232}
233
234/* packs request-line and headers, appends <crlf> terminator */
235void
5cafad19 236HttpRequest::pack(Packer * p)
a00a7c85 237{
5cafad19 238 assert(p);
a00a7c85 239 /* pack request-line */
240 packerPrintf(p, "%s %s HTTP/1.0\r\n",
30abd221 241 RequestMethodStr[method], urlpath.buf());
a00a7c85 242 /* headers */
a9925b40 243 header.packInto(p);
2246b732 244 /* trailer */
a00a7c85 245 packerAppend(p, "\r\n", 2);
2246b732 246}
247
5cafad19 248/*
249 * A wrapper for debugObj()
250 */
2246b732 251void
5cafad19 252httpRequestPack(void *obj, Packer *p)
2246b732 253{
5cafad19 254 HttpRequest *request = static_cast<HttpRequest*>(obj);
255 request->pack(p);
99edd1c3 256}
eeb423fb 257
2246b732 258/* returns the length of request line + headers + crlf */
259int
5cafad19 260HttpRequest::prefixLen()
2246b732 261{
5cafad19 262 return strlen(RequestMethodStr[method]) + 1 +
263 urlpath.size() + 1 +
62e76326 264 4 + 1 + 3 + 2 +
5cafad19 265 header.len + 2;
2246b732 266}
99edd1c3 267
6bccf575 268/*
269 * Returns true if HTTP allows us to pass this header on. Does not
270 * check anonymizer (aka header_access) configuration.
271 */
99edd1c3 272int
30abd221 273httpRequestHdrAllowed(const HttpHeaderEntry * e, String * strConn)
99edd1c3 274{
275 assert(e);
97474590 276 /* check connection header */
62e76326 277
30abd221 278 if (strConn && strListIsMember(strConn, e->name.buf(), ','))
62e76326 279 return 0;
280
99edd1c3 281 return 1;
282}
e429f975 283
190154cf 284/* sync this routine when you update HttpRequest struct */
8596962e 285void
07947ad8 286HttpRequest::hdrCacheInit()
528b2c61 287{
07947ad8 288 HttpMsg::hdrCacheInit();
62e76326 289
a9925b40 290 range = header.getRange();
528b2c61 291}
292
e429f975 293/* request_flags */
294bool
295request_flags::resetTCP() const
296{
297 return reset_tcp != 0;
298}
299
300void
301request_flags::setResetTCP()
302{
bf8fe701 303 debugs(73, 9, "request_flags::setResetTCP");
e429f975 304 reset_tcp = 1;
305}
306
307void
308request_flags::clearResetTCP()
309{
bf8fe701 310 debugs(73, 9, "request_flags::clearResetTCP");
e429f975 311 reset_tcp = 0;
312}
528b2c61 313
314bool
190154cf 315HttpRequest::multipartRangeRequest() const
528b2c61 316{
317 return (range && range->specs.count > 1);
318}
8000a965 319
320void
321request_flags::destinationIPLookupCompleted()
322{
323 destinationIPLookedUp_ = true;
324}
325
326bool
327request_flags::destinationIPLookedUp() const
328{
329 return destinationIPLookedUp_;
330}
8596962e 331
5f8252d2 332request_flags
333request_flags::cloneAdaptationImmune() const
334{
335 // At the time of writing, all flags where either safe to copy after
336 // adaptation or were not set at the time of the adaptation. If there
337 // are flags that are different, they should be cleared in the clone.
338 return *this;
339}
340
58217e94 341bool
342HttpRequest::bodyNibbled() const {
343 return body_pipe != NULL && body_pipe->consumedSize() > 0;
344}
5f8252d2 345
8596962e 346const char *HttpRequest::packableURI(bool full_uri) const
347{
348 if (full_uri)
349 return urlCanonical((HttpRequest*)this);
350
351 if (urlpath.size())
30abd221 352 return urlpath.buf();
8596962e 353
354 return "/";
355}
356
357void HttpRequest::packFirstLineInto(Packer * p, bool full_uri) const
358{
359 // form HTTP request-line
360 packerPrintf(p, "%s %s HTTP/%d.%d\r\n",
361 RequestMethodStr[method],
362 packableURI(full_uri),
363 http_ver.major, http_ver.minor);
364}
8ddea643 365
366/*
367 * Indicate whether or not we would usually expect an entity-body
368 * along with this request
369 */
370bool
47f6e231 371HttpRequest::expectingBody(method_t unused, int64_t& theSize) const
8ddea643 372{
373 bool expectBody = false;
374
375 /*
376 * GET and HEAD don't usually have bodies, but we should be prepared
377 * to accept one if the request_entities directive is set
378 */
379
380 if (method == METHOD_GET || method == METHOD_HEAD)
381 expectBody = Config.onoff.request_entities ? true : false;
382 else if (method == METHOD_PUT || method == METHOD_POST)
383 expectBody = true;
a9925b40 384 else if (header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ','))
8ddea643 385 expectBody = true;
386 else if (content_length >= 0)
387 expectBody = true;
388 else
389 expectBody = false;
390
391 if (expectBody) {
a9925b40 392 if (header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ','))
8ddea643 393 theSize = -1;
394 else if (content_length >= 0)
395 theSize = content_length;
396 else
397 theSize = -1;
398 }
399
400 return expectBody;
401}
c21ad0f5 402
403/*
404 * Create a Request from a URL and METHOD.
405 *
406 * If the METHOD is CONNECT, then a host:port pair is looked for instead of a URL.
407 * If the request cannot be created cleanly, NULL is returned
408 */
409HttpRequest *
410HttpRequest::CreateFromUrlAndMethod(char * url, method_t method)
411{
412 return urlParse(method, url, NULL);
413}
414
415/*
416 * Create a Request from a URL.
417 *
418 * If the request cannot be created cleanly, NULL is returned
419 */
420HttpRequest *
421HttpRequest::CreateFromUrl(char * url)
422{
423 return urlParse(METHOD_GET, url, NULL);
424}
610ee341 425
426/*
427 * Are responses to this request possible cacheable ?
428 * If false then no matter what the response must not be cached.
429 */
430bool
431HttpRequest::cacheable() const
432{
433 if (protocol == PROTO_HTTP)
434 return httpCachable(method);
435
610ee341 436 /*
437 * The below looks questionable: what non HTTP protocols use connect,
438 * trace, put and post? RC
439 */
440 if (method == METHOD_CONNECT)
441 return 0;
442
443 if (method == METHOD_TRACE)
444 return 0;
445
446 if (method == METHOD_PUT)
447 return 0;
448
449 if (method == METHOD_POST)
450 return 0;
451
452 /*
453 * XXX POST may be cached sometimes.. ignored
454 * for now
455 */
456 if (protocol == PROTO_GOPHER)
457 return gopherCachable(this);
458
459 if (protocol == PROTO_CACHEOBJ)
460 return 0;
461
462 return 1;
463}