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.
 
 
 

163 lines
4.3 KiB

  1. // Copyright 2015 Google Inc. All rights reserved.
  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. // Package header provides utilities for modifying, filtering, and
  15. // verifying headers in martian.Proxy.
  16. package header
  17. import (
  18. "encoding/json"
  19. "fmt"
  20. "net/http"
  21. "strings"
  22. "github.com/google/martian"
  23. "github.com/google/martian/parse"
  24. "github.com/google/martian/proxyutil"
  25. "github.com/google/martian/verify"
  26. )
  27. const (
  28. headerErrFormat = "%s(%s) header verify failure: got no header, want %s header"
  29. valueErrFormat = "%s(%s) header verify failure: got %s with value %s, want value %s"
  30. )
  31. type verifier struct {
  32. name, value string
  33. reqerr *martian.MultiError
  34. reserr *martian.MultiError
  35. }
  36. type verifierJSON struct {
  37. Name string `json:"name"`
  38. Value string `json:"value"`
  39. Scope []parse.ModifierType `json:"scope"`
  40. }
  41. func init() {
  42. parse.Register("header.Verifier", verifierFromJSON)
  43. }
  44. // NewVerifier creates a new header verifier for the given name and value.
  45. func NewVerifier(name, value string) verify.RequestResponseVerifier {
  46. return &verifier{
  47. name: name,
  48. value: value,
  49. reqerr: martian.NewMultiError(),
  50. reserr: martian.NewMultiError(),
  51. }
  52. }
  53. // ModifyRequest verifies that the header for name is present in all modified
  54. // requests. If value is non-empty the value must be present in at least one
  55. // header for name. An error will be added to the contained *MultiError for
  56. // every unmatched request.
  57. func (v *verifier) ModifyRequest(req *http.Request) error {
  58. h := proxyutil.RequestHeader(req)
  59. vs, ok := h.All(v.name)
  60. if !ok {
  61. v.reqerr.Add(fmt.Errorf(headerErrFormat, "request", req.URL, v.name))
  62. return nil
  63. }
  64. for _, value := range vs {
  65. switch v.value {
  66. case "", value:
  67. return nil
  68. }
  69. }
  70. v.reqerr.Add(fmt.Errorf(valueErrFormat, "request", req.URL, v.name,
  71. strings.Join(vs, ", "), v.value))
  72. return nil
  73. }
  74. // ModifyResponse verifies that the header for name is present in all modified
  75. // responses. If value is non-empty the value must be present in at least one
  76. // header for name. An error will be added to the contained *MultiError for
  77. // every unmatched response.
  78. func (v *verifier) ModifyResponse(res *http.Response) error {
  79. h := proxyutil.ResponseHeader(res)
  80. vs, ok := h.All(v.name)
  81. if !ok {
  82. v.reserr.Add(fmt.Errorf(headerErrFormat, "response", res.Request.URL, v.name))
  83. return nil
  84. }
  85. for _, value := range vs {
  86. switch v.value {
  87. case "", value:
  88. return nil
  89. }
  90. }
  91. v.reserr.Add(fmt.Errorf(valueErrFormat, "response", res.Request.URL, v.name,
  92. strings.Join(vs, ", "), v.value))
  93. return nil
  94. }
  95. // VerifyRequests returns an error if verification for any request failed.
  96. // If an error is returned it will be of type *martian.MultiError.
  97. func (v *verifier) VerifyRequests() error {
  98. if v.reqerr.Empty() {
  99. return nil
  100. }
  101. return v.reqerr
  102. }
  103. // VerifyResponses returns an error if verification for any request failed.
  104. // If an error is returned it will be of type *martian.MultiError.
  105. func (v *verifier) VerifyResponses() error {
  106. if v.reserr.Empty() {
  107. return nil
  108. }
  109. return v.reserr
  110. }
  111. // ResetRequestVerifications clears all failed request verifications.
  112. func (v *verifier) ResetRequestVerifications() {
  113. v.reqerr = martian.NewMultiError()
  114. }
  115. // ResetResponseVerifications clears all failed response verifications.
  116. func (v *verifier) ResetResponseVerifications() {
  117. v.reserr = martian.NewMultiError()
  118. }
  119. // verifierFromJSON builds a header.Verifier from JSON.
  120. //
  121. // Example JSON:
  122. // {
  123. // "name": "header.Verifier",
  124. // "scope": ["request", "result"],
  125. // "modifier": {
  126. // "name": "Martian-Testing",
  127. // "value": "true"
  128. // }
  129. // }
  130. func verifierFromJSON(b []byte) (*parse.Result, error) {
  131. msg := &verifierJSON{}
  132. if err := json.Unmarshal(b, msg); err != nil {
  133. return nil, err
  134. }
  135. return parse.NewResult(NewVerifier(msg.Name, msg.Value), msg.Scope)
  136. }