~ubuntu-branches/ubuntu/utopic/squid3/utopic-proposed

« back to all changes in this revision

Viewing changes to src/HttpRequest.cc

  • Committer: Package Import Robot
  • Author(s): Yolanda Robla
  • Date: 2013-07-10 17:12:42 UTC
  • mfrom: (21.2.18 sid)
  • Revision ID: package-import@ubuntu.com-20130710171242-2i9v941ikbpnjyqk
Tags: 3.3.4-1ubuntu1
* Merge from Debian unstable (LP: #1199883).  Remaining changes:
  + debian/control:
    - Update maintainer.
    - Suggests apparmor (>= 2.3)
    - Depends on ssl-cert ((>= 1.0-11ubuntu1), autopkgtests
  + debian/squid3.upstart
    - Move ulimit command to script section so that it applies
      to the started squid daemon. Thanks to Timur Irmatov (LP: 986159)
    - Work around squid not handling SIGHUP by adding respawn to
      upstart job. (LP: 978356)
  + debian/NEWS.Debian: Rename NEWS.debian, add note regarding squid3
    transition in 12.04 (LP: 924739)
  + debian/rules
    - Re-enable all hardening options lost in the squid->squid3
      transition (LP: 986314)
  + squid3.resolvconf, debian/squid3.postinst, debian/squid3.postrm,
    debian/squid3.preinst, debian/squid3.prerm:
    - Convert init script to upstart
  + debian/patches/99-ubuntu-ssl-cert-snakeoil:
    - Use snakeoil certificates.
  + debian/logrotate
    - Use sar-reports rather than sarg-maint. (LP: 26616)
  + debian/patches/90-cf.data.ubuntu.dpatch:
    - Add an example refresh pattern for debs.
      (foundations-lucid-local-report spec)
  + Add disabled by default AppArmor profile (LP: 497790)
    - debian/squid3.upstart: load profile in pre-start stanza
    - add debian/usr.sbin.squid3 profile
    - debian/rules:
      + install debian/usr.sbin.squid3, etc/apparmor.d/force-complain and
        etc/apparmor.d/disable into $(INSTALLDIR)
      + use dh_apparmor
    - debian/squid3.install: install etc/apparmor.d/disable, force-complain
      and usr.sbin.squid3
    - debian/squid3.preinst: disable profile on clean install or upgrades
      from earlier than when we shipped the profile
  + debian/tests:
    - Add autopkgtests.

* Dropped:
  - debian/patches: dropped patches, superseded by new release:
    + 98-CVE-2012-5643.patch
    + 99-lp1117517_r12473.patch
  - debian/rules: fix FTBFS, removed --with-cppunit-basedir flag,
    included in Debian.
  - debian/control: Dropped transitional packages from squid, no
    longer required.

* Refreshed patches:
  - 01-cf.data.debian.patch
  - 02-makefile-defaults.patch
  - 15-cachemgr-default-config.patch

* debian/tests/test-squid.py: fixed case problem with ftp test

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
1
/*
3
 
 * $Id$
4
 
 *
5
2
 * DEBUG: section 73    HTTP Request
6
3
 * AUTHOR: Duane Wessels
7
4
 *
35
32
 */
36
33
 
37
34
#include "squid.h"
 
35
#include "AccessLogEntry.h"
 
36
#include "acl/AclSizeLimit.h"
 
37
#include "acl/FilledChecklist.h"
 
38
#include "client_side.h"
 
39
#include "DnsLookupDetails.h"
 
40
#include "err_detail_type.h"
 
41
#include "globals.h"
 
42
#include "gopher.h"
 
43
#include "http.h"
 
44
#include "HttpHdrCc.h"
 
45
#include "HttpHeaderRange.h"
38
46
#include "HttpRequest.h"
39
 
#include "auth/UserRequest.h"
40
 
#include "HttpHeaderRange.h"
 
47
#include "log/Config.h"
41
48
#include "MemBuf.h"
 
49
#include "SquidConfig.h"
42
50
#include "Store.h"
 
51
#include "URL.h"
 
52
 
 
53
#if USE_AUTH
 
54
#include "auth/UserRequest.h"
 
55
#endif
43
56
#if ICAP_CLIENT
44
57
#include "adaptation/icap/icap_log.h"
45
58
#endif
49
62
    init();
50
63
}
51
64
 
52
 
HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, protocol_t aProtocol, const char *aUrlpath) : HttpMsg(hoRequest)
 
