/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 breezy/tests/http_server.py

  • Committer: Jelmer Vernooij
  • Date: 2017-06-08 23:30:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170608233031-3qavls2o7a1pqllj
Update imports.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import errno
18
 
import http.client as http_client
19
 
import http.server as http_server
 
18
import httplib
20
19
import os
21
20
import posixpath
22
21
import random
23
22
import re
 
23
import SimpleHTTPServer
24
24
import socket
25
 
import sys
26
 
from urllib.parse import urlparse
 
25
import urlparse
27
26
 
28
27
from .. import (
29
28
    osutils,
37
36
        return 'path %s is not in %s' % self.args
38
37
 
39
38
 
40
 
class TestingHTTPRequestHandler(http_server.SimpleHTTPRequestHandler):
 
39
class TestingHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
41
40
    """Handles one request.
42
41
 
43
42
    A TestingHTTPRequestHandler is instantiated for every request received by
49
48
    protocol_version = 'HTTP/1.1'
50
49
 
51
50
    # The Message-like class used to parse the request headers
52
 
    MessageClass = http_client.HTTPMessage
 
51
    MessageClass = httplib.HTTPMessage
53
52
 
54
53
    def setup(self):
55
 
        http_server.SimpleHTTPRequestHandler.setup(self)
 
54
        SimpleHTTPServer.SimpleHTTPRequestHandler.setup(self)
56
55
        self._cwd = self.server._home_dir
57
56
        tcs = self.server.test_case_server
58
57
        if tcs.protocol_version is not None:
68
67
                self.headers.get('referer', '-'),
69
68
                self.headers.get('user-agent', '-'))
70
69
 
 
70
    def handle(self):
 
71
        SimpleHTTPServer.SimpleHTTPRequestHandler.handle(self)
 
72
        # Some client (pycurl, I'm looking at you) are more picky than others
 
73
        # and require that the socket itself is closed
 
74
        # (SocketServer.StreamRequestHandler only close the two associated
 
75
        # 'makefile' objects)
 
76
        self.connection.close()
 
77
 
71
78
    def handle_one_request(self):
72
79
        """Handle a single HTTP request.
73
80
 
95
102
    def send_error(self, code, message=None):
96
103
        """Send and log an error reply.
97
104
 
98
 
        We redefine the python-provided version to be able to set a
 
105
        We redefine the python-provided version to be able to set a 
99
106
        ``Content-Length`` header as some http/1.1 clients complain otherwise
100
107
        (see bug #568421).
101
108
 
119
126
        self.send_header('Connection', 'close')
120
127
        self.end_headers()
121
128
        if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
122
 
            self.wfile.write(content.encode('utf-8'))
 
129
            self.wfile.write(content)
123
130
 
124
131
    def _handle_one_request(self):
125
 
        http_server.SimpleHTTPRequestHandler.handle_one_request(self)
 
132
        SimpleHTTPServer.SimpleHTTPRequestHandler.handle_one_request(self)
126
133
 
127
134
    _range_regexp = re.compile(r'^(?P<start>\d+)-(?P<end>\d+)?$')
128
135
    _tail_regexp = re.compile(r'^-(?P<tail>\d+)$')
187
194
        header_line = '%s: %s\r\n' % (keyword, value)
188
195
        return len(header_line)
189
196
 
 
197
    def send_head(self):
 
198
        """Overrides base implementation to work around a bug in python2.5."""
 
199
        path = self.translate_path(self.path)
 
200
        if os.path.isdir(path) and not self.path.endswith('/'):
 
201
            # redirect browser - doing basically what apache does when
 
202
            # DirectorySlash option is On which is quite common (braindead, but
 
203
            # common)
 
204
            self.send_response(301)
 
205
            self.send_header("Location", self.path + "/")
 
206
            # Indicates that the body is empty for HTTP/1.1 clients
 
207
            self.send_header('Content-Length', '0')
 
208
            self.end_headers()
 
209
            return None
 
210
 
 
211
        return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
 
212
 
190
213
    def send_range_content(self, file, start, length):
191
214
        file.seek(start)
192
215
        self.wfile.write(file.read(length))
207
230
    def get_multiple_ranges(self, file, file_size, ranges):
208
231
        self.send_response(206)
209
232
        self.send_header('Accept-Ranges', 'bytes')
210
 
        boundary = '%d' % random.randint(0, 0x7FFFFFFF)
 
233
        boundary = '%d' % random.randint(0,0x7FFFFFFF)
211
234
        self.send_header('Content-Type',
212
235
                         'multipart/byteranges; boundary=%s' % boundary)
213
 
        boundary_line = b'--%s\r\n' % boundary.encode('ascii')
 
236
        boundary_line = '--%s\r\n' % boundary
214
237
        # Calculate the Content-Length
215
238
        content_length = 0
216
239
        for (start, end) in ranges:
219
242
                'Content-type', 'application/octet-stream')
220
243
            content_length += self._header_line_length(
221
244
                'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
222
 
            content_length += len('\r\n')  # end headers
 
245
            content_length += len('\r\n') # end headers
223
246
            content_length += end - start + 1
224
247
        content_length += len(boundary_line)
225
248
        self.send_header('Content-length', content_length)
248
271
        ranges_header_value = self.headers.get('Range')
249
272
        if ranges_header_value is None or os.path.isdir(path):
250
273
            # Let the mother class handle most cases
251
 
            return http_server.SimpleHTTPRequestHandler.do_GET(self)
 
274
            return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
252
275
 
253
276
        try:
254
277
            # Always read in binary mode. Opening files in text
297
320
            # do beginning with python 2.4.3: abandon query
298
321
            # parameters, scheme, host port, etc (which ensure we
299
322
            # provide the right behaviour on all python versions).
300
 
            path = urlparse(path)[2]
 
323
            path = urlparse.urlparse(path)[2]
301
324
            # And now, we can apply *our* trick to proxy files
302
325
            path += '-proxied'
303
326
 
315
338
        Override from python standard library to stop it calling os.getcwd()
316
339
        """
317
340
        # abandon query parameters
318
 
        path = urlparse(path)[2]
 
341
        path = urlparse.urlparse(path)[2]
319
342
        path = posixpath.normpath(urlutils.unquote(path))
 
343
        path = path.decode('utf-8')
320
344
        words = path.split('/')
321
345
        path = self._cwd
322
346
        for num, word in enumerate(w for w in words if w):
323
347
            if num == 0:
324
348
                drive, word = os.path.splitdrive(word)
325
349
            head, word = os.path.split(word)
326
 
            if word in (os.curdir, os.pardir):
327
 
                continue
 
350
            if word in (os.curdir, os.pardir): continue
328
351
            path = os.path.join(path, word)
329
352
        return path
330
353
 
357
380
    server, we need an independent connection for each of them. We achieve that
358
381
    by spawning a new thread for each connection.
359
382
    """
360
 
 
361
383
    def __init__(self, server_address, request_handler_class,
362
384
                 test_case_server):
363
385
        test_server.TestingThreadingTCPServer.__init__(self, server_address,
405
427
        # Get the appropriate server class for the required protocol
406
428
        serv_cls = self.http_server_class.get(proto_vers, None)
407
429
        if serv_cls is None:
408
 
            raise http_client.UnknownProtocol(proto_vers)
 
430
            raise httplib.UnknownProtocol(proto_vers)
409
431
        self.host = 'localhost'
410
432
        self.port = 0
411
433
        super(HttpServer, self).__init__((self.host, self.port),
425
447
        path_parts = path.split(os.path.sep)
426
448
        if os.path.isabs(path):
427
449
            if path_parts[:len(self._local_path_parts)] != \
428
 
                    self._local_path_parts:
 
450
                   self._local_path_parts:
429
451
                raise BadWebserverPath(path, self.test_dir)
430
452
            remote_path = '/'.join(path_parts[len(self._local_path_parts):])
431
453
        else:
469
491
        # this is chosen to try to prevent trouble with proxies, weird dns,
470
492
        # etc
471
493
        return self._url_protocol + '://127.0.0.1:1/'
 
494
 
 
495
 
 
496
class HttpServer_urllib(HttpServer):
 
497
    """Subclass of HttpServer that gives http+urllib urls.
 
498
 
 
499
    This is for use in testing: connections to this server will always go
 
500
    through urllib where possible.
 
501
    """
 
502
 
 
503
    # urls returned by this server should require the urllib client impl
 
504
    _url_protocol = 'http+urllib'
 
505
 
 
506
 
 
507
class HttpServer_PyCurl(HttpServer):
 
508
    """Subclass of HttpServer that gives http+pycurl urls.
 
509
 
 
510
    This is for use in testing: connections to this server will always go
 
511
    through pycurl where possible.
 
512
    """
 
513
 
 
514
    # We don't care about checking the pycurl availability as
 
515
    # this server will be required only when pycurl is present
 
516
 
 
517
    # urls returned by this server should require the pycurl client impl
 
518
    _url_protocol = 'http+pycurl'