89
90
                                     errno.ECONNABORTED, errno.EBADF)):
 
92
 
    _range_regexp = re.compile(r'^(?P<start>\d+)-(?P<end>\d+)$')
 
 
93
    error_content_type = 'text/plain'
 
 
94
    error_message_format = '''\
 
 
99
    def send_error(self, code, message=None):
 
 
100
        """Send and log an error reply.
 
 
102
        We redefine the python-provided version to be able to set a 
 
 
103
        ``Content-Length`` header as some http/1.1 clients complain otherwise
 
 
106
        :param code: The HTTP error code.
 
 
108
        :param message: The explanation of the error code, Defaults to a short
 
 
114
                message = self.responses[code][0]
 
 
117
        self.log_error("code %d, message %s", code, message)
 
 
118
        content = (self.error_message_format %
 
 
119
                   {'code': code, 'message': message})
 
 
120
        self.send_response(code, message)
 
 
121
        self.send_header("Content-Type", self.error_content_type)
 
 
122
        self.send_header("Content-Length", "%d" % len(content))
 
 
123
        self.send_header('Connection', 'close')
 
 
125
        if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
 
 
126
            self.wfile.write(content)
 
 
128
    def _handle_one_request(self):
 
 
129
        SimpleHTTPServer.SimpleHTTPRequestHandler.handle_one_request(self)
 
 
131
    _range_regexp = re.compile(r'^(?P<start>\d+)-(?P<end>\d+)?$')
 
93
132
    _tail_regexp = re.compile(r'^-(?P<tail>\d+)$')
 
95
 
    def parse_ranges(self, ranges_header):
 
96
 
        """Parse the range header value and returns ranges and tail.
 
98
 
        RFC2616 14.35 says that syntactically invalid range
 
99
 
        specifiers MUST be ignored. In that case, we return 0 for
 
100
 
        tail and [] for ranges.
 
 
134
    def _parse_ranges(self, ranges_header, file_size):
 
 
135
        """Parse the range header value and returns ranges.
 
 
137
        RFC2616 14.35 says that syntactically invalid range specifiers MUST be
 
 
138
        ignored. In that case, we return None instead of a range list.
 
 
140
        :param ranges_header: The 'Range' header value.
 
 
142
        :param file_size: The size of the requested file.
 
 
144
        :return: A list of (start, end) tuples or None if some invalid range
 
 
145
            specifier is encountered.
 
104
147
        if not ranges_header.startswith('bytes='):
 
105
148
            # Syntactically invalid header
 
108
153
        ranges_header = ranges_header[len('bytes='):]
 
109
154
        for range_str in ranges_header.split(','):
 
110
 
            # FIXME: RFC2616 says end is optional and default to file_size
 
111
155
            range_match = self._range_regexp.match(range_str)
 
112
156
            if range_match is not None:
 
113
157
                start = int(range_match.group('start'))
 
114
 
                end = int(range_match.group('end'))
 
 
158
                end_match = range_match.group('end')
 
 
159
                if end_match is None:
 
 
160
                    # RFC2616 says end is optional and default to file_size
 
116
165
                    # Syntactically invalid range
 
118
167
                ranges.append((start, end))
 
120
169
                tail_match = self._tail_regexp.match(range_str)
 
 
122
171
                    tail = int(tail_match.group('tail'))
 
124
173
                    # Syntactically invalid range
 
 
176
            # Normalize tail into ranges
 
 
177
            ranges.append((max(0, file_size - tail), file_size))
 
 
180
        for start, end in ranges:
 
 
181
            if start >= file_size:
 
 
182
                # RFC2616 14.35, ranges are invalid if start >= file_size
 
 
184
            # RFC2616 14.35, end values should be truncated
 
 
185
            # to file_size -1 if they exceed it
 
 
186
            end = min(end, file_size - 1)
 
 
187
            checked_ranges.append((start, end))
 
 
188
        return checked_ranges
 
128
190
    def _header_line_length(self, keyword, value):
 
129
191
        header_line = '%s: %s\r\n' % (keyword, value)
 
 
213
275
            # mode may cause newline translations, making the
 
214
276
            # actual size of the content transmitted *less* than
 
215
277
            # the content-length!
 
216
 
            file = open(path, 'rb')
 
218
280
            self.send_error(404, "File not found")
 
221
 
        file_size = os.fstat(file.fileno())[6]
 
222
 
        tail, ranges = self.parse_ranges(ranges_header_value)
 
223
 
        # Normalize tail into ranges
 
225
 
            ranges.append((file_size - tail, file_size))
 
227
 
        self._satisfiable_ranges = True
 
229
 
            self._satisfiable_ranges = False
 
231
 
            def check_range(range_specifier):
 
232
 
                start, end = range_specifier
 
233
 
                # RFC2616 14.35, ranges are invalid if start >= file_size
 
234
 
                if start >= file_size:
 
235
 
                    self._satisfiable_ranges = False # Side-effect !
 
237
 
                # RFC2616 14.35, end values should be truncated
 
238
 
                # to file_size -1 if they exceed it
 
239
 
                end = min(end, file_size - 1)
 
242
 
            ranges = map(check_range, ranges)
 
244
 
        if not self._satisfiable_ranges:
 
 
283
        file_size = os.fstat(f.fileno())[6]
 
 
284
        ranges = self._parse_ranges(ranges_header_value, file_size)
 
245
286
            # RFC2616 14.16 and 14.35 says that when a server
 
246
287
            # encounters unsatisfiable range specifiers, it
 
247
288
            # SHOULD return a 416.
 
249
290
            # FIXME: We SHOULD send a Content-Range header too,
 
250
291
            # but the implementation of send_error does not
 
251
292
            # allows that. So far.
 
 
319
360
        self.test_case_server = test_case_server
 
320
361
        self._home_dir = test_case_server._home_dir
 
322
 
    def stop_server(self):
 
323
 
         """Called to clean-up the server.
 
325
 
         Since the server may be (surely is, even) in a blocking listen, we
 
326
 
         shutdown its socket before closing it.
 
328
 
         # Note that is this executed as part of the implicit tear down in the
 
329
 
         # main thread while the server runs in its own thread. The clean way
 
330
 
         # to tear down the server is to instruct him to stop accepting
 
331
 
         # connections and wait for the current connection(s) to end
 
332
 
         # naturally. To end the connection naturally, the http transports
 
333
 
         # should close their socket when they do not need to talk to the
 
334
 
         # server anymore. This happens naturally during the garbage collection
 
335
 
         # phase of the test transport objetcs (the server clients), so we
 
336
 
         # don't have to worry about them.  So, for the server, we must tear
 
337
 
         # down here, from the main thread, when the test have ended.  Note
 
338
 
         # that since the server is in a blocking operation and since python
 
339
 
         # use select internally, shutting down the socket is reliable and
 
342
 
             self.socket.shutdown(socket.SHUT_RDWR)
 
343
 
         except socket.error, e:
 
344
 
             # WSAENOTCONN (10057) 'Socket is not connected' is harmless on
 
345
 
             # windows (occurs before the first connection attempt
 
348
 
             # 'Socket is not connected' can also occur on OSX, with a
 
349
 
             # "regular" ENOTCONN (when something went wrong during test case
 
350
 
             # setup leading to self.setUp() *not* being called but
 
351
 
             # self.stop_server() still being called -- vila20081106
 
352
 
             if not len(e.args) or e.args[0] not in (errno.ENOTCONN, 10057):
 
354
 
         # Let the server properly close the socket
 
358
 
class TestingHTTPServer(SocketServer.TCPServer, TestingHTTPServerMixin):
 
 
364
class TestingHTTPServer(test_server.TestingTCPServer, TestingHTTPServerMixin):
 
360
366
    def __init__(self, server_address, request_handler_class,
 
361
367
                 test_case_server):
 
 
368
        test_server.TestingTCPServer.__init__(self, server_address,
 
 
369
                                              request_handler_class)
 
362
370
        TestingHTTPServerMixin.__init__(self, test_case_server)
 
363
 
        SocketServer.TCPServer.__init__(self, server_address,
 
364
 
                                        request_handler_class)
 
367
 
class TestingThreadingHTTPServer(SocketServer.ThreadingTCPServer,
 
 
373
class TestingThreadingHTTPServer(test_server.TestingThreadingTCPServer,
 
368
374
                                 TestingHTTPServerMixin):
 
369
375
    """A threading HTTP test server for HTTP 1.1.
 
 
372
378
    server, we need an independent connection for each of them. We achieve that
 
373
379
    by spawning a new thread for each connection.
 
376
381
    def __init__(self, server_address, request_handler_class,
 
377
382
                 test_case_server):
 
 
383
        test_server.TestingThreadingTCPServer.__init__(self, server_address,
 
 
384
                                                       request_handler_class)
 
378
385
        TestingHTTPServerMixin.__init__(self, test_case_server)
 
379
 
        SocketServer.ThreadingTCPServer.__init__(self, server_address,
 
380
 
                                                 request_handler_class)
 
381
 
        # Decides how threads will act upon termination of the main
 
382
 
        # process. This is prophylactic as we should not leave the threads
 
384
 
        self.daemon_threads = True
 
386
 
    def process_request_thread(self, request, client_address):
 
387
 
        SocketServer.ThreadingTCPServer.process_request_thread(
 
388
 
            self, request, client_address)
 
389
 
        # Under some circumstances (as in bug #383920), we need to force the
 
390
 
        # shutdown as python delays it until gc occur otherwise and the client
 
393
 
            # The request process has been completed, the thread is about to
 
394
 
            # die, let's shutdown the socket if we can.
 
395
 
            request.shutdown(socket.SHUT_RDWR)
 
396
 
        except (socket.error, select.error), e:
 
397
 
            if e[0] in (errno.EBADF, errno.ENOTCONN):
 
398
 
                # Right, the socket is already down
 
404
 
class HttpServer(transport.Server):
 
 
388
class HttpServer(test_server.TestingTCPServerInAThread):
 
405
389
    """A test server for http transports.
 
407
391
    Subclasses can provide a specific request handler.
 
 
429
413
        :param protocol_version: if specified, will override the protocol
 
430
414
            version of the request handler.
 
432
 
        transport.Server.__init__(self)
 
433
 
        self.request_handler = request_handler
 
 
416
        # Depending on the protocol version, we will create the approriate
 
 
418
        if protocol_version is None:
 
 
419
            # Use the request handler one
 
 
420
            proto_vers = request_handler.protocol_version
 
 
422
            # Use our own, it will be used to override the request handler
 
 
424
            proto_vers = protocol_version
 
 
425
        # Get the appropriate server class for the required protocol
 
 
426
        serv_cls = self.http_server_class.get(proto_vers, None)
 
 
428
            raise httplib.UnknownProtocol(proto_vers)
 
434
429
        self.host = 'localhost'
 
437
 
        self.protocol_version = protocol_version
 
 
431
        super(HttpServer, self).__init__((self.host, self.port),
 
 
434
        self.protocol_version = proto_vers
 
438
435
        # Allows tests to verify number of GET requests issued
 
439
436
        self.GET_request_nb = 0
 
441
 
    def create_httpd(self, serv_cls, rhandler_cls):
 
442
 
        return serv_cls((self.host, self.port), self.request_handler, self)
 
445
 
        return "%s(%s:%s)" % \
 
446
 
            (self.__class__.__name__, self.host, self.port)
 
448
 
    def _get_httpd(self):
 
449
 
        if self._httpd is None:
 
450
 
            rhandler = self.request_handler
 
451
 
            # Depending on the protocol version, we will create the approriate
 
453
 
            if self.protocol_version is None:
 
454
 
                # Use the request handler one
 
455
 
                proto_vers = rhandler.protocol_version
 
457
 
                # Use our own, it will be used to override the request handler
 
459
 
                proto_vers = self.protocol_version
 
460
 
            # Create the appropriate server for the required protocol
 
461
 
            serv_cls = self.http_server_class.get(proto_vers, None)
 
463
 
                raise httplib.UnknownProtocol(proto_vers)
 
465
 
                self._httpd = self.create_httpd(serv_cls, rhandler)
 
466
 
            self.host, self.port = self._httpd.socket.getsockname()
 
469
 
    def _http_start(self):
 
470
 
        """Server thread main entry point. """
 
471
 
        self._http_running = False
 
474
 
                httpd = self._get_httpd()
 
475
 
                self._http_base_url = '%s://%s:%s/' % (self._url_protocol,
 
476
 
                                                       self.host, self.port)
 
477
 
                self._http_running = True
 
479
 
                # Whatever goes wrong, we save the exception for the main
 
480
 
                # thread. Note that since we are running in a thread, no signal
 
481
 
                # can be received, so we don't care about KeyboardInterrupt.
 
482
 
                self._http_exception = sys.exc_info()
 
484
 
            # Release the lock or the main thread will block and the whole
 
486
 
            self._http_starting.release()
 
488
 
        # From now on, exceptions are taken care of by the
 
489
 
        # SocketServer.BaseServer or the request handler.
 
490
 
        while self._http_running:
 
492
 
                # Really an HTTP connection but the python framework is generic
 
493
 
                # and call them requests
 
494
 
                httpd.handle_request()
 
495
 
            except socket.timeout:
 
497
 
            except (socket.error, select.error), e:
 
498
 
                if (e[0] == errno.EBADF
 
499
 
                    or (sys.platform == 'win32' and e[0] == 10038)):
 
500
 
                    # Starting with python-2.6, handle_request may raise socket
 
501
 
                    # or select exceptions when the server is shut down (as we
 
503
 
                    # 10038 = WSAENOTSOCK
 
504
 
                    # http://msdn.microsoft.com/en-us/library/ms740668%28VS.85%29.aspx
 
 
437
        self._http_base_url = None
 
 
440
    def create_server(self):
 
 
441
        return self.server_class(
 
 
442
            (self.host, self.port), self.request_handler_class, self)
 
509
444
    def _get_remote_url(self, path):
 
510
445
        path_parts = path.split(os.path.sep)
 
 
535
470
                or isinstance(backing_transport_server,
 
536
471
                              test_server.LocalURLServer)):
 
537
472
            raise AssertionError(
 
538
 
                "HTTPServer currently assumes local transport, got %s" % \
 
 
473
                "HTTPServer currently assumes local transport, got %s" %
 
539
474
                backing_transport_server)
 
540
475
        self._home_dir = os.getcwdu()
 
541
476
        self._local_path_parts = self._home_dir.split(os.path.sep)
 
542
 
        self._http_base_url = None
 
544
 
        # Create the server thread
 
545
 
        self._http_starting = threading.Lock()
 
546
 
        self._http_starting.acquire()
 
547
 
        self._http_thread = threading.Thread(target=self._http_start)
 
548
 
        self._http_thread.setDaemon(True)
 
549
 
        self._http_exception = None
 
550
 
        self._http_thread.start()
 
552
 
        # Wait for the server thread to start (i.e release the lock)
 
553
 
        self._http_starting.acquire()
 
555
 
        if self._http_exception is not None:
 
556
 
            # Something went wrong during server start
 
557
 
            exc_class, exc_value, exc_tb = self._http_exception
 
558
 
            raise exc_class, exc_value, exc_tb
 
559
 
        self._http_starting.release()
 
562
 
    def stop_server(self):
 
563
 
        self._httpd.stop_server()
 
564
 
        self._http_running = False
 
565
 
        # We don't need to 'self._http_thread.join()' here since the thread is
 
566
 
        # a daemonic one and will be garbage collected anyway. Joining just
 
567
 
        # slows us down for no added benefit.
 
 
479
        super(HttpServer, self).start_server()
 
 
480
        self._http_base_url = '%s://%s:%s/' % (
 
 
481
            self._url_protocol, self.host, self.port)
 
569
483
    def get_url(self):
 
570
484
        """See bzrlib.transport.Server.get_url."""