1
from twisted.trial import unittest
4
from twisted.web2 import http_headers
5
from twisted.web2.http_headers import Cookie, HeaderHandler
6
from twisted.python import util
10
def __init__(self, raw):
13
def __eq__(self, other):
14
return isinstance(other, parsedvalue) and other.raw == self.raw
16
class HeadersAPITest(unittest.TestCase):
17
"""Make sure the public API exists and works."""
19
rawvalue = ("value1", "value2")
20
h = http_headers.Headers(handler=HeaderHandler(parsers={}, generators={}))
21
h.setRawHeaders("test", rawvalue)
22
self.assertEquals(h.hasHeader("test"), True)
23
self.assertEquals(h.getRawHeaders("test"), rawvalue)
24
self.assertEquals(list(h.getAllRawHeaders()), [('Test', rawvalue)])
26
self.assertEquals(h.getRawHeaders("foobar"), None)
27
h.removeHeader("test")
28
self.assertEquals(h.getRawHeaders("test"), None)
31
parsed = parsedvalue(("value1", "value2"))
32
h = http_headers.Headers(handler=HeaderHandler(parsers={}, generators={}))
34
h.setHeader("test", parsed)
35
self.assertEquals(h.hasHeader("test"), True)
36
self.assertEquals(h.getHeader("test"), parsed)
38
self.assertEquals(h.getHeader("foobar"), None)
39
h.removeHeader("test")
40
self.assertEquals(h.getHeader("test"), None)
42
def testParsedAndRaw(self):
44
return parsedvalue(raw)
49
rawvalue = ("value1", "value2")
50
rawvalue2 = ("value3", "value4")
51
handler = HeaderHandler(parsers={'test':(parse,)},
52
generators={'test':(generate,)})
54
h = http_headers.Headers(handler=handler)
55
h.setRawHeaders("test", rawvalue)
56
self.assertEquals(h.getHeader("test"), parsedvalue(rawvalue))
58
h.setHeader("test", parsedvalue(rawvalue2))
59
self.assertEquals(h.getRawHeaders("test"), rawvalue2)
61
# Check the initializers
62
h = http_headers.Headers(rawHeaders={"test": rawvalue},
64
self.assertEquals(h.getHeader("test"), parsedvalue(rawvalue))
66
h = http_headers.Headers({"test": parsedvalue(rawvalue2)},
68
self.assertEquals(h.getRawHeaders("test"), rawvalue2)
70
def testImmutable(self):
71
h = http_headers.Headers(handler=HeaderHandler(parsers={}, generators={}))
74
self.assertRaises(AttributeError, h.setRawHeaders, "test", [1])
75
self.assertRaises(AttributeError, h.setHeader, "test", 1)
76
self.assertRaises(AttributeError, h.removeHeader, "test")
78
class TokenizerTest(unittest.TestCase):
79
"""Test header list parsing functions."""
82
parser = lambda val: list(http_headers.tokenize([val,]))
83
Token = http_headers.Token
84
tests = (('foo,bar', ['foo', Token(','), 'bar']),
85
('FOO,BAR', ['foo', Token(','), 'bar']),
86
(' \t foo \t bar \t , \t baz ', ['foo', Token(' '), 'bar', Token(','), 'baz']),
87
('()<>@,;:\\/[]?={}', [Token('('), Token(')'), Token('<'), Token('>'), Token('@'), Token(','), Token(';'), Token(':'), Token('\\'), Token('/'), Token('['), Token(']'), Token('?'), Token('='), Token('{'), Token('}')]),
89
('"FOO(),\\"BAR,"', ['FOO(),"BAR,']))
91
raiseTests = ('"open quote', '"ending \\', "control character: \x127", "\x00", "\x1f")
93
for test,result in tests:
94
self.assertEquals(parser(test), result)
95
for test in raiseTests:
96
self.assertRaises(ValueError, parser, test)
98
def testGenerate(self):
101
def testRoundtrip(self):
104
def atSpecifiedTime(when, func):
107
time.time = lambda: when
109
return func(*a, **kw)
112
return util.mergeFunctionMetadata(func, inner)
114
def parseHeader(name, val):
115
head = http_headers.Headers(handler=http_headers.DefaultHTTPHandler)
116
head.setRawHeaders(name,val)
117
return head.getHeader(name)
118
parseHeader = atSpecifiedTime(999999990, parseHeader) # Sun, 09 Sep 2001 01:46:30 GMT
120
def generateHeader(name, val):
121
head = http_headers.Headers(handler=http_headers.DefaultHTTPHandler)
122
head.setHeader(name, val)
123
return head.getRawHeaders(name)
124
generateHeader = atSpecifiedTime(999999990, generateHeader) # Sun, 09 Sep 2001 01:46:30 GMT
127
class HeaderParsingTestBase(unittest.TestCase):
128
def runRoundtripTest(self, headername, table):
130
Perform some assertions about the behavior of parsing and
131
generating HTTP headers. Specifically: parse an HTTP header
132
value, assert that the parsed form contains all the available
133
information with the correct structure; generate the HTTP
134
header value from the parsed form, assert that it contains
135
certain literal strings; finally, re-parse the generated HTTP
136
header value and assert that the resulting structured data is
137
the same as the first-pass parsed form.
139
@type headername: C{str}
140
@param headername: The name of the HTTP header L{table} contains values for.
142
@type table: A sequence of tuples describing inputs to and
143
outputs from header parsing and generation. The tuples may be
144
either 2 or 3 elements long. In either case: the first
145
element is a string representing an HTTP-format header value;
146
the second element is a dictionary mapping names of parameters
147
to values of those parameters (the parsed form of the header).
148
If there is a third element, it is a list of strings which
149
must occur exactly in the HTTP header value
150
string which is re-generated from the parsed form.
154
rawHeaderInput, parsedHeaderData = row
155
requiredGeneratedElements = []
157
rawHeaderInput, parsedHeaderData, requiredGeneratedElements = row
160
assert isinstance(requiredGeneratedElements, list)
163
parsed = parseHeader(headername, [rawHeaderInput,])
164
self.assertEquals(parsed, parsedHeaderData)
166
regeneratedHeaderValue = generateHeader(headername, parsed)
168
if requiredGeneratedElements:
170
for regeneratedElement in regeneratedHeaderValue:
171
reqEle = requiredGeneratedElements[regeneratedHeaderValue.index(regeneratedElement)]
172
elementIndex = regeneratedElement.find(reqEle)
175
"%r did not appear in generated HTTP header %r: %r" % (reqEle,
180
reparsed = parseHeader(headername, regeneratedHeaderValue)
181
self.assertEquals(parsed, reparsed)
184
def invalidParseTest(self, headername, values):
186
parsed = parseHeader(headername, val)
187
self.assertEquals(parsed, None)
189
class GeneralHeaderParsingTests(HeaderParsingTestBase):
190
def testCacheControl(self):
194
("no-cache, no-store, max-age=5, max-stale=3, min-fresh=5, no-transform, only-if-cached, blahblah-extension-thingy",
201
'only-if-cached':None,
202
'blahblah-extension-thingy':None}),
205
("public, private, no-cache, no-store, no-transform, must-revalidate, proxy-revalidate, max-age=5, s-maxage=10, blahblah-extension-thingy",
211
'must-revalidate':None,
212
'proxy-revalidate':None,
215
'blahblah-extension-thingy':None}),
216
('private="Set-Cookie, Set-Cookie2", no-cache="PROXY-AUTHENTICATE"',
217
{'private': ['set-cookie', 'set-cookie2'],
218
'no-cache': ['proxy-authenticate']},
219
['private="Set-Cookie, Set-Cookie2"', 'no-cache="Proxy-Authenticate"']),
221
self.runRoundtripTest("Cache-Control", table)
223
def testConnection(self):
225
("close", ['close',]),
226
("close, foo-bar", ['close', 'foo-bar'])
228
self.runRoundtripTest("Connection", table)
231
# Don't need major tests since the datetime parser has its own tests
232
self.runRoundtripTest("Date", (("Sun, 09 Sep 2001 01:46:40 GMT", 1000000000),))
234
# def testPragma(self):
237
# def testTrailer(self):
240
def testTransferEncoding(self):
242
('chunked', ['chunked']),
243
('gzip, chunked', ['gzip', 'chunked'])
245
self.runRoundtripTest("Transfer-Encoding", table)
247
# def testUpgrade(self):
253
# def testWarning(self):
256
class RequestHeaderParsingTests(HeaderParsingTestBase):
257
#FIXME test ordering too.
258
def testAccept(self):
260
("audio/*;q=0.2, audio/basic",
261
{http_headers.MimeType('audio', '*'): 0.2,
262
http_headers.MimeType('audio', 'basic'): 1.0}),
264
("text/plain;q=0.5, text/html, text/x-dvi;q=0.8, text/x-c",
265
{http_headers.MimeType('text', 'plain'): 0.5,
266
http_headers.MimeType('text', 'html'): 1.0,
267
http_headers.MimeType('text', 'x-dvi'): 0.8,
268
http_headers.MimeType('text', 'x-c'): 1.0}),
270
("text/*, text/html, text/html;level=1, */*",
271
{http_headers.MimeType('text', '*'): 1.0,
272
http_headers.MimeType('text', 'html'): 1.0,
273
http_headers.MimeType('text', 'html', (('level', '1'),)): 1.0,
274
http_headers.MimeType('*', '*'): 1.0}),
276
("text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5",
277
{http_headers.MimeType('text', '*'): 0.3,
278
http_headers.MimeType('text', 'html'): 0.7,
279
http_headers.MimeType('text', 'html', (('level', '1'),)): 1.0,
280
http_headers.MimeType('text', 'html', (('level', '2'),)): 0.4,
281
http_headers.MimeType('*', '*'): 0.5}),
284
self.runRoundtripTest("Accept", table)
287
def testAcceptCharset(self):
289
("iso-8859-5, unicode-1-1;q=0.8",
290
{'iso-8859-5': 1.0, 'iso-8859-1': 1.0, 'unicode-1-1': 0.8},
291
["iso-8859-5", "unicode-1-1;q=0.8", "iso-8859-1"]),
293
{'iso-8859-1': 0.7}),
299
["iso-8859-1"]), # Yes this is an actual change -- we'll say that's okay. :)
301
self.runRoundtripTest("Accept-Charset", table)
303
def testAcceptEncoding(self):
306
{'compress': 1.0, 'gzip': 1.0, 'identity': 0.0001}),
308
{'identity': 0.0001}),
311
("compress;q=0.5, gzip;q=1.0",
312
{'compress': 0.5, 'gzip': 1.0, 'identity': 0.0001},
313
["compress;q=0.5", "gzip"]),
314
("gzip;q=1.0, identity;q=0.5, *;q=0",
315
{'gzip': 1.0, 'identity': 0.5, '*':0},
316
["gzip", "identity;q=0.5", "*;q=0"]),
318
self.runRoundtripTest("Accept-Encoding", table)
320
def testAcceptLanguage(self):
322
("da, en-gb;q=0.8, en;q=0.7",
323
{'da': 1.0, 'en-gb': 0.8, 'en': 0.7}),
327
self.runRoundtripTest("Accept-Language", table)
329
def testAuthorization(self):
331
("Basic dXNlcm5hbWU6cGFzc3dvcmQ=",
332
("basic", "dXNlcm5hbWU6cGFzc3dvcmQ="),
333
["basic dXNlcm5hbWU6cGFzc3dvcmQ="]),
334
('Digest nonce="bar", realm="foo", username="baz", response="bax"',
335
('digest', 'nonce="bar", realm="foo", username="baz", response="bax"'),
336
['digest', 'nonce="bar"', 'realm="foo"', 'username="baz"', 'response="bax"'])
339
self.runRoundtripTest("Authorization", table)
341
def testCookie(self):
343
('name=value', [Cookie('name', 'value')]),
344
('"name"="value"', [Cookie('"name"', '"value"')]),
345
('name,"blah=value,"', [Cookie('name,"blah', 'value,"')]),
346
('name,"blah = value," ', [Cookie('name,"blah', 'value,"')], ['name,"blah=value,"']),
347
("`~!@#$%^&*()-_+[{]}\\|:'\",<.>/?=`~!@#$%^&*()-_+[{]}\\|:'\",<.>/?", [Cookie("`~!@#$%^&*()-_+[{]}\\|:'\",<.>/?", "`~!@#$%^&*()-_+[{]}\\|:'\",<.>/?")]),
348
('name,"blah = value," ; name2=val2',
349
[Cookie('name,"blah', 'value,"'), Cookie('name2', 'val2')],
350
['name,"blah=value,"', 'name2=val2']),
352
self.runRoundtripTest("Cookie", table)
354
#newstyle RFC2965 Cookie
357
'name="value";$Path="/foo";$Domain="www.local";$Port="80,8000";'
359
[Cookie('name', 'value', path='/foo', domain='www.local', ports=(80,8000), version=1), Cookie('name2', 'value', version=1)]),
361
'name="value";$Port',
362
[Cookie('name', 'value', ports=(), version=1)]),
363
('$Version = 1, NAME = "qq\\"qq",Frob=boo',
364
[Cookie('name', 'qq"qq', version=1), Cookie('frob', 'boo', version=1)],
365
['$Version="1";name="qq\\"qq";frob="boo"']),
367
self.runRoundtripTest("Cookie", table2)
370
# make headers by combining oldstyle and newstyle cookies
372
([Cookie('name', 'value'), Cookie('name2', 'value2', version=1)],
373
'$Version="1";name=value;name2="value2"'),
374
([Cookie('name', 'value', path="/foo"), Cookie('name2', 'value2', domain="bar.baz", version=1)],
375
'$Version="1";name=value;$Path="/foo";name2="value2";$Domain="bar.baz"'),
376
([Cookie('invalid,"name', 'value'), Cookie('name2', 'value2', version=1)],
377
'$Version="1";name2="value2"'),
378
([Cookie('name', 'qq"qq'), Cookie('name2', 'value2', version=1)],
379
'$Version="1";name="qq\\"qq";name2="value2"'),
382
self.assertEquals(generateHeader("Cookie", row[0]), [row[1],])
386
def testSetCookie(self):
388
('name,"blah=value,; expires=Sun, 09 Sep 2001 01:46:40 GMT; path=/foo; domain=bar.baz; secure',
389
[Cookie('name,"blah', 'value,', expires=1000000000, path="/foo", domain="bar.baz", secure=True)]),
390
('name,"blah = value, ; expires="Sun, 09 Sep 2001 01:46:40 GMT"',
391
[Cookie('name,"blah', 'value,', expires=1000000000)],
392
['name,"blah=value,', 'expires=Sun, 09 Sep 2001 01:46:40 GMT']),
394
self.runRoundtripTest("Set-Cookie", table)
396
def testSetCookie2(self):
398
('name="value"; Comment="YadaYada"; CommentURL="http://frobnotz/"; Discard; Domain="blah.blah"; Max-Age=10; Path="/foo"; Port="80,8080"; Secure; Version="1"',
399
[Cookie("name", "value", comment="YadaYada", commenturl="http://frobnotz/", discard=True, domain="blah.blah", expires=1000000000, path="/foo", ports=(80,8080), secure=True, version=1)]),
401
self.runRoundtripTest("Set-Cookie2", table)
403
def testExpect(self):
406
{"100-continue":(None,)}),
408
{'foobar':('twiddle',)}),
410
{'foo':('bar',('a', 'b'), ('c', None))})
412
self.runRoundtripTest("Expect", table)
415
self.runRoundtripTest("From", (("webmaster@w3.org", "webmaster@w3.org"),))
418
self.runRoundtripTest("Host", (("www.w3.org", "www.w3.org"),))
420
def testIfMatch(self):
422
('"xyzzy"', [http_headers.ETag('xyzzy')]),
423
('"xyzzy", "r2d2xxxx", "c3piozzzz"', [http_headers.ETag('xyzzy'),
424
http_headers.ETag('r2d2xxxx'),
425
http_headers.ETag('c3piozzzz')]),
428
def testIfModifiedSince(self):
429
# Don't need major tests since the datetime parser has its own test
430
# Just test stupid ; length= brokenness.
432
("Sun, 09 Sep 2001 01:46:40 GMT", 1000000000),
433
("Sun, 09 Sep 2001 01:46:40 GMT; length=500", 1000000000, ["Sun, 09 Sep 2001 01:46:40 GMT"]),
436
self.runRoundtripTest("If-Modified-Since", table)
438
def testIfNoneMatch(self):
440
('"xyzzy"', [http_headers.ETag('xyzzy')]),
441
('W/"xyzzy", "r2d2xxxx", "c3piozzzz"', [http_headers.ETag('xyzzy', weak=True),
442
http_headers.ETag('r2d2xxxx'),
443
http_headers.ETag('c3piozzzz')]),
444
('W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"', [http_headers.ETag('xyzzy', weak=True),
445
http_headers.ETag('r2d2xxxx', weak=True),
446
http_headers.ETag('c3piozzzz', weak=True)]),
449
self.runRoundtripTest("If-None-Match", table)
451
def testIfRange(self):
453
('"xyzzy"', http_headers.ETag('xyzzy')),
454
('W/"xyzzy"', http_headers.ETag('xyzzy', weak=True)),
455
('W/"xyzzy"', http_headers.ETag('xyzzy', weak=True)),
456
("Sun, 09 Sep 2001 01:46:40 GMT", 1000000000),
458
self.runRoundtripTest("If-Range", table)
460
def testIfUnmodifiedSince(self):
461
self.runRoundtripTest("If-Unmodified-Since", (("Sun, 09 Sep 2001 01:46:40 GMT", 1000000000),))
463
def testMaxForwards(self):
464
self.runRoundtripTest("Max-Forwards", (("15", 15),))
467
# def testProxyAuthorize(self):
472
("bytes=0-499", ('bytes', [(0,499),])),
473
("bytes=500-999", ('bytes', [(500,999),])),
474
("bytes=-500",('bytes', [(None,500),])),
475
("bytes=9500-",('bytes', [(9500, None),])),
476
("bytes=0-0,-1", ('bytes', [(0,0),(None,1)])),
478
self.runRoundtripTest("Range", table)
481
def testReferer(self):
482
self.runRoundtripTest("Referer", (("http://www.w3.org/hypertext/DataSources/Overview.html",
483
"http://www.w3.org/hypertext/DataSources/Overview.html"),))
488
("deflate", {'deflate':1}),
490
("trailers, deflate;q=0.5", {'trailers':1, 'deflate':0.5}),
492
self.runRoundtripTest("TE", table)
494
def testUserAgent(self):
495
self.runRoundtripTest("User-Agent", (("CERN-LineMode/2.15 libwww/2.17b3", "CERN-LineMode/2.15 libwww/2.17b3"),))
498
class ResponseHeaderParsingTests(HeaderParsingTestBase):
499
def testAcceptRanges(self):
500
self.runRoundtripTest("Accept-Ranges", (("bytes", ["bytes"]), ("none", ["none"])))
503
self.runRoundtripTest("Age", (("15", 15),))
507
('"xyzzy"', http_headers.ETag('xyzzy')),
508
('W/"xyzzy"', http_headers.ETag('xyzzy', weak=True)),
509
('""', http_headers.ETag('')),
511
self.runRoundtripTest("ETag", table)
513
def testLocation(self):
514
self.runRoundtripTest("Location", (("http://www.w3.org/pub/WWW/People.htm",
515
"http://www.w3.org/pub/WWW/People.htm"),))
518
# def testProxyAuthenticate(self):
521
def testRetryAfter(self):
522
# time() is always 999999990 when being tested.
524
("Sun, 09 Sep 2001 01:46:40 GMT", 1000000000, ["10"]),
525
("120", 999999990+120),
527
self.runRoundtripTest("Retry-After", table)
529
def testServer(self):
530
self.runRoundtripTest("Server", (("CERN/3.0 libwww/2.17", "CERN/3.0 libwww/2.17"),))
535
("Accept, Accept-Encoding", ["accept", "accept-encoding"], ["accept", "accept-encoding"])
537
self.runRoundtripTest("Vary", table)
539
def testWWWAuthenticate(self):
540
digest = ('Digest realm="digest realm", nonce="bAr", qop="auth"',
541
[('Digest', {'realm': 'digest realm', 'nonce': 'bAr',
543
['Digest', 'realm="digest realm"',
544
'nonce="bAr"', 'qop="auth"'])
546
basic = ('Basic realm="foo"',
547
[('Basic', {'realm': 'foo'})], ['Basic', 'realm="foo"'])
550
[('NTLM', {})], ['NTLM', ''])
552
negotiate = ('Negotiate SomeGssAPIData',
553
[('Negotiate', 'SomeGssAPIData')],
554
['Negotiate', 'SomeGssAPIData'])
558
(digest[0]+', '+basic[0],
559
digest[1] + basic[1],
560
[digest[2], basic[2]]),
563
(ntlm[0]+', '+basic[0],
565
[ntlm[2], basic[2]]),
566
(digest[0]+', '+negotiate[0],
567
digest[1] + negotiate[1],
568
[digest[2], negotiate[2]]),
569
(negotiate[0]+', '+negotiate[0],
570
negotiate[1] + negotiate[1],
571
[negotiate[2] + negotiate[2]]),
572
(ntlm[0]+', '+ntlm[0],
575
(basic[0]+', '+ntlm[0],
577
[basic[2], ntlm[2]]),
580
# runRoundtripTest doesn't work because we don't generate a single
583
headername = 'WWW-Authenticate'
586
rawHeaderInput, parsedHeaderData, requiredGeneratedElements = row
588
parsed = parseHeader(headername, [rawHeaderInput,])
589
self.assertEquals(parsed, parsedHeaderData)
591
regeneratedHeaderValue = generateHeader(headername, parsed)
593
for regeneratedElement in regeneratedHeaderValue:
594
requiredElements = requiredGeneratedElements[
595
regeneratedHeaderValue.index(
598
for reqEle in requiredElements:
599
elementIndex = regeneratedElement.find(reqEle)
603
"%r did not appear in generated HTTP header %r: %r" % (reqEle,
608
reparsed = parseHeader(headername, regeneratedHeaderValue)
609
self.assertEquals(parsed, reparsed)
612
class EntityHeaderParsingTests(HeaderParsingTestBase):
614
# Allow is a silly case-sensitive header unlike all the rest
617
("GET, HEAD, PUT", ['GET', 'HEAD', 'PUT']),
619
self.runRoundtripTest("Allow", table)
621
def testContentEncoding(self):
625
self.runRoundtripTest("Content-Encoding", table)
627
def testContentLanguage(self):
630
("mi, en", ['mi', 'en']),
632
self.runRoundtripTest("Content-Language", table)
634
def testContentLength(self):
635
self.runRoundtripTest("Content-Length", (("15", 15),))
636
self.invalidParseTest("Content-Length", ("asdf",))
638
def testContentLocation(self):
639
self.runRoundtripTest("Content-Location",
640
(("http://www.w3.org/pub/WWW/People.htm",
641
"http://www.w3.org/pub/WWW/People.htm"),))
643
def testContentMD5(self):
644
self.runRoundtripTest("Content-MD5", (("Q2hlY2sgSW50ZWdyaXR5IQ==", "Check Integrity!"),))
645
self.invalidParseTest("Content-MD5", ("sdlaksjdfhlkaj",))
647
def testContentRange(self):
649
("bytes 0-499/1234", ("bytes", 0, 499, 1234)),
650
("bytes 500-999/1234", ("bytes", 500, 999, 1234)),
651
("bytes 500-1233/1234", ("bytes", 500, 1233, 1234)),
652
("bytes 734-1233/1234", ("bytes", 734, 1233, 1234)),
653
("bytes 734-1233/*", ("bytes", 734, 1233, None)),
654
("bytes */1234", ("bytes", None, None, 1234)),
655
("bytes */*", ("bytes", None, None, None))
657
self.runRoundtripTest("Content-Range", table)
659
def testContentType(self):
661
("text/html;charset=iso-8859-4", http_headers.MimeType('text', 'html', (('charset','iso-8859-4'),))),
662
("text/html", http_headers.MimeType('text', 'html')),
664
self.runRoundtripTest("Content-Type", table)
666
def testExpires(self):
667
self.runRoundtripTest("Expires", (("Sun, 09 Sep 2001 01:46:40 GMT", 1000000000),))
668
# Invalid expires MUST return date in the past.
669
self.assertEquals(parseHeader("Expires", ["0"]), 0)
670
self.assertEquals(parseHeader("Expires", ["wejthnaljn"]), 0)
673
def testLastModified(self):
674
# Don't need major tests since the datetime parser has its own test
675
self.runRoundtripTest("Last-Modified", (("Sun, 09 Sep 2001 01:46:40 GMT", 1000000000),))
677
class DateTimeTest(unittest.TestCase):
678
"""Test date parsing functions."""
682
timeStrs = ('Sun, 06 Nov 1994 08:49:37 GMT',
683
'Sunday, 06-Nov-94 08:49:37 GMT',
684
'Sun Nov 6 08:49:37 1994',
686
# Also some non-RFC formats, for good measure.
687
'Somefakeday 6 Nov 1994 8:49:37',
688
'6 Nov 1994 8:49:37',
689
'Sun, 6 Nov 1994 8:49:37',
690
'6 Nov 1994 8:49:37 GMT',
692
'06-Nov-94 08:49:37',
693
'Sunday, 06-Nov-94 08:49:37',
694
'06-Nov-94 08:49:37 GMT',
696
'Nov 6 08:49:37 1994',
698
for timeStr in timeStrs:
699
self.assertEquals(http_headers.parseDateTime(timeStr), timeNum)
701
# Test 2 Digit date wraparound yuckiness.
702
self.assertEquals(http_headers.parseDateTime(
703
'Monday, 11-Oct-04 14:56:50 GMT'), 1097506610)
704
self.assertEquals(http_headers.parseDateTime(
705
'Monday, 11-Oct-2004 14:56:50 GMT'), 1097506610)
708
def testGenerate(self):
709
self.assertEquals(http_headers.generateDateTime(784111777), 'Sun, 06 Nov 1994 08:49:37 GMT')
711
def testRoundtrip(self):
712
for i in range(2000):
713
time = random.randint(0, 2000000000)
714
timestr = http_headers.generateDateTime(time)
715
time2 = http_headers.parseDateTime(timestr)
716
self.assertEquals(time, time2)
719
class TestMimeType(unittest.TestCase):
720
def testEquality(self):
721
"""Test that various uses of the constructer are equal
724
kwargMime = http_headers.MimeType('text', 'plain',
727
dictMime = http_headers.MimeType('text', 'plain',
730
tupleMime = http_headers.MimeType('text', 'plain',
734
stringMime = http_headers.MimeType.fromString('text/plain;key=value;param')
736
self.assertEquals(kwargMime, dictMime)
737
self.assertEquals(dictMime, tupleMime)
738
self.assertEquals(kwargMime, tupleMime)
739
self.assertEquals(kwargMime, stringMime)