test_http_headers.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for L{twisted.web.http_headers}.
  5. """
  6. from __future__ import division, absolute_import
  7. from twisted.trial.unittest import TestCase
  8. from twisted.python.compat import _PY3, unicode
  9. from twisted.web.http_headers import Headers
  10. class BytesHeadersTests(TestCase):
  11. """
  12. Tests for L{Headers}, using L{bytes} arguments for methods.
  13. """
  14. def test_initializer(self):
  15. """
  16. The header values passed to L{Headers.__init__} can be retrieved via
  17. L{Headers.getRawHeaders}.
  18. """
  19. h = Headers({b'Foo': [b'bar']})
  20. self.assertEqual(h.getRawHeaders(b'foo'), [b'bar'])
  21. def test_setRawHeaders(self):
  22. """
  23. L{Headers.setRawHeaders} sets the header values for the given
  24. header name to the sequence of byte string values.
  25. """
  26. rawValue = [b"value1", b"value2"]
  27. h = Headers()
  28. h.setRawHeaders(b"test", rawValue)
  29. self.assertTrue(h.hasHeader(b"test"))
  30. self.assertTrue(h.hasHeader(b"Test"))
  31. self.assertEqual(h.getRawHeaders(b"test"), rawValue)
  32. def test_rawHeadersTypeChecking(self):
  33. """
  34. L{Headers.setRawHeaders} requires values to be of type list.
  35. """
  36. h = Headers()
  37. self.assertRaises(TypeError, h.setRawHeaders, b'key', {b'Foo': b'bar'})
  38. def test_addRawHeader(self):
  39. """
  40. L{Headers.addRawHeader} adds a new value for a given header.
  41. """
  42. h = Headers()
  43. h.addRawHeader(b"test", b"lemur")
  44. self.assertEqual(h.getRawHeaders(b"test"), [b"lemur"])
  45. h.addRawHeader(b"test", b"panda")
  46. self.assertEqual(h.getRawHeaders(b"test"), [b"lemur", b"panda"])
  47. def test_getRawHeadersNoDefault(self):
  48. """
  49. L{Headers.getRawHeaders} returns L{None} if the header is not found and
  50. no default is specified.
  51. """
  52. self.assertIsNone(Headers().getRawHeaders(b"test"))
  53. def test_getRawHeadersDefaultValue(self):
  54. """
  55. L{Headers.getRawHeaders} returns the specified default value when no
  56. header is found.
  57. """
  58. h = Headers()
  59. default = object()
  60. self.assertIdentical(h.getRawHeaders(b"test", default), default)
  61. def test_getRawHeadersWithDefaultMatchingValue(self):
  62. """
  63. If the object passed as the value list to L{Headers.setRawHeaders}
  64. is later passed as a default to L{Headers.getRawHeaders}, the
  65. result nevertheless contains encoded values.
  66. """
  67. h = Headers()
  68. default = [u"value"]
  69. h.setRawHeaders(b"key", default)
  70. self.assertIsInstance(h.getRawHeaders(b"key", default)[0], bytes)
  71. self.assertEqual(h.getRawHeaders(b"key", default), [b"value"])
  72. def test_getRawHeaders(self):
  73. """
  74. L{Headers.getRawHeaders} returns the values which have been set for a
  75. given header.
  76. """
  77. h = Headers()
  78. h.setRawHeaders(b"test", [b"lemur"])
  79. self.assertEqual(h.getRawHeaders(b"test"), [b"lemur"])
  80. self.assertEqual(h.getRawHeaders(b"Test"), [b"lemur"])
  81. def test_hasHeaderTrue(self):
  82. """
  83. Check that L{Headers.hasHeader} returns C{True} when the given header
  84. is found.
  85. """
  86. h = Headers()
  87. h.setRawHeaders(b"test", [b"lemur"])
  88. self.assertTrue(h.hasHeader(b"test"))
  89. self.assertTrue(h.hasHeader(b"Test"))
  90. def test_hasHeaderFalse(self):
  91. """
  92. L{Headers.hasHeader} returns C{False} when the given header is not
  93. found.
  94. """
  95. self.assertFalse(Headers().hasHeader(b"test"))
  96. def test_removeHeader(self):
  97. """
  98. Check that L{Headers.removeHeader} removes the given header.
  99. """
  100. h = Headers()
  101. h.setRawHeaders(b"foo", [b"lemur"])
  102. self.assertTrue(h.hasHeader(b"foo"))
  103. h.removeHeader(b"foo")
  104. self.assertFalse(h.hasHeader(b"foo"))
  105. h.setRawHeaders(b"bar", [b"panda"])
  106. self.assertTrue(h.hasHeader(b"bar"))
  107. h.removeHeader(b"Bar")
  108. self.assertFalse(h.hasHeader(b"bar"))
  109. def test_removeHeaderDoesntExist(self):
  110. """
  111. L{Headers.removeHeader} is a no-operation when the specified header is
  112. not found.
  113. """
  114. h = Headers()
  115. h.removeHeader(b"test")
  116. self.assertEqual(list(h.getAllRawHeaders()), [])
  117. def test_canonicalNameCaps(self):
  118. """
  119. L{Headers._canonicalNameCaps} returns the canonical capitalization for
  120. the given header.
  121. """
  122. h = Headers()
  123. self.assertEqual(h._canonicalNameCaps(b"test"), b"Test")
  124. self.assertEqual(h._canonicalNameCaps(b"test-stuff"), b"Test-Stuff")
  125. self.assertEqual(h._canonicalNameCaps(b"content-md5"), b"Content-MD5")
  126. self.assertEqual(h._canonicalNameCaps(b"dnt"), b"DNT")
  127. self.assertEqual(h._canonicalNameCaps(b"etag"), b"ETag")
  128. self.assertEqual(h._canonicalNameCaps(b"p3p"), b"P3P")
  129. self.assertEqual(h._canonicalNameCaps(b"te"), b"TE")
  130. self.assertEqual(h._canonicalNameCaps(b"www-authenticate"),
  131. b"WWW-Authenticate")
  132. self.assertEqual(h._canonicalNameCaps(b"x-xss-protection"),
  133. b"X-XSS-Protection")
  134. def test_getAllRawHeaders(self):
  135. """
  136. L{Headers.getAllRawHeaders} returns an iterable of (k, v) pairs, where
  137. C{k} is the canonicalized representation of the header name, and C{v}
  138. is a sequence of values.
  139. """
  140. h = Headers()
  141. h.setRawHeaders(b"test", [b"lemurs"])
  142. h.setRawHeaders(b"www-authenticate", [b"basic aksljdlk="])
  143. allHeaders = set([(k, tuple(v)) for k, v in h.getAllRawHeaders()])
  144. self.assertEqual(allHeaders,
  145. set([(b"WWW-Authenticate", (b"basic aksljdlk=",)),
  146. (b"Test", (b"lemurs",))]))
  147. def test_headersComparison(self):
  148. """
  149. A L{Headers} instance compares equal to itself and to another
  150. L{Headers} instance with the same values.
  151. """
  152. first = Headers()
  153. first.setRawHeaders(b"foo", [b"panda"])
  154. second = Headers()
  155. second.setRawHeaders(b"foo", [b"panda"])
  156. third = Headers()
  157. third.setRawHeaders(b"foo", [b"lemur", b"panda"])
  158. self.assertEqual(first, first)
  159. self.assertEqual(first, second)
  160. self.assertNotEqual(first, third)
  161. def test_otherComparison(self):
  162. """
  163. An instance of L{Headers} does not compare equal to other unrelated
  164. objects.
  165. """
  166. h = Headers()
  167. self.assertNotEqual(h, ())
  168. self.assertNotEqual(h, object())
  169. self.assertNotEqual(h, b"foo")
  170. def test_repr(self):
  171. """
  172. The L{repr} of a L{Headers} instance shows the names and values of all
  173. the headers it contains.
  174. """
  175. foo = b"foo"
  176. bar = b"bar"
  177. baz = b"baz"
  178. self.assertEqual(
  179. repr(Headers({foo: [bar, baz]})),
  180. "Headers({%r: [%r, %r]})" % (foo, bar, baz))
  181. def test_reprWithRawBytes(self):
  182. """
  183. The L{repr} of a L{Headers} instance shows the names and values of all
  184. the headers it contains, not attempting to decode any raw bytes.
  185. """
  186. # There's no such thing as undecodable latin-1, you'll just get
  187. # some mojibake
  188. foo = b"foo"
  189. # But this is invalid UTF-8! So, any accidental decoding/encoding will
  190. # throw an exception.
  191. bar = b"bar\xe1"
  192. baz = b"baz\xe1"
  193. self.assertEqual(
  194. repr(Headers({foo: [bar, baz]})),
  195. "Headers({%r: [%r, %r]})" % (foo, bar, baz))
  196. def test_subclassRepr(self):
  197. """
  198. The L{repr} of an instance of a subclass of L{Headers} uses the name
  199. of the subclass instead of the string C{"Headers"}.
  200. """
  201. foo = b"foo"
  202. bar = b"bar"
  203. baz = b"baz"
  204. class FunnyHeaders(Headers):
  205. pass
  206. self.assertEqual(
  207. repr(FunnyHeaders({foo: [bar, baz]})),
  208. "FunnyHeaders({%r: [%r, %r]})" % (foo, bar, baz))
  209. def test_copy(self):
  210. """
  211. L{Headers.copy} creates a new independent copy of an existing
  212. L{Headers} instance, allowing future modifications without impacts
  213. between the copies.
  214. """
  215. h = Headers()
  216. h.setRawHeaders(b'test', [b'foo'])
  217. i = h.copy()
  218. self.assertEqual(i.getRawHeaders(b'test'), [b'foo'])
  219. h.addRawHeader(b'test', b'bar')
  220. self.assertEqual(i.getRawHeaders(b'test'), [b'foo'])
  221. i.addRawHeader(b'test', b'baz')
  222. self.assertEqual(h.getRawHeaders(b'test'), [b'foo', b'bar'])
  223. class UnicodeHeadersTests(TestCase):
  224. """
  225. Tests for L{Headers}, using L{unicode} arguments for methods.
  226. """
  227. def test_initializer(self):
  228. """
  229. The header values passed to L{Headers.__init__} can be retrieved via
  230. L{Headers.getRawHeaders}. If a L{bytes} argument is given, it returns
  231. L{bytes} values, and if a L{unicode} argument is given, it returns
  232. L{unicode} values. Both are the same header value, just encoded or
  233. decoded.
  234. """
  235. h = Headers({u'Foo': [u'bar']})
  236. self.assertEqual(h.getRawHeaders(b'foo'), [b'bar'])
  237. self.assertEqual(h.getRawHeaders(u'foo'), [u'bar'])
  238. def test_setRawHeaders(self):
  239. """
  240. L{Headers.setRawHeaders} sets the header values for the given
  241. header name to the sequence of strings, encoded.
  242. """
  243. rawValue = [u"value1", u"value2"]
  244. rawEncodedValue = [b"value1", b"value2"]
  245. h = Headers()
  246. h.setRawHeaders("test", rawValue)
  247. self.assertTrue(h.hasHeader(b"test"))
  248. self.assertTrue(h.hasHeader(b"Test"))
  249. self.assertTrue(h.hasHeader("test"))
  250. self.assertTrue(h.hasHeader("Test"))
  251. self.assertEqual(h.getRawHeaders("test"), rawValue)
  252. self.assertEqual(h.getRawHeaders(b"test"), rawEncodedValue)
  253. def test_nameNotEncodable(self):
  254. """
  255. Passing L{unicode} to any function that takes a header name will encode
  256. said header name as ISO-8859-1, and if it cannot be encoded, it will
  257. raise a L{UnicodeDecodeError}.
  258. """
  259. h = Headers()
  260. # Only these two functions take names
  261. with self.assertRaises(UnicodeEncodeError):
  262. h.setRawHeaders(u"\u2603", [u"val"])
  263. with self.assertRaises(UnicodeEncodeError):
  264. h.hasHeader(u"\u2603")
  265. def test_nameEncoding(self):
  266. """
  267. Passing L{unicode} to any function that takes a header name will encode
  268. said header name as ISO-8859-1.
  269. """
  270. h = Headers()
  271. # We set it using a Unicode string.
  272. h.setRawHeaders(u"\u00E1", [b"foo"])
  273. # It's encoded to the ISO-8859-1 value, which we can use to access it
  274. self.assertTrue(h.hasHeader(b"\xe1"))
  275. self.assertEqual(h.getRawHeaders(b"\xe1"), [b'foo'])
  276. # We can still access it using the Unicode string..
  277. self.assertTrue(h.hasHeader(u"\u00E1"))
  278. def test_rawHeadersValueEncoding(self):
  279. """
  280. Passing L{unicode} to L{Headers.setRawHeaders} will encode the name as
  281. ISO-8859-1 and values as UTF-8.
  282. """
  283. h = Headers()
  284. h.setRawHeaders(u"\u00E1", [u"\u2603", b"foo"])
  285. self.assertTrue(h.hasHeader(b"\xe1"))
  286. self.assertEqual(h.getRawHeaders(b"\xe1"), [b'\xe2\x98\x83', b'foo'])
  287. def test_rawHeadersTypeChecking(self):
  288. """
  289. L{Headers.setRawHeaders} requires values to be of type list.
  290. """
  291. h = Headers()
  292. self.assertRaises(TypeError, h.setRawHeaders, u'key', {u'Foo': u'bar'})
  293. def test_addRawHeader(self):
  294. """
  295. L{Headers.addRawHeader} adds a new value for a given header.
  296. """
  297. h = Headers()
  298. h.addRawHeader(u"test", u"lemur")
  299. self.assertEqual(h.getRawHeaders(u"test"), [u"lemur"])
  300. h.addRawHeader(u"test", u"panda")
  301. self.assertEqual(h.getRawHeaders(u"test"), [u"lemur", u"panda"])
  302. self.assertEqual(h.getRawHeaders(b"test"), [b"lemur", b"panda"])
  303. def test_getRawHeadersNoDefault(self):
  304. """
  305. L{Headers.getRawHeaders} returns L{None} if the header is not found and
  306. no default is specified.
  307. """
  308. self.assertIsNone(Headers().getRawHeaders(u"test"))
  309. def test_getRawHeadersDefaultValue(self):
  310. """
  311. L{Headers.getRawHeaders} returns the specified default value when no
  312. header is found.
  313. """
  314. h = Headers()
  315. default = object()
  316. self.assertIdentical(h.getRawHeaders(u"test", default), default)
  317. self.assertIdentical(h.getRawHeaders(u"test", None), None)
  318. self.assertEqual(h.getRawHeaders(u"test", [None]), [None])
  319. self.assertEqual(
  320. h.getRawHeaders(u"test", [u"\N{SNOWMAN}"]),
  321. [u"\N{SNOWMAN}"],
  322. )
  323. def test_getRawHeadersWithDefaultMatchingValue(self):
  324. """
  325. If the object passed as the value list to L{Headers.setRawHeaders}
  326. is later passed as a default to L{Headers.getRawHeaders}, the
  327. result nevertheless contains decoded values.
  328. """
  329. h = Headers()
  330. default = [b"value"]
  331. h.setRawHeaders(b"key", default)
  332. self.assertIsInstance(h.getRawHeaders(u"key", default)[0], unicode)
  333. self.assertEqual(h.getRawHeaders(u"key", default), [u"value"])
  334. def test_getRawHeaders(self):
  335. """
  336. L{Headers.getRawHeaders} returns the values which have been set for a
  337. given header.
  338. """
  339. h = Headers()
  340. h.setRawHeaders(u"test\u00E1", [u"lemur"])
  341. self.assertEqual(h.getRawHeaders(u"test\u00E1"), [u"lemur"])
  342. self.assertEqual(h.getRawHeaders(u"Test\u00E1"), [u"lemur"])
  343. self.assertEqual(h.getRawHeaders(b"test\xe1"), [b"lemur"])
  344. self.assertEqual(h.getRawHeaders(b"Test\xe1"), [b"lemur"])
  345. def test_hasHeaderTrue(self):
  346. """
  347. Check that L{Headers.hasHeader} returns C{True} when the given header
  348. is found.
  349. """
  350. h = Headers()
  351. h.setRawHeaders(u"test\u00E1", [u"lemur"])
  352. self.assertTrue(h.hasHeader(u"test\u00E1"))
  353. self.assertTrue(h.hasHeader(u"Test\u00E1"))
  354. self.assertTrue(h.hasHeader(b"test\xe1"))
  355. self.assertTrue(h.hasHeader(b"Test\xe1"))
  356. def test_hasHeaderFalse(self):
  357. """
  358. L{Headers.hasHeader} returns C{False} when the given header is not
  359. found.
  360. """
  361. self.assertFalse(Headers().hasHeader(u"test\u00E1"))
  362. def test_removeHeader(self):
  363. """
  364. Check that L{Headers.removeHeader} removes the given header.
  365. """
  366. h = Headers()
  367. h.setRawHeaders(u"foo", [u"lemur"])
  368. self.assertTrue(h.hasHeader(u"foo"))
  369. h.removeHeader(u"foo")
  370. self.assertFalse(h.hasHeader(u"foo"))
  371. self.assertFalse(h.hasHeader(b"foo"))
  372. h.setRawHeaders(u"bar", [u"panda"])
  373. self.assertTrue(h.hasHeader(u"bar"))
  374. h.removeHeader(u"Bar")
  375. self.assertFalse(h.hasHeader(u"bar"))
  376. self.assertFalse(h.hasHeader(b"bar"))
  377. def test_removeHeaderDoesntExist(self):
  378. """
  379. L{Headers.removeHeader} is a no-operation when the specified header is
  380. not found.
  381. """
  382. h = Headers()
  383. h.removeHeader(u"test")
  384. self.assertEqual(list(h.getAllRawHeaders()), [])
  385. def test_getAllRawHeaders(self):
  386. """
  387. L{Headers.getAllRawHeaders} returns an iterable of (k, v) pairs, where
  388. C{k} is the canonicalized representation of the header name, and C{v}
  389. is a sequence of values.
  390. """
  391. h = Headers()
  392. h.setRawHeaders(u"test\u00E1", [u"lemurs"])
  393. h.setRawHeaders(u"www-authenticate", [u"basic aksljdlk="])
  394. h.setRawHeaders(u"content-md5", [u"kjdfdfgdfgnsd"])
  395. allHeaders = set([(k, tuple(v)) for k, v in h.getAllRawHeaders()])
  396. self.assertEqual(allHeaders,
  397. set([(b"WWW-Authenticate", (b"basic aksljdlk=",)),
  398. (b"Content-MD5", (b"kjdfdfgdfgnsd",)),
  399. (b"Test\xe1", (b"lemurs",))]))
  400. def test_headersComparison(self):
  401. """
  402. A L{Headers} instance compares equal to itself and to another
  403. L{Headers} instance with the same values.
  404. """
  405. first = Headers()
  406. first.setRawHeaders(u"foo\u00E1", [u"panda"])
  407. second = Headers()
  408. second.setRawHeaders(u"foo\u00E1", [u"panda"])
  409. third = Headers()
  410. third.setRawHeaders(u"foo\u00E1", [u"lemur", u"panda"])
  411. self.assertEqual(first, first)
  412. self.assertEqual(first, second)
  413. self.assertNotEqual(first, third)
  414. # Headers instantiated with bytes equivs are also the same
  415. firstBytes = Headers()
  416. firstBytes.setRawHeaders(b"foo\xe1", [b"panda"])
  417. secondBytes = Headers()
  418. secondBytes.setRawHeaders(b"foo\xe1", [b"panda"])
  419. thirdBytes = Headers()
  420. thirdBytes.setRawHeaders(b"foo\xe1", [b"lemur", u"panda"])
  421. self.assertEqual(first, firstBytes)
  422. self.assertEqual(second, secondBytes)
  423. self.assertEqual(third, thirdBytes)
  424. def test_otherComparison(self):
  425. """
  426. An instance of L{Headers} does not compare equal to other unrelated
  427. objects.
  428. """
  429. h = Headers()
  430. self.assertNotEqual(h, ())
  431. self.assertNotEqual(h, object())
  432. self.assertNotEqual(h, u"foo")
  433. def test_repr(self):
  434. """
  435. The L{repr} of a L{Headers} instance shows the names and values of all
  436. the headers it contains. This shows only reprs of bytes values, as
  437. undecodable headers may cause an exception.
  438. """
  439. foo = u"foo\u00E1"
  440. bar = u"bar\u2603"
  441. baz = u"baz"
  442. fooEncoded = "'foo\\xe1'"
  443. barEncoded = "'bar\\xe2\\x98\\x83'"
  444. if _PY3:
  445. fooEncoded = "b" + fooEncoded
  446. barEncoded = "b" + barEncoded
  447. self.assertEqual(
  448. repr(Headers({foo: [bar, baz]})),
  449. "Headers({%s: [%s, %r]})" % (fooEncoded,
  450. barEncoded,
  451. baz.encode('utf8')))
  452. def test_subclassRepr(self):
  453. """
  454. The L{repr} of an instance of a subclass of L{Headers} uses the name
  455. of the subclass instead of the string C{"Headers"}.
  456. """
  457. foo = u"foo\u00E1"
  458. bar = u"bar\u2603"
  459. baz = u"baz"
  460. fooEncoded = "'foo\\xe1'"
  461. barEncoded = "'bar\\xe2\\x98\\x83'"
  462. if _PY3:
  463. fooEncoded = "b" + fooEncoded
  464. barEncoded = "b" + barEncoded
  465. class FunnyHeaders(Headers):
  466. pass
  467. self.assertEqual(
  468. repr(FunnyHeaders({foo: [bar, baz]})),
  469. "FunnyHeaders({%s: [%s, %r]})" % (fooEncoded,
  470. barEncoded,
  471. baz.encode('utf8')))
  472. def test_copy(self):
  473. """
  474. L{Headers.copy} creates a new independent copy of an existing
  475. L{Headers} instance, allowing future modifications without impacts
  476. between the copies.
  477. """
  478. h = Headers()
  479. h.setRawHeaders(u'test\u00E1', [u'foo\u2603'])
  480. i = h.copy()
  481. # The copy contains the same value as the original
  482. self.assertEqual(i.getRawHeaders(u'test\u00E1'), [u'foo\u2603'])
  483. self.assertEqual(i.getRawHeaders(b'test\xe1'), [b'foo\xe2\x98\x83'])
  484. # Add a header to the original
  485. h.addRawHeader(u'test\u00E1', u'bar')
  486. # Verify that the copy has not changed
  487. self.assertEqual(i.getRawHeaders(u'test\u00E1'), [u'foo\u2603'])
  488. self.assertEqual(i.getRawHeaders(b'test\xe1'), [b'foo\xe2\x98\x83'])
  489. # Add a header to the copy
  490. i.addRawHeader(u'test\u00E1', b'baz')
  491. # Verify that the orignal does not have it
  492. self.assertEqual(
  493. h.getRawHeaders(u'test\u00E1'), [u'foo\u2603', u'bar'])
  494. self.assertEqual(
  495. h.getRawHeaders(b'test\xe1'), [b'foo\xe2\x98\x83', b'bar'])