You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

190 lines
4.9 KiB

  1. // Copyright 2018 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // +build go1.8
  15. package proxy
  16. import (
  17. "io/ioutil"
  18. "net/http"
  19. "strings"
  20. "testing"
  21. "cloud.google.com/go/internal/testutil"
  22. "github.com/google/go-cmp/cmp"
  23. "github.com/google/go-cmp/cmp/cmpopts"
  24. "github.com/google/martian/har"
  25. )
  26. func TestRequestBody(t *testing.T) {
  27. req1 := &http.Request{
  28. Header: http.Header{"Content-Type": {"multipart/mixed; boundary=foo"}},
  29. Body: ioutil.NopCloser(strings.NewReader(
  30. "--foo\r\nFoo: one\r\n\r\nA section\r\n" +
  31. "--foo\r\nFoo: two\r\n\r\nAnd another\r\n" +
  32. "--foo--\r\n")),
  33. }
  34. rb1, err := newRequestBodyFromHTTP(req1)
  35. if err != nil {
  36. t.Fatal(err)
  37. }
  38. want := &requestBody{
  39. mediaType: "multipart/mixed",
  40. parts: [][]byte{
  41. []byte("A section"),
  42. []byte("And another"),
  43. },
  44. }
  45. if diff := testutil.Diff(rb1, want, cmp.AllowUnexported(requestBody{})); diff != "" {
  46. t.Error(diff)
  47. }
  48. // Same contents, different boundary.
  49. req2 := &http.Request{
  50. Header: http.Header{"Content-Type": {"multipart/mixed; boundary=bar"}},
  51. Body: ioutil.NopCloser(strings.NewReader(
  52. "--bar\r\nFoo: one\r\n\r\nA section\r\n" +
  53. "--bar\r\nFoo: two\r\n\r\nAnd another\r\n" +
  54. "--bar--\r\n")),
  55. }
  56. rb2, err := newRequestBodyFromHTTP(req2)
  57. if err != nil {
  58. t.Fatal(err)
  59. }
  60. if diff := testutil.Diff(rb1, want, cmp.AllowUnexported(requestBody{})); diff != "" {
  61. t.Error(diff)
  62. }
  63. if !rb1.equal(rb2) {
  64. t.Error("equal returned false, want true")
  65. }
  66. }
  67. func TestHeadersMatch(t *testing.T) {
  68. for _, test := range []struct {
  69. h1, h2 http.Header
  70. want bool
  71. }{
  72. {
  73. http.Header{"A": {"x"}, "B": {"y", "z"}},
  74. http.Header{"A": {"x"}, "B": {"y", "z"}},
  75. true,
  76. },
  77. {
  78. http.Header{"A": {"x"}, "B": {"y", "z"}},
  79. http.Header{"A": {"x"}, "B": {"w"}},
  80. false,
  81. },
  82. {
  83. http.Header{"A": {"x"}, "B": {"y", "z"}, "I": {"foo"}},
  84. http.Header{"A": {"x"}, "B": {"y", "z"}, "I": {"bar"}},
  85. true,
  86. },
  87. {
  88. http.Header{"A": {"x"}, "B": {"y", "z"}},
  89. http.Header{"A": {"x"}, "B": {"y", "z"}, "I": {"bar"}},
  90. true,
  91. },
  92. {
  93. http.Header{"A": {"x"}, "B": {"y", "z"}, "I": {"foo"}},
  94. http.Header{"A": {"x"}, "I": {"bar"}},
  95. false,
  96. },
  97. {
  98. http.Header{"A": {"x"}, "I": {"foo"}},
  99. http.Header{"A": {"x"}, "B": {"y", "z"}, "I": {"bar"}},
  100. false,
  101. },
  102. } {
  103. got := headersMatch(test.h1, test.h2, map[string]bool{"I": true})
  104. if got != test.want {
  105. t.Errorf("%v, %v: got %t, want %t", test.h1, test.h2, got, test.want)
  106. }
  107. }
  108. }
  109. func TestHarResponseToHTTPResponse(t *testing.T) {
  110. for _, test := range []struct {
  111. desc string
  112. hr *har.Response
  113. req *http.Request
  114. want *http.Response
  115. }{
  116. {
  117. desc: "GET request",
  118. hr: &har.Response{
  119. Status: 201,
  120. StatusText: "201",
  121. HTTPVersion: "1.1",
  122. Headers: []har.Header{{Name: "h", Value: "v"}},
  123. Content: &har.Content{Text: []byte("text")},
  124. },
  125. req: &http.Request{Method: "GET"},
  126. want: &http.Response{
  127. Request: &http.Request{Method: "GET"},
  128. StatusCode: 201,
  129. Status: "201",
  130. Proto: "1.1",
  131. Header: http.Header{"h": {"v"}},
  132. ContentLength: 4,
  133. },
  134. },
  135. {
  136. desc: "HEAD request with no Content-Length header",
  137. hr: &har.Response{
  138. Status: 201,
  139. StatusText: "201",
  140. HTTPVersion: "1.1",
  141. Headers: []har.Header{{Name: "h", Value: "v"}},
  142. Content: &har.Content{Text: []byte("text")},
  143. },
  144. req: &http.Request{Method: "HEAD"},
  145. want: &http.Response{
  146. Request: &http.Request{Method: "HEAD"},
  147. StatusCode: 201,
  148. Status: "201",
  149. Proto: "1.1",
  150. Header: http.Header{"h": {"v"}},
  151. ContentLength: -1,
  152. },
  153. },
  154. {
  155. desc: "HEAD request with Content-Length header",
  156. hr: &har.Response{
  157. Status: 201,
  158. StatusText: "201",
  159. HTTPVersion: "1.1",
  160. Headers: []har.Header{{Name: "h", Value: "v"}, {Name: "Content-Length", Value: "17"}},
  161. Content: &har.Content{Text: []byte("text")},
  162. },
  163. req: &http.Request{Method: "HEAD"},
  164. want: &http.Response{
  165. Request: &http.Request{Method: "HEAD"},
  166. StatusCode: 201,
  167. Status: "201",
  168. Proto: "1.1",
  169. Header: http.Header{"h": {"v"}, "Content-Length": {"17"}},
  170. ContentLength: 17,
  171. },
  172. },
  173. } {
  174. got := harResponseToHTTPResponse(test.hr, test.req)
  175. got.Body = nil
  176. if diff := testutil.Diff(got, test.want, cmpopts.IgnoreUnexported(http.Request{})); diff != "" {
  177. t.Errorf("%s: %s", test.desc, diff)
  178. }
  179. }
  180. }