~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_http_response.py

  • Committer: John Arbash Meinel
  • Date: 2006-10-11 00:23:23 UTC
  • mfrom: (2070 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2071.
  • Revision ID: john@arbash-meinel.com-20061011002323-82ba88c293d7caff
[merge] bzr.dev 2070

Show diffs side-by-side

added added

removed removed

Lines of Context:
146
146
 
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,
 
158
                         self.regex.match(
 
159
                             ' multipart/byteranges ; boundary= "xx yy zz '))
 
160
        self.assertEqual(None,
 
161
                         self.regex.match(
 
162
                             ' multipart/byteranges ; boundary= xx yy zz" '))
155
163
        self.assertEqual(None,
156
164
                self.regex.match('multipart byteranges;boundary=xx'))
157
165
 
389
397
mbp@sourcefrog.net-20050314025737-55eb441f430ab4ba
390
398
mbp@sourcefrog.net-20050314025901-d74aa93bb7ee8f62
391
399
mbp@source\r
392
 
--418470f848b63279b--\r\n'
 
400
--418470f848b63279b--\r
 
401
""")
 
402
 
 
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
 
413
\r
 
414
""",
 
415
"""\r
 
416
--squid/2.5.STABLE12:C99323425AD4FE26F726261FA6C24196\r
 
417
Content-Type: text/plain\r
 
418
Content-Range: bytes 0-99/18672\r
 
419
\r
 
420
# bzr knit index 8
 
421
 
 
422
scott@netsplit.com-20050708230047-47c7868f276b939f fulltext 0 863  :
 
423
scott@netsp\r
 
424
--squid/2.5.STABLE12:C99323425AD4FE26F726261FA6C24196\r
 
425
Content-Type: text/plain\r
 
426
Content-Range: bytes 300-499/18672\r
 
427
\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
 
432
""")
 
433
 
 
434
 
 
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
 
443
\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
 
455
\r
 
456
""", """this data intentionally removed, 
 
457
this is not meant to be tested by
 
458
handle_response, just _extract_headers
393
459
""")
394
460
 
395
461
 
415
481
class TestExtractHeader(TestCase):
416
482
    
417
483
    def use_response(self, response):
418
 
        self.headers = http._extract_headers(StringIO(response[1]))
 
484
        self.headers = http._extract_headers(response[1], 'http://foo')
419
485
 
420
486
    def check_header(self, header, value):
421
487
        self.assertEqual(value, self.headers[header])
449
515
        self.check_header('Content-Type',
450
516
                          'multipart/byteranges; boundary=418470f848b63279b')
451
517
 
452
 
 
453
 
 
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)
 
520
 
 
521
        self.check_header('Content-Length', '598')
 
522
        self.check_header('Content-Type',
 
523
                          'multipart/byteranges; '\
 
524
                          'boundary="squid/2.5.STABLE12:C99323425AD4FE26F726261FA6C24196"')
 
525
 
 
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')
 
531
 
 
532
    def test_empty(self):
 
533
        self.assertRaises(errors.InvalidHttpResponse,
 
534
            http._extract_headers, '', 'bad url')
 
535
 
 
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')
 
541
 
 
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))
 
547
 
 
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')
 
551
 
 
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))
 
557
 
 
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')
 
562
 
 
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')
 
572
 
459
573
 
460
574
class TestHandleResponse(TestCase):
461
575
    
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]))
467
581
 
494
608
        out.seek(1000)
495
609
        out.read(1050)
496
610
 
 
611
    def test_multi_squid_range(self):
 
612
        out = self.get_response(_multipart_squid_range_response)
 
613
        self.assertIsInstance(out, response.HttpMultipartRangeResponse)
 
614
 
 
615
        # Just make sure we can read the right contents
 
616
        out.seek(0)
 
617
        out.read(100)
 
618
 
 
619
        out.seek(300)
 
620
        out.read(200)
 
621
 
497
622
    def test_invalid_response(self):
498
623
        self.assertRaises(errors.InvalidHttpResponse,
499
624
            self.get_response, _invalid_response)
501
626
    def test_full_text_no_content_type(self):
502
627
        # We should not require Content-Type for a full response
503
628
        a_response = _full_text_response
504
 
        headers = http._extract_headers(StringIO(a_response[1]))
 
629
        headers = http._extract_headers(a_response[1], 'http://foo')
505
630
        del headers['Content-Type']
506
631
        out = response.handle_response('http://foo', a_response[0], headers,
507
632
                                        StringIO(a_response[2]))
510
635
    def test_missing_no_content_type(self):
511
636
        # Without Content-Type we should still raise NoSuchFile on a 404
512
637
        a_response = _missing_response
513
 
        headers = http._extract_headers(StringIO(a_response[1]))
 
638
        headers = http._extract_headers(a_response[1], 'http://missing')
514
639
        del headers['Content-Type']
515
640
        self.assertRaises(errors.NoSuchFile,
516
641
            response.handle_response, 'http://missing', a_response[0], headers,
518
643
 
519
644
    def test_missing_content_type(self):
520
645
        a_response = _single_range_response
521
 
        headers = http._extract_headers(StringIO(a_response[1]))
 
646
        headers = http._extract_headers(a_response[1], 'http://nocontent')
522
647
        del headers['Content-Type']
523
648
        self.assertRaises(errors.InvalidHttpContentType,
524
649
            response.handle_response, 'http://nocontent', a_response[0],
526
651
 
527
652
    def test_missing_content_range(self):
528
653
        a_response = _single_range_response
529
 
        headers = http._extract_headers(StringIO(a_response[1]))
 
654
        headers = http._extract_headers(a_response[1], 'http://nocontent')
530
655
        del headers['Content-Range']
531
656
        self.assertRaises(errors.InvalidHttpResponse,
532
657
            response.handle_response, 'http://nocontent', a_response[0],