/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transport/http/_urllib2_wrappers.py

  • Committer: Aaron Bentley
  • Date: 2008-02-24 16:42:13 UTC
  • mfrom: (3234 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3235.
  • Revision ID: aaron@aaronbentley.com-20080224164213-eza1lzru5bwuwmmj
Merge with bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006,2007 Canonical Ltd
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
32
32
handle authentication schemes.
33
33
"""
34
34
 
35
 
# TODO: now that we have -Dhttp most of the needs should be covered in a more
36
 
# accessible way (i.e. no need to edit the source), if experience confirms
37
 
# that, delete all DEBUG uses -- vila20071130 (happy birthday).
38
35
DEBUG = 0
39
36
 
40
37
# FIXME: Oversimplifying, two kind of exceptions should be
78
75
    # Some responses have bodies in which we have no interest
79
76
    _body_ignored_responses = [301,302, 303, 307, 401, 403, 404]
80
77
 
 
78
    # in finish() below, we may have to discard several MB in the worst
 
79
    # case. To avoid buffering that much, we read and discard by chunks
 
80
    # instead. The underlying file is either a socket or a StringIO, so reading
 
81
    # 8k chunks should be fine.
 
82
    _discarded_buf_size = 8192
 
83
 
81
84
    def begin(self):
82
85
        """Begin to read the response from the server.
83
86
 
88
91
        """
89
92
        httplib.HTTPResponse.begin(self)
90
93
        if self.status in self._body_ignored_responses:
91
 
            if self.debuglevel > 0:
 
94
            if self.debuglevel >= 2:
92
95
                print "For status: [%s]," % self.status,
93
 
                print "will ready body, length: ",
94
 
                if  self.length is not None:
95
 
                    print "[%d]" % self.length
96
 
                else:
97
 
                    print "None"
 
96
                print "will ready body, length: %s" % self.length
98
97
            if not (self.length is None or self.will_close):
99
98
                # In some cases, we just can't read the body not
100
99
                # even try or we may encounter a 104, 'Connection
102
101
                # and the server closed the connection just after
103
102
                # having issued the response headers (even if the
104
103
                # headers indicate a Content-Type...)
105
 
                body = self.fp.read(self.length)
106
 
                if self.debuglevel > 3:
 
104
                body = self.read(self.length)
 
105
                if self.debuglevel >= 9:
107
106
                    # This one can be huge and is generally not interesting
108
107
                    print "Consumed body: [%s]" % body
109
108
            self.close()
120
119
            # below we keep the socket with the server opened.
121
120
            self.will_close = False
122
121
 
123
 
    # in finish() below, we may have to discard several MB in the worst
124
 
    # case. To avoid buffering that much, we read and discard by chunks
125
 
    # instead. The underlying file is either a socket or a StringIO, so reading
126
 
    # 8k chunks should be fine.
127
 
    _discarded_buf_size = 8192
128
 
 
129
122
    def finish(self):
130
123
        """Finish reading the body.
131
124
 
141
134
        if not self.isclosed():
142
135
            # Make sure nothing was left to be read on the socket
143
136
            pending = 0
144
 
            while self.length and self.length > self._discarded_buf_size:
145
 
                data = self.read(self._discarded_buf_size)
146
 
                pending += len(data)
147
 
            if self.length:
148
 
                data = self.read(self.length)
 
137
            data = True
 
138
            while data and self.length:
 
139
                # read() will update self.length
 
140
                data = self.read(min(self.length, self._discarded_buf_size))
149
141
                pending += len(data)
150
142
            if pending:
151
 
                trace.mutter(
152
 
                    "bogus http server didn't give body length,"
153
 
                    "%s bytes left on the socket",
154
 
                    pending)
 
143
                trace.mutter("%s bytes left on the HTTP socket", pending)
155
144
            self.close()
156
145
        return pending
157
146
 
161
150
    """A custom HTTP(S) Connection, which can reset itself on a bad response"""
162
151
 
163
152
    response_class = Response
164
 
    strict = 1 # We don't support HTTP/0.9
165
153
 
166
154
    # When we detect a server responding with the whole file to range requests,
167
155
    # we want to warn. But not below a given thresold.
183
171
        return self._response
184
172
 
185
173
    def cleanup_pipe(self):
186
 
        """Make the connection believe the response has been fully processed."""
 
174
        """Read the remaining bytes of the last response if any."""
187
175
        if self._response is not None:
188
176
            pending = self._response.finish()
189
177
            # Warn the user (once)
209
197
class HTTPConnection(AbstractHTTPConnection, httplib.HTTPConnection):
210
198
 
211
199
    # XXX: Needs refactoring at the caller level.
212
 
    def __init__(self, host, port=None, strict=None, proxied_host=None):
 
200
    def __init__(self, host, port=None, proxied_host=None):
213
201
        AbstractHTTPConnection.__init__(self)
214
 
        httplib.HTTPConnection.__init__(self, host, port, strict)
 
202
        # Use strict=True since we don't support HTTP/0.9
 
203
        httplib.HTTPConnection.__init__(self, host, port, strict=True)
215
204
        self.proxied_host = proxied_host
216
205
 
217
206
    def connect(self):
220
209
        httplib.HTTPConnection.connect(self)
221
210
 
222
211
 
 
212
# FIXME: Should test for ssl availability
223
213
class HTTPSConnection(AbstractHTTPConnection, httplib.HTTPSConnection):
224
214
 
225
215
    def __init__(self, host, port=None, key_file=None, cert_file=None,
226
 
                 strict=None, proxied_host=None):
 
216
                 proxied_host=None):
