hpack_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // Copyright 2014 The Go Authors.
  2. // See https://code.google.com/p/go/source/browse/CONTRIBUTORS
  3. // Licensed under the same terms as Go itself:
  4. // https://code.google.com/p/go/source/browse/LICENSE
  5. package hpack
  6. import (
  7. "bufio"
  8. "bytes"
  9. "encoding/hex"
  10. "regexp"
  11. "strconv"
  12. "strings"
  13. "testing"
  14. )
  15. func TestStaticTable(t *testing.T) {
  16. fromSpec := `
  17. +-------+-----------------------------+---------------+
  18. | 1 | :authority | |
  19. | 2 | :method | GET |
  20. | 3 | :method | POST |
  21. | 4 | :path | / |
  22. | 5 | :path | /index.html |
  23. | 6 | :scheme | http |
  24. | 7 | :scheme | https |
  25. | 8 | :status | 200 |
  26. | 9 | :status | 204 |
  27. | 10 | :status | 206 |
  28. | 11 | :status | 304 |
  29. | 12 | :status | 400 |
  30. | 13 | :status | 404 |
  31. | 14 | :status | 500 |
  32. | 15 | accept-charset | |
  33. | 16 | accept-encoding | gzip, deflate |
  34. | 17 | accept-language | |
  35. | 18 | accept-ranges | |
  36. | 19 | accept | |
  37. | 20 | access-control-allow-origin | |
  38. | 21 | age | |
  39. | 22 | allow | |
  40. | 23 | authorization | |
  41. | 24 | cache-control | |
  42. | 25 | content-disposition | |
  43. | 26 | content-encoding | |
  44. | 27 | content-language | |
  45. | 28 | content-length | |
  46. | 29 | content-location | |
  47. | 30 | content-range | |
  48. | 31 | content-type | |
  49. | 32 | cookie | |
  50. | 33 | date | |
  51. | 34 | etag | |
  52. | 35 | expect | |
  53. | 36 | expires | |
  54. | 37 | from | |
  55. | 38 | host | |
  56. | 39 | if-match | |
  57. | 40 | if-modified-since | |
  58. | 41 | if-none-match | |
  59. | 42 | if-range | |
  60. | 43 | if-unmodified-since | |
  61. | 44 | last-modified | |
  62. | 45 | link | |
  63. | 46 | location | |
  64. | 47 | max-forwards | |
  65. | 48 | proxy-authenticate | |
  66. | 49 | proxy-authorization | |
  67. | 50 | range | |
  68. | 51 | referer | |
  69. | 52 | refresh | |
  70. | 53 | retry-after | |
  71. | 54 | server | |
  72. | 55 | set-cookie | |
  73. | 56 | strict-transport-security | |
  74. | 57 | transfer-encoding | |
  75. | 58 | user-agent | |
  76. | 59 | vary | |
  77. | 60 | via | |
  78. | 61 | www-authenticate | |
  79. +-------+-----------------------------+---------------+
  80. `
  81. bs := bufio.NewScanner(strings.NewReader(fromSpec))
  82. re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`)
  83. for bs.Scan() {
  84. l := bs.Text()
  85. if !strings.Contains(l, "|") {
  86. continue
  87. }
  88. m := re.FindStringSubmatch(l)
  89. if m == nil {
  90. continue
  91. }
  92. i, err := strconv.Atoi(m[1])
  93. if err != nil {
  94. t.Errorf("Bogus integer on line %q", l)
  95. continue
  96. }
  97. if i < 1 || i > len(staticTable) {
  98. t.Errorf("Bogus index %d on line %q", i, l)
  99. continue
  100. }
  101. if got, want := staticTable[i-1].Name, m[2]; got != want {
  102. t.Errorf("header index %d name = %q; want %q", i, got, want)
  103. }
  104. if got, want := staticTable[i-1].Value, m[3]; got != want {
  105. t.Errorf("header index %d value = %q; want %q", i, got, want)
  106. }
  107. }
  108. if err := bs.Err(); err != nil {
  109. t.Error(err)
  110. }
  111. }
  112. func TestHeaderTableAt(t *testing.T) {
  113. var ht headerTable
  114. if got, want := ht.at(2), (HeaderField{":method", "GET"}); got != want {
  115. t.Errorf("at(2) = %q; want %q", got, want)
  116. }
  117. ht.add(HeaderField{"foo", "bar"})
  118. if got, want := ht.at(1), (HeaderField{"foo", "bar"}); got != want {
  119. t.Errorf("at(1) = %q; want %q", got, want)
  120. }
  121. if got, want := ht.at(3), (HeaderField{":method", "GET"}); got != want {
  122. t.Errorf("at(3) = %q; want %q", got, want)
  123. }
  124. if got, want := ht.at(62), (HeaderField{"www-authenticate", ""}); got != want {
  125. t.Errorf("at(62) = %q; want %q", got, want)
  126. }
  127. }
  128. func TestHuffmanDecode(t *testing.T) {
  129. tests := []struct {
  130. inHex, want string
  131. }{
  132. {"f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"},
  133. {"a8eb 1064 9cbf", "no-cache"},
  134. {"25a8 49e9 5ba9 7d7f", "custom-key"},
  135. {"25a8 49e9 5bb8 e8b4 bf", "custom-value"},
  136. {"6402", "302"},
  137. {"aec3 771a 4b", "private"},
  138. {"d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", "Mon, 21 Oct 2013 20:13:21 GMT"},
  139. {"9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", "https://www.example.com"},
  140. {"9bd9 ab", "gzip"},
  141. {"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
  142. "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
  143. }
  144. for i, tt := range tests {
  145. var buf bytes.Buffer
  146. in, err := hex.DecodeString(strings.Replace(tt.inHex, " ", "", -1))
  147. if err != nil {
  148. t.Errorf("%d. hex input error: %v", i, err)
  149. continue
  150. }
  151. if _, err := HuffmanDecode(&buf, in); err != nil {
  152. t.Errorf("%d. decode error: %v", i, err)
  153. continue
  154. }
  155. if got := buf.String(); tt.want != got {
  156. t.Errorf("%d. decode = %q; want %q", i, got, tt.want)
  157. }
  158. }
  159. }