~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/http_server.py

  • Committer: Martin von Gagern
  • Date: 2010-04-20 08:47:38 UTC
  • mfrom: (5167 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5195.
  • Revision ID: martin.vgagern@gmx.net-20100420084738-ygymnqmdllzrhpfn
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006-2010 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import errno
18
18
import httplib
31
31
import urlparse
32
32
 
33
33
from bzrlib import transport
 
34
from bzrlib.tests import test_server
34
35
from bzrlib.transport import local
35
36
 
36
37
 
37
 
class WebserverNotAvailable(Exception):
38
 
    pass
39
 
 
40
 
 
41
38
class BadWebserverPath(ValueError):
42
39
    def __str__(self):
43
40
        return 'path %s is not in %s' % self.args
141
138
            # common)
142
139
            self.send_response(301)
143
140
            self.send_header("Location", self.path + "/")
144
 
            # Indicates that the body is empty for HTTP/1.1 clients 
 
141
            # Indicates that the body is empty for HTTP/1.1 clients
145
142
            self.send_header('Content-Length', '0')
146
143
            self.end_headers()
147
144
            return None
181
178
            content_length += self._header_line_length(
182
179
                'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
183
180
            content_length += len('\r\n') # end headers
184
 
            content_length += end - start # + 1
 
181
            content_length += end - start + 1
185
182
        content_length += len(boundary_line)
186
183
        self.send_header('Content-length', content_length)
187
184
        self.end_headers()
322
319
        self.test_case_server = test_case_server
323
320
        self._home_dir = test_case_server._home_dir
324
321
 
325
 
    def tearDown(self):
 
322
    def stop_server(self):
326
323
         """Called to clean-up the server.
327
 
 
 
324
 
328
325
         Since the server may be (surely is, even) in a blocking listen, we
329
326
         shutdown its socket before closing it.
330
327
         """
347
344
             # WSAENOTCONN (10057) 'Socket is not connected' is harmless on
348
345
             # windows (occurs before the first connection attempt
349
346
             # vila--20071230)
350
 
             if not len(e.args) or e.args[0] != 10057:
 
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):
351
353
                 raise
352
354
         # Let the server properly close the socket
353
355
         self.server_close()
381
383
        # lying around.
382
384
        self.daemon_threads = True
383
385
 
 
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
 
384
403
 
385
404
class HttpServer(transport.Server):
386
405
    """A test server for http transports.
419
438
        # Allows tests to verify number of GET requests issued
420
439
        self.GET_request_nb = 0
421
440
 
 
441
    def create_httpd(self, serv_cls, rhandler_cls):
 
442
        return serv_cls((self.host, self.port), self.request_handler, self)
 
443
 
422
444
    def __repr__(self):
423
445
        return "%s(%s:%s)" % \
424
446
            (self.__class__.__name__, self.host, self.port)
440
462
            if serv_cls is None:
441
463
                raise httplib.UnknownProtocol(proto_vers)
442
464
            else:
443
 
                self._httpd = serv_cls((self.host, self.port), rhandler, self)
444
 
            host, self.port = self._httpd.socket.getsockname()
 
465
                self._httpd = self.create_httpd(serv_cls, rhandler)
 
466
            self.host, self.port = self._httpd.socket.getsockname()
445
467
        return self._httpd
446
468
 
447
469
    def _http_start(self):
473
495
            except socket.timeout:
474
496
                pass
475
497
            except (socket.error, select.error), e:
476
 
               if e[0] == errno.EBADF:
477
 
                   # Starting with python-2.6, handle_request may raise socket
478
 
                   # or select exceptions when the server is shut down (as we
479
 
                   # do).
480
 
                   pass
481
 
               else:
482
 
                   raise
 
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
483
508
 
484
509
    def _get_remote_url(self, path):
485
510
        path_parts = path.split(os.path.sep)
497
522
        """Capture Server log output."""
498
523
        self.logs.append(format % args)
499
524
 
500
 
    def setUp(self, backing_transport_server=None):
501
 
        """See bzrlib.transport.Server.setUp.
502
 
        
 
525
    def start_server(self, backing_transport_server=None):
 
526
        """See bzrlib.transport.Server.start_server.
 
527
 
503
528
        :param backing_transport_server: The transport that requests over this
504
529
            protocol should be forwarded to. Note that this is currently not
505
530
            supported for HTTP.
506
531
        """
507
532
        # XXX: TODO: make the server back onto vfs_server rather than local
508
533
        # disk.
509
 
        if not (backing_transport_server is None or \
510
 
                isinstance(backing_transport_server, local.LocalURLServer)):
 
534
        if not (backing_transport_server is None
 
535
                or isinstance(backing_transport_server,
 
536
                              test_server.LocalURLServer)):
511
537
            raise AssertionError(
512
538
                "HTTPServer currently assumes local transport, got %s" % \
513
539
                backing_transport_server)
533
559
        self._http_starting.release()
534
560
        self.logs = []
535
561
 
536
 
    def tearDown(self):
537
 
        """See bzrlib.transport.Server.tearDown."""
538
 
        self._httpd.tearDown()
 
562
    def stop_server(self):
 
563
        self._httpd.stop_server()
539
564
        self._http_running = False
540
565
        # We don't need to 'self._http_thread.join()' here since the thread is
541
566
        # a daemonic one and will be garbage collected anyway. Joining just