227
217
        AbstractHTTPConnection.__init__(self)
 
218
        # Use strict=True since we don't support HTTP/0.9
228
219
        httplib.HTTPSConnection.__init__(self, host, port,
229
 
                                         key_file, cert_file, strict)
 
220
                                         key_file, cert_file, strict=True)
230
221
        self.proxied_host = proxied_host
231
222
 
232
223
    def connect(self):
440
431
            raise exc_type, exc_val, exc_tb
441
432
        else:
442
433
            if first_try:
443
 
                if self._debuglevel > 0:
 
434
                if self._debuglevel >= 2:
444
435
                    print 'Received exception: [%r]' % exc_val
445
436
                    print '  On connection: [%r]' % request.connection
446
437
                    method = request.get_method()
449
440
                request.connection.close()
450
441
                response = self.do_open(http_class, request, False)
451
442
            else:
452
 
                if self._debuglevel > 0:
 
443
                if self._debuglevel >= 2:
453
444
                    print 'Received second exception: [%r]' % exc_val
454
445
                    print '  On connection: [%r]' % request.connection
455
446
                if exc_type in (httplib.BadStatusLine, httplib.UnknownProtocol):
476
467
                                                       request.get_selector()),
477
468
                        orig_error=exc_val)
478
469
 
479
 
                if self._debuglevel > 0:
 
470
                if self._debuglevel >= 2:
480
471
                    print 'On connection: [%r]' % request.connection
481
472
                    method = request.get_method()
482
473
                    url = request.get_full_url()
511
502
                trace.mutter('> %s %s' % (method, url))
512
503
                hdrs = ['%s: %s' % (k, v) for k,v in headers.items()]
513
504
                trace.mutter('> ' + '\n> '.join(hdrs) + '\n')
514
 
            if self._debuglevel > 0:
515
 
                print 'Request sent: [%r]' % request
 
505
            if self._debuglevel >= 1:
 
506
                print 'Request sent: [%r] from (%s)' \
 
507
                    % (request, request.connection.sock.getsockname())
516
508
            response = connection.getresponse()
517
509
            convert_to_addinfourl = True
