]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HttpRequest.cc
Cleanup: zap CVS Id tags
[thirdparty/squid.git] / src / HttpRequest.cc
CommitLineData
99edd1c3 1
2/*
262a0e14 3 * $Id$
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.
9e008dda 24 *
99edd1c3 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.
9e008dda 29 *
99edd1c3 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
60745f24 49HttpRequest::HttpRequest(const HttpRequestMethod& 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
60745f24 61HttpRequest::initHTTP(const HttpRequestMethod& 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;
d67acb4e 77 pinned_connection = NULL;
a3f28359 78 port = 0;
79 canonical = NULL;
a3f28359 80 memset(&flags, '\0', sizeof(flags));
81 range = NULL;
82 ims = -1;
83 imslen = 0;
5cafad19 84 lastmod = -1;
85 max_forwards = -1;
cc192b50 86 client_addr.SetEmpty();
87 my_addr.SetEmpty();
5f8252d2 88 body_pipe = NULL;
a3f28359 89 // hier
90 errType = ERR_NONE;
5cafad19 91 peer_login = NULL; // not allocated/deallocated by this class
92 peer_domain = NULL; // not allocated/deallocated by this class
a3f28359 93 vary_headers = NULL;
5cafad19 94 tag = null_string;
95 extacl_user = null_string;
96 extacl_passwd = null_string;
97 extacl_log = null_string;
c99de607 98 pstate = psReadyToParseStartLine;
3d674977
AJ
99#if FOLLOW_X_FORWARDED_FOR
100 indirect_client_addr.SetEmpty();
101#endif /* FOLLOW_X_FORWARDED_FOR */
8596962e 102}
103
99edd1c3 104void
5cafad19 105HttpRequest::clean()
99edd1c3 106{
9e008dda 107 // we used to assert that the pipe is NULL, but now the request only
5f8252d2 108 // points to a pipe that is owned and initiated by another object.
9e008dda 109 body_pipe = NULL;
62e76326 110
4f0ef8e8 111 AUTHUSERREQUESTUNLOCK(auth_user_request, "request");
62e76326 112
8596962e 113 safe_free(canonical);
62e76326 114
8596962e 115 safe_free(vary_headers);
62e76326 116
30abd221 117 urlpath.clean();
62e76326 118
519e0948 119 header.clean();
62e76326 120
07947ad8 121 if (cache_control) {
8596962e 122 httpHdrCcDestroy(cache_control);
07947ad8 123 cache_control = NULL;
124 }
62e76326 125
5cafad19 126 if (range) {
8596962e 127 delete range;
5cafad19 128 range = NULL;
129 }
62e76326 130
9e008dda
AJ
131 if (pinned_connection)
132 cbdataReferenceDone(pinned_connection);
d67acb4e 133
30abd221 134 tag.clean();
abb929f0 135
30abd221 136 extacl_user.clean();
abb929f0 137
30abd221 138 extacl_passwd.clean();
abb929f0 139
30abd221 140 extacl_log.clean();
8596962e 141}
4a972fa2 142
5cafad19 143void
144HttpRequest::reset()
145{
146 clean();
147 init();
148}
149
fa0e6114
AR
150HttpRequest *
151HttpRequest::clone() const
152{
153 HttpRequest *copy = new HttpRequest(method, protocol, urlpath.buf());
154 // TODO: move common cloning clone to Msg::copyTo() or copy ctor
155 copy->header.append(&header);
156 copy->hdrCacheInit();
157 copy->hdr_sz = hdr_sz;
158 copy->http_ver = http_ver;
159 copy->pstate = pstate; // TODO: should we assert a specific state here?
160 copy->body_pipe = body_pipe;
161
162 strncpy(copy->login, login, sizeof(login)); // MAX_LOGIN_SZ
163 strncpy(copy->host, host, sizeof(host)); // SQUIDHOSTNAMELEN
164 copy->host_addr = host_addr;
165
166 if (auth_user_request) {
167 copy->auth_user_request = auth_user_request;
168 AUTHUSERREQUESTLOCK(copy->auth_user_request, "HttpRequest::clone");
9e008dda 169 }
fa0e6114
AR
170
171 copy->port = port;
172 // urlPath handled in ctor
9e008dda
AJ
173 copy->canonical = canonical ? xstrdup(canonical) : NULL;
174
fa0e6114
AR
175 // This may be too conservative for the 204 No Content case
176 // may eventually need cloneNullAdaptationImmune() for that.
177 copy->flags = flags.cloneAdaptationImmune();
178
9e008dda
AJ
179 copy->range = range ? new HttpHdrRange(*range) : NULL;
180 copy->ims = ims;
181 copy->imslen = imslen;
182 copy->max_forwards = max_forwards;
fa0e6114
AR
183 copy->client_addr = client_addr;
184 copy->my_addr = my_addr;
185 copy->hier = hier; // Is it safe to copy? Should we?
186
187 copy->errType = errType;
188
189 // XXX: what to do with copy->peer_login?
190
9e008dda 191 copy->lastmod = lastmod;
fa0e6114
AR
192 copy->vary_headers = vary_headers ? xstrdup(vary_headers) : NULL;
193 // XXX: what to do with copy->peer_domain?
194
195 copy->tag = tag;
196 copy->extacl_user = extacl_user;
197 copy->extacl_passwd = extacl_passwd;
198 copy->extacl_log = extacl_log;
199
200 return copy;
201}
202
c21ad0f5 203bool
204HttpRequest::sanityCheckStartLine(MemBuf *buf, http_status *error)
8596962e 205{
914b89a2 206 /**
8596962e 207 * Just see if the request buffer starts with a known
208 * HTTP request method. NOTE this whole function is somewhat
209 * superfluous and could just go away.
914b89a2 210 \todo AYJ: Check for safely removing this function. We now accept 'unknown' request methods in HTTP.
8596962e 211 */
212
914b89a2 213 if (HttpRequestMethod(buf->content(),NULL) == METHOD_NONE) {
bf8fe701 214 debugs(73, 3, "HttpRequest::sanityCheckStartLine: did not find HTTP request method");
8596962e 215 return false;
216 }
217
218 return true;
219}
220
c21ad0f5 221bool
222HttpRequest::parseFirstLine(const char *start, const char *end)
8596962e 223{
863d85ee 224 const char *t = start + strcspn(start, w_space);
985c86bc 225 method = HttpRequestMethod(start, t);
863d85ee 226
914b89a2 227 if (method == METHOD_NONE)
863d85ee 228 return false;
229
230 start = t + strspn(t, w_space);
231
232 const char *ver = findTrailingHTTPVersion(start, end);
233
234 if (ver) {
235 end = ver - 1;
236
237 while (xisspace(*end)) // find prev non-space
238 end--;
239
240 end++; // back to space
241
242 if (2 != sscanf(ver + 5, "%d.%d", &http_ver.major, &http_ver.minor)) {
bf8fe701 243 debugs(73, 1, "parseRequestLine: Invalid HTTP identifier.");
863d85ee 244 return false;
245 }
246 } else {
247 http_ver.major = 0;
248 http_ver.minor = 9;
249 }
250
251 if (end < start) // missing URI
252 return false;
253
254 char save = *end;
255
256 * (char *) end = '\0'; // temp terminate URI, XXX dangerous?
257
258 HttpRequest *tmp = urlParse(method, (char *) start, this);
259
260 * (char *) end = save;
261
262 if (NULL == tmp)
263 return false;
264
265 return true;
99edd1c3 266}
267
99edd1c3 268int
666f514b 269HttpRequest::parseHeader(const char *parse_start, int len)
99edd1c3 270{
271 const char *blk_start, *blk_end;
62e76326 272
666f514b 273 if (!httpMsgIsolateHeaders(&parse_start, len, &blk_start, &blk_end))
62e76326 274 return 0;
275
a9925b40 276 int result = header.parse(blk_start, blk_end);
62e76326 277
528b2c61 278 if (result)
07947ad8 279 hdrCacheInit();
62e76326 280
528b2c61 281 return result;
99edd1c3 282}
283
a00a7c85 284/* swaps out request using httpRequestPack */
99edd1c3 285void
5cafad19 286HttpRequest::swapOut(StoreEntry * e)
99edd1c3 287{
a00a7c85 288 Packer p;
5cafad19 289 assert(e);
a00a7c85 290 packerToStoreInit(&p, e);
5cafad19 291 pack(&p);
a00a7c85 292 packerClean(&p);
293}
294
295/* packs request-line and headers, appends <crlf> terminator */
296void
5cafad19 297HttpRequest::pack(Packer * p)
a00a7c85 298{
5cafad19 299 assert(p);
a00a7c85 300 /* pack request-line */
301 packerPrintf(p, "%s %s HTTP/1.0\r\n",
60745f24 302 RequestMethodStr(method), urlpath.buf());
a00a7c85 303 /* headers */
a9925b40 304 header.packInto(p);
2246b732 305 /* trailer */
a00a7c85 306 packerAppend(p, "\r\n", 2);
2246b732 307}
308
5cafad19 309/*
310 * A wrapper for debugObj()
311 */
2246b732 312void
5cafad19 313httpRequestPack(void *obj, Packer *p)
2246b732 314{
5cafad19 315 HttpRequest *request = static_cast<HttpRequest*>(obj);
316 request->pack(p);
99edd1c3 317}
eeb423fb 318
2246b732 319/* returns the length of request line + headers + crlf */
320int
5cafad19 321HttpRequest::prefixLen()
2246b732 322{
60745f24 323 return strlen(RequestMethodStr(method)) + 1 +
5cafad19 324 urlpath.size() + 1 +
62e76326 325 4 + 1 + 3 + 2 +
5cafad19 326 header.len + 2;
2246b732 327}
99edd1c3 328
06093389 329/**
6bccf575 330 * Returns true if HTTP allows us to pass this header on. Does not
331 * check anonymizer (aka header_access) configuration.
332 */
99edd1c3 333int
30abd221 334httpRequestHdrAllowed(const HttpHeaderEntry * e, String * strConn)
99edd1c3 335{
336 assert(e);
97474590 337 /* check connection header */
62e76326 338
30abd221 339 if (strConn && strListIsMember(strConn, e->name.buf(), ','))
62e76326 340 return 0;
341
99edd1c3 342 return 1;
343}
e429f975 344
190154cf 345/* sync this routine when you update HttpRequest struct */
8596962e 346void
07947ad8 347HttpRequest::hdrCacheInit()
528b2c61 348{
07947ad8 349 HttpMsg::hdrCacheInit();
62e76326 350
a9925b40 351 range = header.getRange();
528b2c61 352}
353
e429f975 354/* request_flags */
355bool
356request_flags::resetTCP() const
357{
358 return reset_tcp != 0;
359}
360
361void
362request_flags::setResetTCP()
363{
bf8fe701 364 debugs(73, 9, "request_flags::setResetTCP");
e429f975 365 reset_tcp = 1;
366}
367
368void
369request_flags::clearResetTCP()
370{
bf8fe701 371 debugs(73, 9, "request_flags::clearResetTCP");
e429f975 372 reset_tcp = 0;
373}
528b2c61 374
375bool
190154cf 376HttpRequest::multipartRangeRequest() const
528b2c61 377{
378 return (range && range->specs.count > 1);
379}
8000a965 380
381void
382request_flags::destinationIPLookupCompleted()
383{
384 destinationIPLookedUp_ = true;
385}
386
387bool
388request_flags::destinationIPLookedUp() const
389{
390 return destinationIPLookedUp_;
391}
8596962e 392
5f8252d2 393request_flags
394request_flags::cloneAdaptationImmune() const
395{
396 // At the time of writing, all flags where either safe to copy after
397 // adaptation or were not set at the time of the adaptation. If there
398 // are flags that are different, they should be cleared in the clone.
399 return *this;
400}
401
58217e94 402bool
9e008dda
AJ
403HttpRequest::bodyNibbled() const
404{
58217e94 405 return body_pipe != NULL && body_pipe->consumedSize() > 0;
406}
5f8252d2 407
8596962e 408const char *HttpRequest::packableURI(bool full_uri) const
409{
410 if (full_uri)
411 return urlCanonical((HttpRequest*)this);
412
413 if (urlpath.size())
30abd221 414 return urlpath.buf();
8596962e 415
416 return "/";
417}
418
419void HttpRequest::packFirstLineInto(Packer * p, bool full_uri) const
420{
421 // form HTTP request-line
422 packerPrintf(p, "%s %s HTTP/%d.%d\r\n",
60745f24 423 RequestMethodStr(method),
8596962e 424 packableURI(full_uri),
425 http_ver.major, http_ver.minor);
426}
8ddea643 427
428/*
429 * Indicate whether or not we would usually expect an entity-body
430 * along with this request
431 */
432bool
60745f24 433HttpRequest::expectingBody(const HttpRequestMethod& unused, int64_t& theSize) const
8ddea643 434{
435 bool expectBody = false;
436
437 /*
438 * GET and HEAD don't usually have bodies, but we should be prepared
439 * to accept one if the request_entities directive is set
440 */
441
442 if (method == METHOD_GET || method == METHOD_HEAD)
443 expectBody = Config.onoff.request_entities ? true : false;
444 else if (method == METHOD_PUT || method == METHOD_POST)
445 expectBody = true;
a9925b40 446 else if (header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ','))
8ddea643 447 expectBody = true;
448 else if (content_length >= 0)
449 expectBody = true;
450 else
451 expectBody = false;
452
453 if (expectBody) {
a9925b40 454 if (header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ','))
8ddea643 455 theSize = -1;
456 else if (content_length >= 0)
457 theSize = content_length;
458 else
459 theSize = -1;
460 }
461
462 return expectBody;
463}
c21ad0f5 464
465/*
466 * Create a Request from a URL and METHOD.
467 *
468 * If the METHOD is CONNECT, then a host:port pair is looked for instead of a URL.
469 * If the request cannot be created cleanly, NULL is returned
470 */
471HttpRequest *
60745f24 472HttpRequest::CreateFromUrlAndMethod(char * url, const HttpRequestMethod& method)
c21ad0f5 473{
474 return urlParse(method, url, NULL);
475}
476
477/*
478 * Create a Request from a URL.
479 *
480 * If the request cannot be created cleanly, NULL is returned
481 */
482HttpRequest *
483HttpRequest::CreateFromUrl(char * url)
484{
485 return urlParse(METHOD_GET, url, NULL);
486}
610ee341 487
488/*
489 * Are responses to this request possible cacheable ?
490 * If false then no matter what the response must not be cached.
491 */
492bool
493HttpRequest::cacheable() const
494{
495 if (protocol == PROTO_HTTP)
496 return httpCachable(method);
497
610ee341 498 /*
499 * The below looks questionable: what non HTTP protocols use connect,
500 * trace, put and post? RC
501 */
9e008dda 502
60745f24 503 if (!method.isCacheble())
9e008dda 504 return false;
610ee341 505
506 /*
507 * XXX POST may be cached sometimes.. ignored
508 * for now
509 */
510 if (protocol == PROTO_GOPHER)
511 return gopherCachable(this);
512
513 if (protocol == PROTO_CACHEOBJ)
60745f24 514 return false;
610ee341 515
60745f24 516 return true;
610ee341 517}
d67acb4e
AJ
518
519bool HttpRequest::inheritProperties(const HttpMsg *aMsg)
520{
521 const HttpRequest* aReq = dynamic_cast<const HttpRequest*>(aMsg);
9e008dda
AJ
522 if (!aReq)
523 return false;
524
d67acb4e
AJ
525 client_addr = aReq->client_addr;
526 my_addr = aReq->my_addr;
527
528 // This may be too conservative for the 204 No Content case
529 // may eventually need cloneNullAdaptationImmune() for that.
530 flags = aReq->flags.cloneAdaptationImmune();
531
532 if (aReq->auth_user_request) {
533 auth_user_request = aReq->auth_user_request;
9e008dda 534 AUTHUSERREQUESTLOCK(auth_user_request, "inheritProperties");
d67acb4e
AJ
535 }
536
9e008dda
AJ
537 if (aReq->pinned_connection) {
538 pinned_connection = cbdataReference(aReq->pinned_connection);
d67acb4e
AJ
539 }
540 return true;
541}