147
147
def test_content_type_re(self):
148
148
self.regex = response.HttpMultipartRangeResponse._CONTENT_TYPE_RE
149
self.assertRegexMatches(('xxyyzz',),
149
self.assertRegexMatches(('', 'xxyyzz'),
150
150
'multipart/byteranges; boundary = xxyyzz')
151
self.assertRegexMatches(('xxyyzz',),
151
self.assertRegexMatches(('', 'xxyyzz'),
152
152
'multipart/byteranges;boundary=xxyyzz')
153
self.assertRegexMatches(('xx yy zz',),
153
self.assertRegexMatches(('', 'xx yy zz'),
154
154
' multipart/byteranges ; boundary= xx yy zz ')
155
self.assertRegexMatches(('"', 'xx yy zz'),
156
' multipart/byteranges ; boundary= "xx yy zz" ')
157
self.assertEqual(None,
159
' multipart/byteranges ; boundary= "xx yy zz '))
160
self.assertEqual(None,
162
' multipart/byteranges ; boundary= xx yy zz" '))
155
163
self.assertEqual(None,
156
164
self.regex.match('multipart byteranges;boundary=xx'))
389
397
mbp@sourcefrog.net-20050314025737-55eb441f430ab4ba
390
398
mbp@sourcefrog.net-20050314025901-d74aa93bb7ee8f62
392
--418470f848b63279b--\r\n'
400
--418470f848b63279b--\r
403
_multipart_squid_range_response = (206, """HTTP/1.0 206 Partial Content\r
404
Date: Thu, 31 Aug 2006 21:16:22 GMT\r
405
Server: Apache/2.2.2 (Unix) DAV/2\r
406
Last-Modified: Thu, 31 Aug 2006 17:57:06 GMT\r
407
Accept-Ranges: bytes\r
408
Content-Type: multipart/byteranges; boundary="squid/2.5.STABLE12:C99323425AD4FE26F726261FA6C24196"\r
409
Content-Length: 598\r
410
X-Cache: MISS from localhost.localdomain\r
411
X-Cache-Lookup: HIT from localhost.localdomain:3128\r
412
Proxy-Connection: keep-alive\r
416
--squid/2.5.STABLE12:C99323425AD4FE26F726261FA6C24196\r
417
Content-Type: text/plain\r
418
Content-Range: bytes 0-99/18672\r
422
scott@netsplit.com-20050708230047-47c7868f276b939f fulltext 0 863 :
424
--squid/2.5.STABLE12:C99323425AD4FE26F726261FA6C24196\r
425
Content-Type: text/plain\r
426
Content-Range: bytes 300-499/18672\r
428
com-20050708231537-2b124b835395399a :
429
scott@netsplit.com-20050820234126-551311dbb7435b51 line-delta 1803 479 .scott@netsplit.com-20050820232911-dc4322a084eadf7e :
430
scott@netsplit.com-20050821213706-c86\r
431
--squid/2.5.STABLE12:C99323425AD4FE26F726261FA6C24196--\r
435
_redirect_response = (206, """HTTP/1.1 301 Moved Permanently\r
436
Date: Tue, 18 Jul 2006 20:29:22 GMT\r
437
Server: Apache/2.0.54 (Ubuntu) PHP/4.4.0-3ubuntu1 mod_ssl/2.0.54 OpenSSL/0.9.7g\r
438
Location: http://bazaar-vcs.org/bzr/bzr.dev/.bzr/repository/inventory.knit\r
439
Content-Length: 272\r
440
Keep-Alive: timeout=15, max=100\r
441
Connection: Keep-Alive\r
442
Content-Type: text/html; charset=iso-8859-1\r
444
HTTP/1.1 206 Partial Content\r
445
Date: Tue, 18 Jul 2006 20:29:23 GMT\r
446
Server: Apache/2.0.54 (Ubuntu) PHP/4.4.0-3ubuntu1 mod_ssl/2.0.54 OpenSSL/0.9.7g\r
447
Last-Modified: Tue, 18 Jul 2006 20:24:59 GMT\r
448
ETag: "be8213-83958c-f0d3dcc0"\r
449
Accept-Ranges: bytes\r
450
Content-Length: 425\r
451
Content-Range: bytes 8623075-8623499/8623500\r
452
Keep-Alive: timeout=15, max=100\r
453
Connection: Keep-Alive\r
454
Content-Type: text/plain; charset=UTF-8\r
456
""", """this data intentionally removed,
457
this is not meant to be tested by
458
handle_response, just _extract_headers
449
515
self.check_header('Content-Type',
450
516
'multipart/byteranges; boundary=418470f848b63279b')
454
def parse_response(response):
455
"""Turn one of the static HTTP responses into an in-flight response."""
456
resp = StringIO(response)
457
http_response = resp.readline()
458
assert http_response.startswith('HTTP/1.1 ')
518
def test_multi_squid_range(self):
519
self.use_response(_multipart_squid_range_response)
521
self.check_header('Content-Length', '598')
522
self.check_header('Content-Type',
523
'multipart/byteranges; '\
524
'boundary="squid/2.5.STABLE12:C99323425AD4FE26F726261FA6C24196"')
526
def test_redirect(self):
527
"""We default to returning the last group of headers in the file."""
528
self.use_response(_redirect_response)
529
self.check_header('Content-Range', 'bytes 8623075-8623499/8623500')
530
self.check_header('Content-Type', 'text/plain; charset=UTF-8')
532
def test_empty(self):
533
self.assertRaises(errors.InvalidHttpResponse,
534
http._extract_headers, '', 'bad url')
536
def test_no_opening_http(self):
537
# Remove the HTTP line from the header
538
first, txt = _full_text_response[1].split('\r\n', 1)
539
self.assertRaises(errors.InvalidHttpResponse,
540
http._extract_headers, txt, 'missing HTTTP')
542
def test_trailing_whitespace(self):
543
# Test that we ignore bogus whitespace on the end
544
code, txt, body = _full_text_response
545
txt += '\r\n\n\n\n\n'
546
self.use_response((code, txt, body))
548
self.check_header('Date', 'Tue, 11 Jul 2006 04:32:56 GMT')
549
self.check_header('Content-Length', '35')
550
self.check_header('Content-Type', 'text/plain; charset=UTF-8')
552
def test_trailing_non_http(self):
553
# Test that we ignore bogus stuff on the end
554
code, txt, body = _full_text_response
555
txt = txt + 'Foo: Bar\r\nBaz: Bling\r\n\r\n'
556
self.use_response((code, txt, body))
558
self.check_header('Date', 'Tue, 11 Jul 2006 04:32:56 GMT')
559
self.check_header('Content-Length', '35')
560
self.check_header('Content-Type', 'text/plain; charset=UTF-8')
561
self.assertRaises(KeyError, self.headers.__getitem__, 'Foo')
563
def test_extra_whitespace(self):
564
# Test that we read an HTTP response, even with extra whitespace
565
code, txt, body = _redirect_response
566
# Find the second HTTP location
567
loc = txt.find('HTTP', 5)
568
txt = txt[:loc] + '\r\n\n' + txt[loc:]
569
self.use_response((code, txt, body))
570
self.check_header('Content-Range', 'bytes 8623075-8623499/8623500')
571
self.check_header('Content-Type', 'text/plain; charset=UTF-8')
460
574
class TestHandleResponse(TestCase):
462
576
def get_response(self, a_response):
463
577
"""Process a supplied response, and return the result."""
464
headers = http._extract_headers(StringIO(a_response[1]))
578
headers = http._extract_headers(a_response[1], 'http://foo')
465
579
return response.handle_response('http://foo', a_response[0], headers,
466
580
StringIO(a_response[2]))