224
226
self._thread = threading.Thread(target=self._accept_read_and_reply)
225
227
self._thread.setDaemon(True)
226
228
self._thread.start()
229
if 'threads' in tests.selftest_debug_flags:
230
print 'Thread started: %s' % (self._thread.ident,)
229
233
def _accept_read_and_reply(self):
230
234
self._sock.listen(1)
235
self._sock.settimeout(5)
231
236
self._ready.set()
232
self._sock.settimeout(5)
234
238
conn, address = self._sock.accept()
235
239
# On win32, the accepted connection will be non-blocking to start
236
240
# with because we're using settimeout.
237
241
conn.setblocking(True)
238
while not self.received_bytes.endswith(self._expect_body_tail):
239
self.received_bytes += conn.recv(4096)
240
conn.sendall('HTTP/1.1 200 OK\r\n')
242
if self._expect_body_tail is not None:
243
while not self.received_bytes.endswith(self._expect_body_tail):
244
self.received_bytes += conn.recv(4096)
245
conn.sendall('HTTP/1.1 200 OK\r\n')
241
246
except socket.timeout:
242
247
# Make sure the client isn't stuck waiting for us to e.g. accept.
243
250
self._sock.close()
244
251
except socket.error:
245
252
# The client may have already closed the socket.
255
def connect_socket(self):
256
err = socket.error('getaddrinfo returns an empty list')
257
for res in socket.getaddrinfo(self.host, self.port):
258
af, socktype, proto, canonname, sa = res
261
sock = socket.socket(af, socktype, proto)
265
except socket.error, err:
266
# err is now the most recent error
271
def stop_server(self):
273
# Issue a fake connection to wake up the server and allow it to
275
fake_conn = self.connect_socket()
251
277
except socket.error:
252
278
# We might have already closed it. We don't care.
283
if 'threads' in tests.selftest_debug_flags:
284
print 'Thread joined: %s' % (self._thread.ident,)
258
287
class TestAuthHeader(tests.TestCase):
266
295
def test_empty_header(self):
267
296
scheme, remainder = self.parse_header('')
268
self.assertEquals('', scheme)
297
self.assertEqual('', scheme)
269
298
self.assertIs(None, remainder)
271
300
def test_negotiate_header(self):
272
301
scheme, remainder = self.parse_header('Negotiate')
273
self.assertEquals('negotiate', scheme)
302
self.assertEqual('negotiate', scheme)
274
303
self.assertIs(None, remainder)
276
305
def test_basic_header(self):
277
306
scheme, remainder = self.parse_header(
278
307
'Basic realm="Thou should not pass"')
279
self.assertEquals('basic', scheme)
280
self.assertEquals('realm="Thou should not pass"', remainder)
308
self.assertEqual('basic', scheme)
309
self.assertEqual('realm="Thou should not pass"', remainder)
282
311
def test_basic_extract_realm(self):
283
312
scheme, remainder = self.parse_header(
305
334
server = http_server.HttpServer(BogusRequestHandler)
307
self.assertRaises(httplib.UnknownProtocol,server.setUp)
336
self.assertRaises(httplib.UnknownProtocol, server.start_server)
310
339
self.fail('HTTP Server creation did not raise UnknownProtocol')
312
341
def test_force_invalid_protocol(self):
313
342
server = http_server.HttpServer(protocol_version='HTTP/0.1')
315
self.assertRaises(httplib.UnknownProtocol,server.setUp)
344
self.assertRaises(httplib.UnknownProtocol, server.start_server)
318
347
self.fail('HTTP Server creation did not raise UnknownProtocol')
320
349
def test_server_start_and_stop(self):
321
350
server = http_server.HttpServer()
323
self.assertTrue(server._http_running)
325
self.assertFalse(server._http_running)
351
server.start_server()
353
self.assertTrue(server._httpd is not None)
354
self.assertTrue(server._httpd.serving is not None)
355
self.assertTrue(server._httpd.serving.isSet())
327
359
def test_create_http_server_one_zero(self):
328
360
class RequestHandlerOneZero(http_server.TestingHTTPRequestHandler):
391
416
def test_url_parsing(self):
392
417
f = FakeManager()
393
418
url = http.extract_auth('http://example.com', f)
394
self.assertEquals('http://example.com', url)
395
self.assertEquals(0, len(f.credentials))
419
self.assertEqual('http://example.com', url)
420
self.assertEqual(0, len(f.credentials))
396
421
url = http.extract_auth(
397
'http://user:pass@www.bazaar-vcs.org/bzr/bzr.dev', f)
398
self.assertEquals('http://www.bazaar-vcs.org/bzr/bzr.dev', url)
399
self.assertEquals(1, len(f.credentials))
400
self.assertEquals([None, 'www.bazaar-vcs.org', 'user', 'pass'],
422
'http://user:pass@example.com/bzr/bzr.dev', f)
423
self.assertEqual('http://example.com/bzr/bzr.dev', url)
424
self.assertEqual(1, len(f.credentials))
425
self.assertEqual([None, 'example.com', 'user', 'pass'],
404
429
class TestHttpTransportUrls(tests.TestCase):
451
476
https by supplying a fake version_info that do not
457
raise tests.TestSkipped('pycurl not present')
479
self.requireFeature(features.pycurl)
480
# Import the module locally now that we now it's available.
481
pycurl = features.pycurl.module
459
version_info_orig = pycurl.version_info
461
# Now that we have pycurl imported, we can fake its version_info
462
# This was taken from a windows pycurl without SSL
464
pycurl.version_info = lambda : (2,
472
('ftp', 'gopher', 'telnet',
473
'dict', 'ldap', 'http', 'file'),
477
self.assertRaises(errors.DependencyNotPresent, self._transport,
478
'https://launchpad.net')
480
# Restore the right function
481
pycurl.version_info = version_info_orig
483
self.overrideAttr(pycurl, 'version_info',
484
# Fake the pycurl version_info This was taken from
485
# a windows pycurl without SSL (thanks to bialix)
494
('ftp', 'gopher', 'telnet',
495
'dict', 'ldap', 'http', 'file'),
499
self.assertRaises(errors.DependencyNotPresent, self._transport,
500
'https://launchpad.net')
484
503
class TestHTTPConnections(http_utils.TestCaseWithWebserver):
764
787
self.assertEqual(None, server.host)
765
788
self.assertEqual(None, server.port)
767
def test_setUp_and_tearDown(self):
790
def test_setUp_and_stop(self):
768
791
server = RecordingServer(expect_body_tail=None)
792
server.start_server()
771
794
self.assertNotEqual(None, server.host)
772
795
self.assertNotEqual(None, server.port)
775
798
self.assertEqual(None, server.host)
776
799
self.assertEqual(None, server.port)
778
801
def test_send_receive_bytes(self):
779
server = RecordingServer(expect_body_tail='c')
781
self.addCleanup(server.tearDown)
802
server = RecordingServer(expect_body_tail='c', scheme='http')
803
self.start_server(server)
782
804
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
783
805
sock.connect((server.host, server.port))
784
806
sock.sendall('abc')
2094
2115
t = self.get_transport()
2095
2116
# We must send a single line of body bytes, see
2096
# PredefinedRequestHandler.handle_one_request
2117
# PredefinedRequestHandler._handle_one_request
2097
2118
code, f = t._post('abc def end-of-body\n')
2098
2119
self.assertEqual('lalala whatever as long as itsssss\n', f.read())
2099
2120
self.assertActivitiesMatch()
2123
class TestActivity(tests.TestCase, TestActivityMixin):
2126
tests.TestCase.setUp(self)
2127
self.server = self._activity_server(self._protocol_version)
2128
self.server.start_server()
2129
self.activities = {}
2130
def report_activity(t, bytes, direction):
2131
count = self.activities.get(direction, 0)
2133
self.activities[direction] = count
2135
# We override at class level because constructors may propagate the
2136
# bound method and render instance overriding ineffective (an
2137
# alternative would be to define a specific ui factory instead...)
2138
self.orig_report_activity = self._transport._report_activity
2139
self._transport._report_activity = report_activity
2142
self._transport._report_activity = self.orig_report_activity
2143
self.server.stop_server()
2144
tests.TestCase.tearDown(self)
2147
class TestNoReportActivity(tests.TestCase, TestActivityMixin):
2150
tests.TestCase.setUp(self)
2151
# Unlike TestActivity, we are really testing ReportingFileSocket and
2152
# ReportingSocket, so we don't need all the parametrization. Since
2153
# ReportingFileSocket and ReportingSocket are wrappers, it's easier to
2154
# test them through their use by the transport than directly (that's a
2155
# bit less clean but far more simpler and effective).
2156
self.server = ActivityHTTPServer('HTTP/1.1')
2157
self._transport=_urllib.HttpTransport_urllib
2159
self.server.start_server()
2161
# We override at class level because constructors may propagate the
2162
# bound method and render instance overriding ineffective (an
2163
# alternative would be to define a specific ui factory instead...)
2164
self.orig_report_activity = self._transport._report_activity
2165
self._transport._report_activity = None
2168
self._transport._report_activity = self.orig_report_activity
2169
self.server.stop_server()
2170
tests.TestCase.tearDown(self)
2172
def assertActivitiesMatch(self):
2173
# Nothing to check here
2177
class TestAuthOnRedirected(http_utils.TestCaseWithRedirectedWebserver):
2178
"""Test authentication on the redirected http server."""
2180
_auth_header = 'Authorization'
2181
_password_prompt_prefix = ''
2182
_username_prompt_prefix = ''
2183
_auth_server = http_utils.HTTPBasicAuthServer
2184
_transport = _urllib.HttpTransport_urllib
2186
def create_transport_readonly_server(self):
2187
return self._auth_server()
2189
def create_transport_secondary_server(self):
2190
"""Create the secondary server redirecting to the primary server"""
2191
new = self.get_readonly_server()
2193
redirecting = http_utils.HTTPServerRedirecting()
2194
redirecting.redirect_to(new.host, new.port)
2198
super(TestAuthOnRedirected, self).setUp()
2199
self.build_tree_contents([('a','a'),
2201
('1/a', 'redirected once'),
2203
new_prefix = 'http://%s:%s' % (self.new_server.host,
2204
self.new_server.port)
2205
self.old_server.redirections = [
2206
('(.*)', r'%s/1\1' % (new_prefix), 301),]
2207
self.old_transport = self._transport(self.old_server.get_url())
2208
self.new_server.add_user('joe', 'foo')
2210
def get_a(self, transport):
2211
return transport.get('a')
2213
def test_auth_on_redirected_via_do_catching_redirections(self):
2214
self.redirections = 0
2216
def redirected(transport, exception, redirection_notice):
2217
self.redirections += 1
2218
dir, file = urlutils.split(exception.target)
2219
return self._transport(dir)
2221
stdout = tests.StringIOWrapper()
2222
stderr = tests.StringIOWrapper()
2223
ui.ui_factory = tests.TestUIFactory(stdin='joe\nfoo\n',
2224
stdout=stdout, stderr=stderr)
2225
self.assertEqual('redirected once',
2226
transport.do_catching_redirections(
2227
self.get_a, self.old_transport, redirected).read())
2228
self.assertEqual(1, self.redirections)
2229
# stdin should be empty
2230
self.assertEqual('', ui.ui_factory.stdin.readline())
2231
# stdout should be empty, stderr will contains the prompts
2232
self.assertEqual('', stdout.getvalue())
2234
def test_auth_on_redirected_via_following_redirections(self):
2235
self.new_server.add_user('joe', 'foo')
2236
stdout = tests.StringIOWrapper()
2237
stderr = tests.StringIOWrapper()
2238
ui.ui_factory = tests.TestUIFactory(stdin='joe\nfoo\n',
2239
stdout=stdout, stderr=stderr)
2240
t = self.old_transport
2241
req = RedirectedRequest('GET', t.abspath('a'))
2242
new_prefix = 'http://%s:%s' % (self.new_server.host,
2243
self.new_server.port)
2244
self.old_server.redirections = [
2245
('(.*)', r'%s/1\1' % (new_prefix), 301),]
2246
self.assertEqual('redirected once',t._perform(req).read())
2247
# stdin should be empty
2248
self.assertEqual('', ui.ui_factory.stdin.readline())
2249
# stdout should be empty, stderr will contains the prompts
2250
self.assertEqual('', stdout.getvalue())