518
510
        except (socket.gaierror, httplib.BadStatusLine, httplib.UnknownProtocol,
532
524
#            connection.send(body)
533
525
#            response = connection.getresponse()
534
526
 
535
 
        if self._debuglevel > 0:
 
527
        if self._debuglevel >= 2:
536
528
            print 'Receives response: %r' % response
537
529
            print '  For: %r(%r)' % (request.get_method(),
538
530
                                     request.get_full_url())
547
539
            resp.code = r.status
548
540
            resp.msg = r.reason
549
541
            resp.version = r.version
550
 
            if self._debuglevel > 0:
 
542
            if self._debuglevel >= 2:
551
543
                print 'Create addinfourl: %r' % resp
552
544
                print '  For: %r(%r)' % (request.get_method(),
553
545
                                         request.get_full_url())
593
585
            # - with and without certificate
594
586
            # - with self-signed certificate
595
587
            # - with and without authentication
596
 
            # - with good and bad credentials (especially the proxy auth aound
 
588
            # - with good and bad credentials (especially the proxy auth around
597
589
            #   CONNECT)
598
590
            # - with basic and digest schemes
599
591
            # - reconnection on errors
694
686
            newurl = headers.getheaders('uri')[0]
695
687
        else:
696
688
            return
697
 
        if self._debuglevel > 0:
 
689
        if self._debuglevel >= 1:
698
690
            print 'Redirected to: %s (followed: %r)' % (newurl,
699
691
                                                        req.follow_redirections)
700
692
        if req.follow_redirections is False:
757
749
        urllib2.ProxyHandler.__init__(self, proxies)
758
750
        # First, let's get rid of urllib2 implementation
759
751
        for type, proxy in self.proxies.items():
760
 
            if self._debuglevel > 0:
 
752
            if self._debuglevel >= 3:
761
753
                print 'Will unbind %s_open for %r' % (type, proxy)
762
754
            delattr(self, '%s_open' % type)
763
755
 
766
758
        https_proxy = self.get_proxy_env_var('https')
767
759
 
768
760
        if http_proxy is not None:
769
 
            if self._debuglevel > 0:
 
761
            if self._debuglevel >= 3:
770
762
                print 'Will bind http_request for %r' % http_proxy
771
763
            setattr(self, 'http_request',
772
764
                    lambda request: self.set_proxy(request, 'http'))
773
765
 
774
766
        if https_proxy is not None:
775
 
            if self._debuglevel > 0:
 
767
            if self._debuglevel >= 3:
776
768
                print 'Will bind http_request for %r' % https_proxy
777
769
            setattr(self, 'https_request',
778
770
                    lambda request: self.set_proxy(request, 'https'))
823
815
            return request
824
816
 
825
817
        proxy = self.get_proxy_env_var(type)
826
 
        if self._debuglevel > 0:
 
818
        if self._debuglevel >= 3:
827
819
            print 'set_proxy %s_request for %r' % (type, proxy)
828
820
        # FIXME: python 2.5 urlparse provides a better _parse_proxy which can
829
821
        # grok user:password@host:port as well as
847
839
        else:
848
840
            phost = host + ':%d' % port
849
841
        request.set_proxy(phost, type)
850
 
        if self._debuglevel > 0:
 
842
        if self._debuglevel >= 3:
851
843
            print 'set_proxy: proxy set to %s://%s' % (type, phost)
852
844
        return request
853
845
 
948
940
                # We already tried that, give up
949
941
                return None
950
942
 
 
943
            # Housekeeping
 
944
            request.connection.cleanup_pipe()
951
945
            response = self.parent.open(request)
952
946
            if response:
953
947
                self.auth_successful(request, response)
1350
1344
            )
1351
1345
 
1352
1346
        self.open = self._opener.open
1353
 
        if DEBUG >= 3:
 
1347
        if DEBUG >= 9:
1354
1348
            # When dealing with handler order, it's easy to mess
1355
1349
            # things up, the following will help understand which
1356
1350
            # handler is used, when and for what.