65
HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath) : HttpMsg(hoRequest)
53
66
{
54
67
    static unsigned int id = 1;
55
68
    debugs(93,7, HERE << "constructed, this=" << this << " id=" << ++id);
64
77
}
65
78
 
66
79
void
67
 
HttpRequest::initHTTP(const HttpRequestMethod& aMethod, protocol_t aProtocol, const char *aUrlpath)
 
80
HttpRequest::initHTTP(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath)
68
81
{
69
82
    method = aMethod;
70
83
    protocol = aProtocol;
75
88
HttpRequest::init()
76
89
{
77
90
    method = METHOD_NONE;
78
 
    protocol = PROTO_NONE;
 
91
    protocol = AnyP::PROTO_NONE;
79
92
    urlpath = NULL;
80
93
    login[0] = '\0';
81
94
    host[0] = '\0';
82
95
    host_is_numeric = -1;
 
96
#if USE_AUTH
83
97
    auth_user_request = NULL;
84
 
    pinned_connection = NULL;
 
98
#endif
85
99
    port = 0;
86
100
    canonical = NULL;
87
101
    memset(&flags, '\0', sizeof(flags));
95
109
    // hier
96
110
    dnsWait = -1;
97
111
    errType = ERR_NONE;
 
112
    errDetail = ERR_DETAIL_NONE;
98
113
    peer_login = NULL;          // not allocated/deallocated by this class
99
114
    peer_domain = NULL;         // not allocated/deallocated by this class
100
115
    vary_headers = NULL;
101
116
    myportname = null_string;
102
117
    tag = null_string;
 
118
#if USE_AUTH
103
119
    extacl_user = null_string;
104
120
    extacl_passwd = null_string;
 
121
#endif
105
122
    extacl_log = null_string;
106
123
    extacl_message = null_string;
107
124
    pstate = psReadyToParseStartLine;
114
131
#if ICAP_CLIENT
115
132
    icapHistory_ = NULL;
116
133
#endif
 
134
    rangeOffsetLimit = -2; //a value of -2 means not checked yet
117
135
}
118
136
 
119
137
void
122
140
    // we used to assert that the pipe is NULL, but now the request only
123
141
    // points to a pipe that is owned and initiated by another object.
124
142
    body_pipe = NULL;
125
 
 
126
 
    AUTHUSERREQUESTUNLOCK(auth_user_request, "request");
127
 
 
 
143
#if USE_AUTH
 
144
    auth_user_request = NULL;
 
145
#endif
128
146
    safe_free(canonical);
129
147
 
130
148
    safe_free(vary_headers);
134
152
    header.clean();
135
153
 
136
154
    if (cache_control) {
137
 
        httpHdrCcDestroy(cache_control);
 
155
        delete cache_control;
138
156
        cache_control = NULL;
139
157
    }
140
158
 
143
161
        range = NULL;
144
162
    }
145
163
 
146
 
    if (pinned_connection)
147
 
        cbdataReferenceDone(pinned_connection);
148
 
 
149
164
    myportname.clean();
150
165
 
151
166
    tag.clean();
152
 
 
 
167
#if USE_AUTH
153
168
    extacl_user.clean();
154
 
 
155
169
    extacl_passwd.clean();
156
 
 
 
170
#endif
157
171
    extacl_log.clean();
158
172
 
159
173
    extacl_message.clean();
208
222
 
209
223
    copy->myportname = myportname;
210
224
    copy->tag = tag;
 
225
#if USE_AUTH
211
226
    copy->extacl_user = extacl_user;
212
227
    copy->extacl_passwd = extacl_passwd;
 
