~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/http.py

  • Committer: Martin Pool
  • Date: 2006-02-22 04:29:54 UTC
  • mfrom: (1566 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1569.
  • Revision ID: mbp@sourcefrog.net-20060222042954-60333f08dd56a646
[merge] from bzr.dev before integration
Fix undefined ordering in sign_my_revisions breaking tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
import urlparse
23
23
from warnings import warn
24
24
 
 
25
import bzrlib
25
26
from bzrlib.transport import Transport, Server
26
27
from bzrlib.errors import (TransportNotPossible, NoSuchFile, 
27
28
                           TransportError, ConnectionError)
28
29
from bzrlib.errors import BzrError, BzrCheckError
29
30
from bzrlib.branch import Branch
30
31
from bzrlib.trace import mutter
 
32
from bzrlib.ui import ui_factory
31
33
 
32
34
 
33
35
def extract_auth(url, password_manager):
36
38
    password manager.  Return the url, minus those auth parameters (which
37
39
    confuse urllib2).
38
40
    """
39
 
    assert url.startswith('http://') or url.startswith('https://')
40
 
    scheme, host = url.split('//', 1)
41
 
    if '/' in host:
42
 
        host, path = host.split('/', 1)
43
 
        path = '/' + path
44
 
    else:
45
 
        path = ''
46
 
    port = ''
47
 
    if '@' in host:
48
 
        auth, host = host.split('@', 1)
 
41
    scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
 
42
    assert (scheme == 'http') or (scheme == 'https')
 
43
    
 
44
    if '@' in netloc:
 
45
        auth, netloc = netloc.split('@', 1)
49
46
        if ':' in auth:
50
47
            username, password = auth.split(':', 1)
51
48
        else:
52
49
            username, password = auth, None
53
 
        if ':' in host:
54
 
            host, port = host.split(':', 1)
55
 
            port = ':' + port
56
 
        # FIXME: if password isn't given, should we ask for it?
 
50
        if ':' in netloc:
 
51
            host = netloc.split(':', 1)[0]
 
52
        else:
 
53
            host = netloc
 
54
        username = urllib.unquote(username)
57
55
        if password is not None:
58
 
            username = urllib.unquote(username)
59
56
            password = urllib.unquote(password)
60
 
            password_manager.add_password(None, host, username, password)
61
 
    url = scheme + '//' + host + port + path
 
57
        else:
 
58
            password = ui_factory.get_password(prompt='HTTP %(user)@%(host) password',
 
59
                                               user=username, host=host)
 
60
        password_manager.add_password(None, host, username, password)
 
61
    url = urlparse.urlunsplit((scheme, netloc, path, query, fragment))
62
62
    return url
63
 
    
64
 
def get_url(url):
 
63
 
 
64
 
 
65
class Request(urllib2.Request):
 
66
    """Request object for urllib2 that allows the method to be overridden."""
 
67
 
 
68
    method = None
 
69
 
 
70
    def get_method(self):
 
71
        if self.method is not None:
 
72
            return self.method
 
73
        else:
 
74
            return urllib2.Request.get_method(self)
 
75
 
 
76
 
 
77
def get_url(url, method=None):
65
78
    import urllib2
66
 
    mutter("get_url %s" % url)
 
79
    mutter("get_url %s", url)
67
80
    manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
68
81
    url = extract_auth(url, manager)
69
82
    auth_handler = urllib2.HTTPBasicAuthHandler(manager)
70
83
    opener = urllib2.build_opener(auth_handler)
71
 
    url_f = opener.open(url)
72
 
    return url_f
 
84
 
 
85
    request = Request(url)
 
86
    request.method = method
 
87
    request.add_header('User-Agent', 'bzr/%s' % bzrlib.__version__)
 
88
    response = opener.open(request)
 
89
    return response
 
90
 
73
91
 
74
92
class HttpTransport(Transport):
75
93
    """This is the transport agent for http:// access.
146
164
    def has(self, relpath):
147
165
        """Does the target location exist?
148
166
 
149
 
        TODO: HttpTransport.has() should use a HEAD request,
150
 
        not a full GET request.
151
 
 
152
167
        TODO: This should be changed so that we don't use
153
168
        urllib2 and get an exception, the code path would be
154
169
        cleaner if we just do an http HEAD request, and parse
157
172
        path = relpath
158
173
        try:
159
174
            path = self.abspath(relpath)
160
 
            f = get_url(path)
 
175
            f = get_url(path, method='HEAD')
161
176
            # Without the read and then close()
162
177
            # we tend to have busy sockets.
163
178
            f.read()
301
316
class TestingHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
302
317
 
303
318
    def log_message(self, format, *args):
304
 
        self.server.test_case.log("webserver - %s - - [%s] %s",
 
319
        self.server.test_case.log('webserver - %s - - [%s] %s "%s" "%s"',
305
320
                                  self.address_string(),
306
321
                                  self.log_date_time_string(),
307
 
                                  format%args)
 
322
                                  format % args,
 
323
                                  self.headers.get('referer', '-'),
 
324
                                  self.headers.get('user-agent', '-'))
308
325
 
309
326
    def handle_one_request(self):
310
327
        """Handle a single HTTP request.
340
357
        method = getattr(self, mname)
341
358
        method()
342
359
 
 
360
 
343
361
class TestingHTTPServer(BaseHTTPServer.HTTPServer):
344
362
    def __init__(self, server_address, RequestHandlerClass, test_case):
345
363
        BaseHTTPServer.HTTPServer.__init__(self, server_address,
350
368
class HttpServer(Server):
351
369
    """A test server for http transports."""
352
370
 
353
 
    _HTTP_PORTS = range(13000, 0x8000)
354
 
 
355
371
    def _http_start(self):
356
372
        httpd = None
357
 
        for port in self._HTTP_PORTS:
358
 
            try:
359
 
                httpd = TestingHTTPServer(('localhost', port),
360
 
                                          TestingHTTPRequestHandler,
361
 
                                          self)
362
 
            except socket.error, e:
363
 
                if e.args[0] == errno.EADDRINUSE:
364
 
                    continue
365
 
                print >>sys.stderr, "Cannot run webserver :-("
366
 
                raise
367
 
            else:
368
 
                break
369
 
 
370
 
        if httpd is None:
371
 
            raise WebserverNotAvailable("Cannot run webserver :-( "
372
 
                                        "no free ports in range %s..%s" %
373
 
                                        (_HTTP_PORTS[0], _HTTP_PORTS[-1]))
374
 
 
 
373
        httpd = TestingHTTPServer(('localhost', 0),
 
374
                                  TestingHTTPRequestHandler,
 
375
                                  self)
 
376
        host, port = httpd.socket.getsockname()
375
377
        self._http_base_url = 'http://localhost:%s/' % port
376
378
        self._http_starting.release()
377
379
        httpd.socket.settimeout(0.1)
396
398
        self._http_starting.release()
397
399
        return self._http_base_url + remote_path
398
400
 
399
 
    def log(self, *args, **kwargs):
 
401
    def log(self, format, *args):
400
402
        """Capture Server log output."""
401
 
        self.logs.append(args[3])
 
403
        self.logs.append(format % args)
402
404
 
403
405
    def setUp(self):
404
406
        """See bzrlib.transport.Server.setUp."""