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