228
#endif
213
229
    copy->extacl_log = extacl_log;
214
230
    copy->extacl_message = extacl_message;
215
231
 
218
234
    return copy;
219
235
}
220
236
 
 
237
bool
 
238
HttpRequest::inheritProperties(const HttpMsg *aMsg)
 
239
{
 
240
    const HttpRequest* aReq = dynamic_cast<const HttpRequest*>(aMsg);
 
241
    if (!aReq)
 
242
        return false;
 
243
 
 
244
    client_addr = aReq->client_addr;
 
245
#if FOLLOW_X_FORWARDED_FOR
 
246
    indirect_client_addr = aReq->indirect_client_addr;
 
247
#endif
 
248
    my_addr = aReq->my_addr;
 
249
 
 
250
    dnsWait = aReq->dnsWait;
 
251
 
 
252
#if USE_ADAPTATION
 
253
    adaptHistory_ = aReq->adaptHistory();
 
254
#endif
 
255
#if ICAP_CLIENT
 
256
    icapHistory_ = aReq->icapHistory();
 
257
#endif
 
258
 
 
259
    // This may be too conservative for the 204 No Content case
 
260
    // may eventually need cloneNullAdaptationImmune() for that.
 
261
    flags = aReq->flags.cloneAdaptationImmune();
 
262
 
 
263
    errType = aReq->errType;
 
264
    errDetail = aReq->errDetail;
 
265
#if USE_AUTH
 
266
    auth_user_request = aReq->auth_user_request;
 
267
#endif
 
268
 
 
269
    // main property is which connection the request was received on (if any)
 
270
    clientConnectionManager = aReq->clientConnectionManager;
 
271
 
 
272
    return true;
 
273
}
 
274
 
221
275
/**
222
276
 * Checks the first line of an HTTP request is valid
223
277
 * currently just checks the request method is present.
265
319
        end = ver - 1;
266
320
 
267
321
        while (xisspace(*end)) // find prev non-space
268
 
            end--;
 
322
            --end;
269
323
 
270
 
        end++;                 // back to space
 
324
        ++end;                 // back to space
271
325
 
272
326
        if (2 != sscanf(ver + 5, "%d.%d", &http_ver.major, &http_ver.minor)) {
273
 
            debugs(73, 1, "parseRequestLine: Invalid HTTP identifier.");
 
327
            debugs(73, DBG_IMPORTANT, "parseRequestLine: Invalid HTTP identifier.");
274
328
            return false;
275
329
        }
276
330
    } else {
367
421
    range = header.getRange();
368
422
}
369
423
 
370
 
/* request_flags */
371
 
bool
372
 
request_flags::resetTCP() const
373
 
{
374
 
    return reset_tcp != 0;
375
 
}
376
 
 
377
 
void
378
 
request_flags::setResetTCP()
379
 
{
380
 
    debugs(73, 9, "request_flags::setResetTCP");
381
 
    reset_tcp = 1;
382
 
}
383
 
 
384
 
void
385
 
request_flags::clearResetTCP()
386
 
