~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/http_server.py

  • Committer: Vincent Ladeuil
  • Date: 2008-09-11 19:36:38 UTC
  • mfrom: (3703 +trunk)
  • mto: (3705.1.1 trunk2)
  • mto: This revision was merged to the branch mainline in revision 3708.
  • Revision ID: v.ladeuil+lp@free.fr-20080911193638-wtjyc1kcmacc6t1f
merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 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
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
import errno
18
18
import httplib
20
20
import posixpath
21
21
import random
22
22
import re
23
 
import select
24
23
import SimpleHTTPServer
25
24
import socket
26
25
import SocketServer
31
30
import urlparse
32
31
 
33
32
from bzrlib import transport
34
 
from bzrlib.tests import test_server
35
33
from bzrlib.transport import local
36
34
 
37
35
 
 
36
class WebserverNotAvailable(Exception):
 
37
    pass
 
38
 
 
39
 
38
40
class BadWebserverPath(ValueError):
39
41
    def __str__(self):
40
42
        return 'path %s is not in %s' % self.args
138
140
            # common)
139
141
            self.send_response(301)
140
142
            self.send_header("Location", self.path + "/")
141
 
            # Indicates that the body is empty for HTTP/1.1 clients
 
143
            # Indicates that the body is empty for HTTP/1.1 clients 
142
144
            self.send_header('Content-Length', '0')
143
145
            self.end_headers()
144
146
            return None
178
180
            content_length += self._header_line_length(
179
181
                'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
180
182
            content_length += len('\r\n') # end headers
181
 
            content_length += end - start + 1
 
183
            content_length += end - start # + 1
182
184
        content_length += len(boundary_line)
183
185
        self.send_header('Content-length', content_length)
184
186
        self.end_headers()
319
321
        self.test_case_server = test_case_server
320
322
        self._home_dir = test_case_server._home_dir
321
323
 
322
 
    def stop_server(self):
 
324
    def tearDown(self):
323
325
         """Called to clean-up the server.
324
 
 
 
326
 
325
327
         Since the server may be (surely is, even) in a blocking listen, we
326
328
         shutdown its socket before closing it.
327
329
         """
344
346
             # WSAENOTCONN (10057) 'Socket is not connected' is harmless on
345
347
             # windows (occurs before the first connection attempt
346
348
             # vila--20071230)
347
 
 
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):
 
349
             if not len(e.args) or e.args[0] != 10057:
353
350
                 raise
354
351
         # Let the server properly close the socket
355
352
         self.server_close()
383
380
        # lying around.
384
381
        self.daemon_threads = True
385
382
 
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
391
 
        # may hang.
392
 
        try:
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
399
 
                pass
400
 
            else:
401
 
                raise
402
 
 
403
383
 
404
384
class HttpServer(transport.Server):
405
385
    """A test server for http transports.
438
418
        # Allows tests to verify number of GET requests issued
439
419
        self.GET_request_nb = 0
440
420
 
441
 
    def create_httpd(self, serv_cls, rhandler_cls):
442
 
        return serv_cls((self.host, self.port), self.request_handler, self)
443
 
 
444
 
    def __repr__(self):
445
 
        return "%s(%s:%s)" % \
446
 
            (self.__class__.__name__, self.host, self.port)
447
 
 
448
421
    def _get_httpd(self):
449
422
        if self._httpd is None:
450
423
            rhandler = self.request_handler
462
435
            if serv_cls is None:
463
436
                raise httplib.UnknownProtocol(proto_vers)
464
437
            else:
465
 
                self._httpd = self.create_httpd(serv_cls, rhandler)
466
 
            self.host, self.port = self._httpd.socket.getsockname()
 
438
                self._httpd = serv_cls((self.host, self.port), rhandler, self)
 
439
            host, self.port = self._httpd.socket.getsockname()
467
440
        return self._httpd
468
441
 
469
442
    def _http_start(self):
494
467
                httpd.handle_request()
495
468
            except socket.timeout:
496
469
                pass
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
502
 
                    # do).
503
 
                    # 10038 = WSAENOTSOCK
504
 
                    # http://msdn.microsoft.com/en-us/library/ms740668%28VS.85%29.aspx
505
 
                    pass
506
 
                else:
507
 
                    raise
508
470
 
509
471
    def _get_remote_url(self, path):
510
472
        path_parts = path.split(os.path.sep)
522
484
        """Capture Server log output."""
523
485
        self.logs.append(format % args)
524
486
 
525
 
    def start_server(self, backing_transport_server=None):
526
 
        """See bzrlib.transport.Server.start_server.
527
 
 
 
487
    def setUp(self, backing_transport_server=None):
 
488
        """See bzrlib.transport.Server.setUp.
 
489
        
528
490
        :param backing_transport_server: The transport that requests over this
529
491
            protocol should be forwarded to. Note that this is currently not
530
492
            supported for HTTP.
531
493
        """
532
494
        # XXX: TODO: make the server back onto vfs_server rather than local
533
495
        # disk.
534
 
        if not (backing_transport_server is None
535
 
                or isinstance(backing_transport_server,
536
 
                              test_server.LocalURLServer)):
 
496
        if not (backing_transport_server is None or \
 
497
                isinstance(backing_transport_server, local.LocalURLServer)):
537
498
            raise AssertionError(
538
499
                "HTTPServer currently assumes local transport, got %s" % \
539
500
                backing_transport_server)
559
520
        self._http_starting.release()
560
521
        self.logs = []
561
522
 
562
 
    def stop_server(self):
563
 
        self._httpd.stop_server()
 
523
    def tearDown(self):
 
524
        """See bzrlib.transport.Server.tearDown."""
 
525
        self._httpd.tearDown()
564
526
        self._http_running = False
565
527
        # We don't need to 'self._http_thread.join()' here since the thread is
566
528
        # a daemonic one and will be garbage collected anyway. Joining just