~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/HTTPTestUtil.py

  • Committer: Ian Clatworthy
  • Date: 2007-12-07 05:31:54 UTC
  • mto: (3092.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 3093.
  • Revision ID: ian.clatworthy@internode.on.net-20071207053154-k9tmyczcf8niwonm
fix efficiency of local commit detection as recommended by jameinel's review

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
from cStringIO import StringIO
 
18
import errno
 
19
import md5
 
20
from SimpleHTTPServer import SimpleHTTPRequestHandler
18
21
import re
 
22
import sha
 
23
import socket
 
24
import time
19
25
import urllib2
20
 
 
21
 
 
22
 
from bzrlib import (
23
 
    errors,
24
 
    osutils,
25
 
    tests,
26
 
    transport,
27
 
    )
28
 
from bzrlib.smart import (
29
 
    medium,
30
 
    )
31
 
from bzrlib.tests import http_server
32
 
from bzrlib.transport import chroot
33
 
 
34
 
 
35
 
class HTTPServerWithSmarts(http_server.HttpServer):
 
26
import urlparse
 
27
 
 
28
from bzrlib.smart import protocol
 
29
from bzrlib.tests import TestCaseWithTransport
 
30
from bzrlib.tests.HttpServer import (
 
31
    HttpServer,
 
32
    TestingHTTPRequestHandler,
 
33
    )
 
34
from bzrlib.transport import (
 
35
    get_transport,
 
36
    )
 
37
 
 
38
 
 
39
class WallRequestHandler(TestingHTTPRequestHandler):
 
40
    """Whatever request comes in, close the connection"""
 
41
 
 
42
    def handle_one_request(self):
 
43
        """Handle a single HTTP request, by abruptly closing the connection"""
 
44
        self.close_connection = 1
 
45
 
 
46
 
 
47
class BadStatusRequestHandler(TestingHTTPRequestHandler):
 
48
    """Whatever request comes in, returns a bad status"""
 
49
 
 
50
    def parse_request(self):
 
51
        """Fakes handling a single HTTP request, returns a bad status"""
 
52
        ignored = TestingHTTPRequestHandler.parse_request(self)
 
53
        try:
 
54
            self.send_response(0, "Bad status")
 
55
            self.end_headers()
 
56
        except socket.error, e:
 
57
            # We don't want to pollute the test results with
 
58
            # spurious server errors while test succeed. In our
 
59
            # case, it may occur that the test has already read
 
60
            # the 'Bad Status' and closed the socket while we are
 
61
            # still trying to send some headers... So the test is
 
62
            # ok, but if we raise the exception, the output is
 
63
            # dirty. So we don't raise, but we close the
 
64
            # connection, just to be safe :)
 
65
            spurious = [errno.EPIPE,
 
66
                        errno.ECONNRESET,
 
67
                        errno.ECONNABORTED,
 
68
                        ]
 
69
            if (len(e.args) > 0) and (e.args[0] in spurious):
 
70
                self.close_connection = 1
 
71
                pass
 
72
            else:
 
73
                raise
 
74
        return False
 
75
 
 
76
 
 
77
class InvalidStatusRequestHandler(TestingHTTPRequestHandler):
 
78
    """Whatever request comes in, returns am invalid status"""
 
79
 
 
80
    def parse_request(self):
 
81
        """Fakes handling a single HTTP request, returns a bad status"""
 
82
        ignored = TestingHTTPRequestHandler.parse_request(self)
 
83
        self.wfile.write("Invalid status line\r\n")
 
84
        return False
 
85
 
 
86
 
 
87
class BadProtocolRequestHandler(TestingHTTPRequestHandler):
 
88
    """Whatever request comes in, returns a bad protocol version"""
 
89
 
 
90
    def parse_request(self):
 
91
        """Fakes handling a single HTTP request, returns a bad status"""
 
92
        ignored = TestingHTTPRequestHandler.parse_request(self)
 
93
        # Returns an invalid protocol version, but curl just
 
94
        # ignores it and those cannot be tested.
 
95
        self.wfile.write("%s %d %s\r\n" % ('HTTP/0.0',
 
96
                                           404,
 
97
                                           'Look at my protocol version'))
 
98
        return False
 
99
 
 
100
 
 
101
class ForbiddenRequestHandler(TestingHTTPRequestHandler):
 
102
    """Whatever request comes in, returns a 403 code"""
 
103
 
 
104
    def parse_request(self):
 
105
        """Handle a single HTTP request, by replying we cannot handle it"""
 
106
        ignored = TestingHTTPRequestHandler.parse_request(self)
 
107
        self.send_error(403)
 
108
        return False
 
109
 
 
110
 
 
111
class HTTPServerWithSmarts(HttpServer):
36
112
    """HTTPServerWithSmarts extends the HttpServer with POST methods that will
37
113
    trigger a smart server to execute with a transport rooted at the rootdir of
38
114
    the HTTP server.
39
115
    """
40
116
 
41
 
    def __init__(self, protocol_version=None):
42
 
        http_server.HttpServer.__init__(self, SmartRequestHandler,
43
 
                                        protocol_version=protocol_version)
44
 
 
45
 
 
46
 
class SmartRequestHandler(http_server.TestingHTTPRequestHandler):
47
 
    """Extend TestingHTTPRequestHandler to support smart client POSTs.
48
 
 
49
 
    XXX: This duplicates a fair bit of the logic in bzrlib.transport.http.wsgi.
50
 
    """
 
117
    def __init__(self):
 
118
        HttpServer.__init__(self, SmartRequestHandler)
 
119
 
 
120
 
 
121
class SmartRequestHandler(TestingHTTPRequestHandler):
 
122
    """Extend TestingHTTPRequestHandler to support smart client POSTs."""
51
123
 
52
124
    def do_POST(self):
53
125
        """Hand the request off to a smart server instance."""
54
 
        backing = transport.get_transport_from_path(
55
 
            self.server.test_case_server._home_dir)
56
 
        chroot_server = chroot.ChrootServer(backing)
57
 
        chroot_server.start_server()
58
 
        try:
59
 
            t = transport.get_transport_from_url(chroot_server.get_url())
60
 
            self.do_POST_inner(t)
61
 
        finally:
62
 
            chroot_server.stop_server()
63
 
 
64
 
    def do_POST_inner(self, chrooted_transport):
65
126
        self.send_response(200)
66
127
        self.send_header("Content-type", "application/octet-stream")
67
 
        if not self.path.endswith('.bzr/smart'):
68
 
            raise AssertionError(
69
 
                'POST to path not ending in .bzr/smart: %r' % (self.path,))
70
 
        t = chrooted_transport.clone(self.path[:-len('.bzr/smart')])
71
 
        # if this fails, we should return 400 bad request, but failure is
72
 
        # failure for now - RBC 20060919
73
 
        data_length = int(self.headers['Content-Length'])
 
128
        transport = get_transport(self.server.test_case_server._home_dir)
74
129
        # TODO: We might like to support streaming responses.  1.0 allows no
75
130
        # Content-length in this case, so for integrity we should perform our
76
131
        # own chunking within the stream.
78
133
        # the HTTP chunking as this will allow HTTP persistence safely, even if
79
134
        # we have to stop early due to error, but we would also have to use the
80
135
        # HTTP trailer facility which may not be widely available.
81
 
        request_bytes = self.rfile.read(data_length)
82
 
        protocol_factory, unused_bytes = medium._get_protocol_factory_for_bytes(
83
 
            request_bytes)
84
136
        out_buffer = StringIO()
85
 
        smart_protocol_request = protocol_factory(t, out_buffer.write, '/')
 
137
        smart_protocol_request = protocol.SmartServerRequestProtocolOne(
 
138
                transport, out_buffer.write)
 
139
        # if this fails, we should return 400 bad request, but failure is
 
140
        # failure for now - RBC 20060919
 
141
        data_length = int(self.headers['Content-Length'])
86
142
        # Perhaps there should be a SmartServerHTTPMedium that takes care of
87
143
        # feeding the bytes in the http request to the smart_protocol_request,
88
144
        # but for now it's simpler to just feed the bytes directly.
89
 
        smart_protocol_request.accept_bytes(unused_bytes)
90
 
        if not (smart_protocol_request.next_read_size() == 0):
91
 
            raise errors.SmartProtocolError(
92
 
                "not finished reading, but all data sent to protocol.")
 
145
        smart_protocol_request.accept_bytes(self.rfile.read(data_length))
 
146
        assert smart_protocol_request.next_read_size() == 0, (
 
147
            "not finished reading, but all data sent to protocol.")
93
148
        self.send_header("Content-Length", str(len(out_buffer.getvalue())))
94
149
        self.end_headers()
95
150
        self.wfile.write(out_buffer.getvalue())
96
151
 
97
152
 
98
 
class TestCaseWithWebserver(tests.TestCaseWithTransport):
 
153
class LimitedRangeRequestHandler(TestingHTTPRequestHandler):
 
154
    """Errors out when range specifiers exceed the limit"""
 
155
 
 
156
    def get_multiple_ranges(self, file, file_size, ranges):
 
157
        """Refuses the multiple ranges request"""
 
158
        tcs = self.server.test_case_server
 
159
        if tcs.range_limit is not None and len(ranges) > tcs.range_limit:
 
160
            file.close()
 
161
            # Emulate apache behavior
 
162
            self.send_error(400, "Bad Request")
 
163
            return
 
164
        return TestingHTTPRequestHandler.get_multiple_ranges(self, file,
 
165
                                                             file_size, ranges)
 
166
 
 
167
 
 
168
class LimitedRangeHTTPServer(HttpServer):
 
169
    """An HttpServer erroring out on requests with too much range specifiers"""
 
170
 
 
171
    def __init__(self, request_handler=LimitedRangeRequestHandler,
 
172
                 range_limit=None):
 
173
        HttpServer.__init__(self, request_handler)
 
174
        self.range_limit = range_limit
 
175
 
 
176
 
 
177
class SingleRangeRequestHandler(TestingHTTPRequestHandler):
 
178
    """Always reply to range request as if they were single.
 
179
 
 
180
    Don't be explicit about it, just to annoy the clients.
 
181
    """
 
182
 
 
183
    def get_multiple_ranges(self, file, file_size, ranges):
 
184
        """Answer as if it was a single range request and ignores the rest"""
 
185
        (start, end) = ranges[0]
 
186
        return self.get_single_range(file, file_size, start, end)
 
187
 
 
188
 
 
189
class SingleOnlyRangeRequestHandler(TestingHTTPRequestHandler):
 
190
    """Only reply to simple range requests, errors out on multiple"""
 
191
 
 
192
    def get_multiple_ranges(self, file, file_size, ranges):
 
193
        """Refuses the multiple ranges request"""
 
194
        if len(ranges) > 1:
 
195
            file.close()
 
196
            self.send_error(416, "Requested range not satisfiable")
 
197
            return
 
198
        (start, end) = ranges[0]
 
199
        return self.get_single_range(file, file_size, start, end)
 
200
 
 
201
 
 
202
class NoRangeRequestHandler(TestingHTTPRequestHandler):
 
203
    """Ignore range requests without notice"""
 
204
 
 
205
    def do_GET(self):
 
206
        # Update the statistics
 
207
        self.server.test_case_server.GET_request_nb += 1
 
208
        # Just bypass the range handling done by TestingHTTPRequestHandler
 
209
        return SimpleHTTPRequestHandler.do_GET(self)
 
210
 
 
211
 
 
212
class TestCaseWithWebserver(TestCaseWithTransport):
99
213
    """A support class that provides readonly urls that are http://.
100
214
 
101
215
    This is done by forcing the readonly server to be an http
102
216
    one. This will currently fail if the primary transport is not
103
217
    backed by regular disk files.
104
218
    """
105
 
 
106
 
    # These attributes can be overriden or parametrized by daughter clasess if
107
 
    # needed, but must exist so that the create_transport_readonly_server()
108
 
    # method (or any method creating an http(s) server) can propagate it.
109
 
    _protocol_version = None
110
 
    _url_protocol = 'http'
111
 
 
112
219
    def setUp(self):
113
220
        super(TestCaseWithWebserver, self).setUp()
114
 
        self.transport_readonly_server = http_server.HttpServer
115
 
 
116
 
    def create_transport_readonly_server(self):
117
 
        server = self.transport_readonly_server(
118
 
            protocol_version=self._protocol_version)
119
 
        server._url_protocol = self._url_protocol
120
 
        return server
 
221
        self.transport_readonly_server = HttpServer
121
222
 
122
223
 
123
224
class TestCaseWithTwoWebservers(TestCaseWithWebserver):
128
229
    """
129
230
    def setUp(self):
130
231
        super(TestCaseWithTwoWebservers, self).setUp()
131
 
        self.transport_secondary_server = http_server.HttpServer
 
232
        self.transport_secondary_server = HttpServer
132
233
        self.__secondary_server = None
133
234
 
134
235
    def create_transport_secondary_server(self):
136
237
 
137
238
        This is mostly a hook for daughter classes.
138
239
        """
139
 
        server = self.transport_secondary_server(
140
 
            protocol_version=self._protocol_version)
141
 
        server._url_protocol = self._url_protocol
142
 
        return server
 
240
        return self.transport_secondary_server()
143
241
 
144
242
    def get_secondary_server(self):
145
243
        """Get the server instance for the secondary transport."""
146
244
        if self.__secondary_server is None:
147
245
            self.__secondary_server = self.create_transport_secondary_server()
148
 
            self.start_server(self.__secondary_server)
 
246
            self.__secondary_server.setUp()
 
247
            self.addCleanup(self.__secondary_server.tearDown)
149
248
        return self.__secondary_server
150
249
 
151
 
    def get_secondary_url(self, relpath=None):
152
 
        base = self.get_secondary_server().get_url()
153
 
        return self._adjust_url(base, relpath)
154
 
 
155
 
    def get_secondary_transport(self, relpath=None):
156
 
        t = transport.get_transport_from_url(self.get_secondary_url(relpath))
157
 
        self.assertTrue(t.is_readonly())
158
 
        return t
159
 
 
160
 
 
161
 
class ProxyServer(http_server.HttpServer):
 
250
 
 
251
class ProxyServer(HttpServer):
162
252
    """A proxy test server for http transports."""
163
253
 
164
254
    proxy_requests = True
165
255
 
166
256
 
167
 
class RedirectRequestHandler(http_server.TestingHTTPRequestHandler):
 
257
class RedirectRequestHandler(TestingHTTPRequestHandler):
168
258
    """Redirect all request to the specified server"""
169
259
 
170
260
    def parse_request(self):
171
261
        """Redirect a single HTTP request to another host"""
172
 
        valid = http_server.TestingHTTPRequestHandler.parse_request(self)
 
262
        valid = TestingHTTPRequestHandler.parse_request(self)
173
263
        if valid:
174
264
            tcs = self.server.test_case_server
175
265
            code, target = tcs.is_redirected(self.path)
177
267
                # Redirect as instructed
178
268
                self.send_response(code)
179
269
                self.send_header('Location', target)
180
 
                # We do not send a body
181
 
                self.send_header('Content-Length', '0')
182
270
                self.end_headers()
183
271
                return False # The job is done
184
272
            else:
187
275
        return valid
188
276
 
189
277
 
190
 
class HTTPServerRedirecting(http_server.HttpServer):
 
278
class HTTPServerRedirecting(HttpServer):
191
279
    """An HttpServer redirecting to another server """
192
280
 
193
 
    def __init__(self, request_handler=RedirectRequestHandler,
194
 
                 protocol_version=None):
195
 
        http_server.HttpServer.__init__(self, request_handler,
196
 
                                        protocol_version=protocol_version)
 
281
    def __init__(self, request_handler=RedirectRequestHandler):
 
282
        HttpServer.__init__(self, request_handler)
197
283
        # redirections is a list of tuples (source, target, code)
198
284
        # - source is a regexp for the paths requested
199
285
        # - target is a replacement for re.sub describing where
236
322
   The 'old' server is redirected to the 'new' server.
237
323
   """
238
324
 
 
325
   def create_transport_secondary_server(self):
 
326
       """Create the secondary server redirecting to the primary server"""
 
327
       new = self.get_readonly_server()
 
328
       redirecting = HTTPServerRedirecting()
 
329
       redirecting.redirect_to(new.host, new.port)
 
330
       return redirecting
 
331
 
239
332
   def setUp(self):
240
333
       super(TestCaseWithRedirectedWebserver, self).setUp()
241
334
       # The redirections will point to the new server
242
335
       self.new_server = self.get_readonly_server()
243
 
       # The requests to the old server will be redirected to the new server
 
336
       # The requests to the old server will be redirected
244
337
       self.old_server = self.get_secondary_server()
245
338
 
246
 
   def create_transport_secondary_server(self):
247
 
       """Create the secondary server redirecting to the primary server"""
248
 
       new = self.get_readonly_server()
249
 
       redirecting = HTTPServerRedirecting(
250
 
           protocol_version=self._protocol_version)
251
 
       redirecting.redirect_to(new.host, new.port)
252
 
       redirecting._url_protocol = self._url_protocol
253
 
       return redirecting
254
 
 
255
 
   def get_old_url(self, relpath=None):
256
 
        base = self.old_server.get_url()
257
 
        return self._adjust_url(base, relpath)
258
 
 
259
 
   def get_old_transport(self, relpath=None):
260
 
        t = transport.get_transport_from_url(self.get_old_url(relpath))
261
 
        self.assertTrue(t.is_readonly())
262
 
        return t
263
 
 
264
 
   def get_new_url(self, relpath=None):
265
 
        base = self.new_server.get_url()
266
 
        return self._adjust_url(base, relpath)
267
 
 
268
 
   def get_new_transport(self, relpath=None):
269
 
        t = transport.get_transport_from_url(self.get_new_url(relpath))
270
 
        self.assertTrue(t.is_readonly())
271
 
        return t
272
 
 
273
 
 
274
 
class AuthRequestHandler(http_server.TestingHTTPRequestHandler):
 
339
 
 
340
class AuthRequestHandler(TestingHTTPRequestHandler):
275
341
    """Requires an authentication to process requests.
276
342
 
277
343
    This is intended to be used with a server that always and
284
350
    # - auth_header_recv: the header received containing auth
285
351
    # - auth_error_code: the error code to indicate auth required
286
352
 
287
 
    def _require_authentication(self):
288
 
        # Note that we must update test_case_server *before*
289
 
        # sending the error or the client may try to read it
290
 
        # before we have sent the whole error back.
291
 
        tcs = self.server.test_case_server
292
 
        tcs.auth_required_errors += 1
293
 
        self.send_response(tcs.auth_error_code)
294
 
        self.send_header_auth_reqed()
295
 
        # We do not send a body
296
 
        self.send_header('Content-Length', '0')
297
 
        self.end_headers()
298
 
        return
299
 
 
300
353
    def do_GET(self):
301
354
        if self.authorized():
302
 
            return http_server.TestingHTTPRequestHandler.do_GET(self)
303
 
        else:
304
 
            return self._require_authentication()
305
 
 
306
 
    def do_HEAD(self):
307
 
        if self.authorized():
308
 
            return http_server.TestingHTTPRequestHandler.do_HEAD(self)
309
 
        else:
310
 
            return self._require_authentication()
 
355
            return TestingHTTPRequestHandler.do_GET(self)
 
356
        else:
 
357
            # Note that we must update test_case_server *before*
 
358
            # sending the error or the client may try to read it
 
359
            # before we have sent the whole error back.
 
360
            tcs = self.server.test_case_server
 
361
            tcs.auth_required_errors += 1
 
362
            self.send_response(tcs.auth_error_code)
 
363
            self.send_header_auth_reqed()
 
364
            self.end_headers()
 
365
            return
311
366
 
312
367
 
313
368
class BasicAuthRequestHandler(AuthRequestHandler):
346
401
 
347
402
    def authorized(self):
348
403
        tcs = self.server.test_case_server
 
404
        if tcs.auth_scheme != 'digest':
 
405
            return False
349
406
 
350
407
        auth_header = self.headers.get(tcs.auth_header_recv, None)
351
408
        if auth_header is None:
366
423
        self.send_header(tcs.auth_header_sent,header)
367
424
 
368
425
 
369
 
class DigestAndBasicAuthRequestHandler(DigestAuthRequestHandler):
370
 
    """Implements a digest and basic authentication of a request.
371
 
 
372
 
    I.e. the server proposes both schemes and the client should choose the best
373
 
    one it can handle, which, in that case, should be digest, the only scheme
374
 
    accepted here.
375
 
    """
376
 
 
377
 
    def send_header_auth_reqed(self):
378
 
        tcs = self.server.test_case_server
379
 
        self.send_header(tcs.auth_header_sent,
380
 
                         'Basic realm="%s"' % tcs.auth_realm)
381
 
        header = 'Digest realm="%s", ' % tcs.auth_realm
382
 
        header += 'nonce="%s", algorithm="%s", qop="auth"' % (tcs.auth_nonce,
383
 
                                                              'MD5')
384
 
        self.send_header(tcs.auth_header_sent,header)
385
 
 
386
 
 
387
 
class AuthServer(http_server.HttpServer):
 
426
class AuthServer(HttpServer):
388
427
    """Extends HttpServer with a dictionary of passwords.
389
428
 
390
429
    This is used as a base class for various schemes which should
401
440
    auth_error_code = None
402
441
    auth_realm = "Thou should not pass"
403
442
 
404
 
    def __init__(self, request_handler, auth_scheme,
405
 
                 protocol_version=None):
406
 
        http_server.HttpServer.__init__(self, request_handler,
407
 
                                        protocol_version=protocol_version)
 
443
    def __init__(self, request_handler, auth_scheme):
 
444
        HttpServer.__init__(self, request_handler)
408
445
        self.auth_scheme = auth_scheme
409
446
        self.password_of = {}
410
447
        self.auth_required_errors = 0
433
470
 
434
471
    auth_nonce = 'now!'
435
472
 
436
 
    def __init__(self, request_handler, auth_scheme,
437
 
                 protocol_version=None):
438
 
        AuthServer.__init__(self, request_handler, auth_scheme,
439
 
                            protocol_version=protocol_version)
 
473
    def __init__(self, request_handler, auth_scheme):
 
474
        AuthServer.__init__(self, request_handler, auth_scheme)
440
475
 
441
476
    def digest_authorized(self, auth, command):
442
477
        nonce = auth['nonce']
462
497
        A1 = '%s:%s:%s' % (user, realm, password)
463
498
        A2 = '%s:%s' % (command, auth['uri'])
464
499
 
465
 
        H = lambda x: osutils.md5(x).hexdigest()
 
500
        H = lambda x: md5.new(x).hexdigest()
466
501
        KD = lambda secret, data: H("%s:%s" % (secret, data))
467
502
 
468
503
        nonce_count = int(auth['nc'], 16)
475
510
 
476
511
        return response_digest == auth['response']
477
512
 
478
 
 
479
513
class HTTPAuthServer(AuthServer):
480
514
    """An HTTP server requiring authentication"""
481
515
 
498
532
class HTTPBasicAuthServer(HTTPAuthServer):
499
533
    """An HTTP server requiring basic authentication"""
500
534
 
501
 
    def __init__(self, protocol_version=None):
502
 
        HTTPAuthServer.__init__(self, BasicAuthRequestHandler, 'basic',
503
 
                                protocol_version=protocol_version)
 
535
    def __init__(self):
 
536
        HTTPAuthServer.__init__(self, BasicAuthRequestHandler, 'basic')
504
537
        self.init_http_auth()
505
538
 
506
539
 
507
540
class HTTPDigestAuthServer(DigestAuthServer, HTTPAuthServer):
508
541
    """An HTTP server requiring digest authentication"""
509
542
 
510
 
    def __init__(self, protocol_version=None):
511
 
        DigestAuthServer.__init__(self, DigestAuthRequestHandler, 'digest',
512
 
                                  protocol_version=protocol_version)
513
 
        self.init_http_auth()
514
 
 
515
 
 
516
 
class HTTPBasicAndDigestAuthServer(DigestAuthServer, HTTPAuthServer):
517
 
    """An HTTP server requiring basic or digest authentication"""
518
 
 
519
 
    def __init__(self, protocol_version=None):
520
 
        DigestAuthServer.__init__(self, DigestAndBasicAuthRequestHandler,
521
 
                                  'basicdigest',
522
 
                                  protocol_version=protocol_version)
523
 
        self.init_http_auth()
524
 
        # We really accept Digest only
525
 
        self.auth_scheme = 'digest'
 
543
    def __init__(self):
 
544
        DigestAuthServer.__init__(self, DigestAuthRequestHandler, 'digest')
 
545
        self.init_http_auth()
526
546
 
527
547
 
528
548
class ProxyBasicAuthServer(ProxyAuthServer):
529
549
    """A proxy server requiring basic authentication"""
530
550
 
531
 
    def __init__(self, protocol_version=None):
532
 
        ProxyAuthServer.__init__(self, BasicAuthRequestHandler, 'basic',
533
 
                                 protocol_version=protocol_version)
 
551
    def __init__(self):
 
552
        ProxyAuthServer.__init__(self, BasicAuthRequestHandler, 'basic')
534
553
        self.init_proxy_auth()
535
554
 
536
555
 
537
556
class ProxyDigestAuthServer(DigestAuthServer, ProxyAuthServer):
538
557
    """A proxy server requiring basic authentication"""
539
558
 
540
 
    def __init__(self, protocol_version=None):
541
 
        ProxyAuthServer.__init__(self, DigestAuthRequestHandler, 'digest',
542
 
                                 protocol_version=protocol_version)
543
 
        self.init_proxy_auth()
544
 
 
545
 
 
546
 
class ProxyBasicAndDigestAuthServer(DigestAuthServer, ProxyAuthServer):
547
 
    """An proxy server requiring basic or digest authentication"""
548
 
 
549
 
    def __init__(self, protocol_version=None):
550
 
        DigestAuthServer.__init__(self, DigestAndBasicAuthRequestHandler,
551
 
                                  'basicdigest',
552
 
                                  protocol_version=protocol_version)
553
 
        self.init_proxy_auth()
554
 
        # We really accept Digest only
555
 
        self.auth_scheme = 'digest'
 
559
    def __init__(self):
 
560
        ProxyAuthServer.__init__(self, DigestAuthRequestHandler, 'digest')
 
561
        self.init_proxy_auth()
556
562
 
557
563