{
387
 
    debugs(73, 9, "request_flags::clearResetTCP");
388
 
    reset_tcp = 0;
389
 
}
390
 
 
391
424
#if ICAP_CLIENT
392
425
Adaptation::Icap::History::Pointer
393
426
HttpRequest::icapHistory() const
394
427
{
395
428
    if (!icapHistory_) {
396
 
        if ((LogfileStatus == LOG_ENABLE && alLogformatHasIcapToken) ||
397
 
                IcapLogfileStatus == LOG_ENABLE) {
 
429
        if (Log::TheConfig.hasIcapToken || IcapLogfileStatus == LOG_ENABLE) {
398
430
            icapHistory_ = new Adaptation::Icap::History();
399
431
            debugs(93,4, HERE << "made " << icapHistory_ << " for " << this);
400
432
        }
419
451
Adaptation::History::Pointer
420
452
HttpRequest::adaptLogHistory() const
421
453
{
422
 
    const bool loggingNeedsHistory = (LogfileStatus == LOG_ENABLE) &&
423
 
                                     alLogformatHasAdaptToken; // TODO: make global to remove this method?
424
 
    return HttpRequest::adaptHistory(loggingNeedsHistory);
 
454
    return HttpRequest::adaptHistory(Log::TheConfig.hasAdaptToken);
 
455
}
 
456
 
 
457
void
 
458
HttpRequest::adaptHistoryImport(const HttpRequest &them)
 
459
{
 
460
    if (!adaptHistory_) {
 
461
        adaptHistory_ = them.adaptHistory_; // may be nil
 
462
    } else {
 
463
        // check that histories did not diverge
 
464
        Must(!them.adaptHistory_ || them.adaptHistory_ == adaptHistory_);
 
465
    }
425
466
}
426
467
 
427
468
#endif
432
473
    return (range && range->specs.count > 1);
433
474
}
434
475
 
435
 
void
436
 
request_flags::destinationIPLookupCompleted()
437
 
{
438
 
    destinationIPLookedUp_ = true;
439
 
}
440
 
 
441
 
bool
442
 
request_flags::destinationIPLookedUp() const
443
 
{
444
 
    return destinationIPLookedUp_;
445
 
}
446
 
 
447
 
request_flags
448
 
request_flags::cloneAdaptationImmune() const
449
 
{
450
 
    // At the time of writing, all flags where either safe to copy after
451
 
    // adaptation or were not set at the time of the adaptation. If there
452
 
    // are flags that are different, they should be cleared in the clone.
453
 
    return *this;
454
 
}
455
 
 
456
476
bool
457
477
HttpRequest::bodyNibbled() const
458
478
{
459
479
    return body_pipe != NULL && body_pipe->consumedSize() > 0;
460
480
}
461
481
 
 
482
void
 
483
HttpRequest::detailError(err_type aType, int aDetail)
 
484
{
 
485
    if (errType || errDetail)
 
486
        debugs(11, 5, HERE << "old error details: " << errType << '/' << errDetail);
 
487
    debugs(11, 5, HERE << "current error details: " << aType << '/' << aDetail);
 
488
    // checking type and detail separately may cause inconsistency, but
 
489
    // may result in more details available if they only become available later
 
490
    if (!errType)
 
491
        errType = aType;
 
492
    if (!errDetail)
 
493
        errDetail = aDetail;
 
494
}
 
495
 
 
496
void
 
497
HttpRequest::clearError()
 
498
{
 
499
    debugs(11, 7, HERE << "old error details: " << errType << '/' << errDetail);
 
500
    errType = ERR_NONE;
 
501
    errDetail = ERR_DETAIL_NONE;
 
502
}
 
503
 
462
504
const char *HttpRequest::packableURI(bool full_uri) const
463
505
{
464
506
    if (full_uri)
536
578
bool
537
579
HttpRequest::cacheable() const
538
580
{
539
 
    if (protocol == PROTO_HTTP)
 
581
    // Intercepted request with Host: header which cannot be trusted.
 
582
    // Because it failed verification, or someone bypassed the security tests
 
583
    // we cannot cache the reponse for sharing between clients.
 
584
    // TODO: update cache to store for particular clients only (going to same Host: and destination IP)
 
585
    if (!flags.hostVerified && (flags.intercepted || flags.spoofClientIp))
 
586
        return false;
 
587
 
 
588
    if (protocol == AnyP::PROTO_HTTP)
540
589
        return httpCachable(method);
541
590
 
542
591
    /*
551
600
     * XXX POST may be cached sometimes.. ignored
552
601
     * for now
553
602
     */
554
 
    if (protocol == PROTO_GOPHER)
 
603
    if (protocol == AnyP::PROTO_GOPHER)
555
604
        return gopherCachable(this);
556
605
 
557
 
    if (protocol == PROTO_CACHEOBJ)
 
606
    if (protocol == AnyP::PROTO_CACHE_OBJECT)
558
607
        return false;
559
608
 
560
609
    return true;
568
617
           header.has(HDR_IF_NONE_MATCH);
569
618
}
570
619
 
571
 
bool HttpRequest::inheritProperties(const HttpMsg *aMsg)
572
 
{
573
 
    const HttpRequest* aReq = dynamic_cast<const HttpRequest*>(aMsg);
574
 
    if (!aReq)
575
 
        return false;
576
 
 
577
 
    client_addr = aReq->client_addr;
578
 
#if FOLLOW_X_FORWARDED_FOR
579
 
    indirect_client_addr = aReq->indirect_client_addr;
580
 
#endif
581
 
    my_addr = aReq->my_addr;
582
 
 
583
 
    dnsWait = aReq->dnsWait;
584
 
 
585
 
#if USE_ADAPTATION
586
 
    adaptHistory_ = aReq->adaptHistory();
587
 
#endif
588
 
#if ICAP_CLIENT
589
 
    icapHistory_ = aReq->icapHistory();
590
 
#endif
591
 
 
592
 
    // This may be too conservative for the 204 No Content case
593
 
    // may eventually need cloneNullAdaptationImmune() for that.
594
 
    flags = aReq->flags.cloneAdaptationImmune();
595
 
 
596
 
    if (aReq->auth_user_request) {
597
 
        auth_user_request = aReq->auth_user_request;
598
 
        AUTHUSERREQUESTLOCK(auth_user_request, "inheritProperties");
599
 
    }
600
 
 
601
 
    if (aReq->pinned_connection) {
602
 
        pinned_connection = cbdataReference(aReq->pinned_connection);
603
 
    }
604
 
    return true;
605
 
}
606
 
 
607
 
void HttpRequest::recordLookup(const DnsLookupDetails &dns)
 
620
void
 
621
HttpRequest::recordLookup(const DnsLookupDetails &dns)
608
622
{
609
623
    if (dns.wait >= 0) { // known delay
610
624
        if (dnsWait >= 0) // have recorded DNS wait before
613
627
            dnsWait = dns.wait;
614
628
    }
615
629
}
 
630
 
 
631
int64_t
 
632
HttpRequest::getRangeOffsetLimit()
 
633
{
 
634
    /* -2 is the starting value of rangeOffsetLimit.
 
635
     * If it is -2, that means we haven't checked it yet.
 
636
     *  Otherwise, return the current value */
 
637
    if (rangeOffsetLimit != -2)
 
638
        return rangeOffsetLimit;
 
639
 
 
640
    rangeOffsetLimit = 0; // default value for rangeOffsetLimit
 
641
 
 
642
    ACLFilledChecklist ch(NULL, this, NULL);
 
643
    ch.src_addr = client_addr;
 
644
    ch.my_addr =  my_addr;
 
645
 
 
646
    for (AclSizeLimit *l = Config.rangeOffsetLimit; l; l = l -> next) {
 
647
        /* if there is no ACL list or if the ACLs listed match use this limit value */
 
648
        if (!l->aclList || ch.fastCheck(l->aclList) == ACCESS_ALLOWED) {
 
649
            debugs(58, 4, HERE << "rangeOffsetLimit=" << rangeOffsetLimit);
 
650
            rangeOffsetLimit = l->size; // may be -1
 
651
            break;
 
652
        }
 
653
    }
 
654
 
 
655
    return rangeOffsetLimit;
 
656
}
 
657
 
 
658
bool
 
659
HttpRequest::canHandle1xx() const
 
660
{
 
661
    // old clients do not support 1xx unless they sent Expect: 100-continue
 
662
    // (we reject all other HDR_EXPECT values so just check for HDR_EXPECT)
 
663
    if (http_ver <= HttpVersion(1,0) && !header.has(HDR_EXPECT))
 
664
        return false;
 
665
 
 
666
    // others must support 1xx control messages
 
667
    return true;
 
668
}
 
669
 
 
670
ConnStateData *
 
671
HttpRequest::pinnedConnection()
 
672
{
 
673
    if (clientConnectionManager.valid() && clientConnectionManager->pinning.pinned)
 
674
        return clientConnectionManager.get();
 
675
    return NULL;
 
676
}