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.
 
 
 

169 lines
3.6 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 port provides utilities for modifying and filtering
  15. // based on the port of request URLs.
  16. package port
  17. import (
  18. "encoding/json"
  19. "net"
  20. "net/http"
  21. "strconv"
  22. "strings"
  23. "github.com/google/martian"
  24. "github.com/google/martian/parse"
  25. )
  26. var noop = martian.Noop("port.Filter")
  27. func init() {
  28. parse.Register("port.Filter", filterFromJSON)
  29. }
  30. // Filter runs modifiers iff the port in the request URL matches port.
  31. type Filter struct {
  32. reqmod martian.RequestModifier
  33. resmod martian.ResponseModifier
  34. port int
  35. }
  36. type filterJSON struct {
  37. Port int `json:"port"`
  38. Modifier json.RawMessage `json:"modifier"`
  39. Scope []parse.ModifierType `json:"scope"`
  40. }
  41. // NewFilter returns a filter that executes modifiers if the port of
  42. // request matches port.
  43. func NewFilter(port int) *Filter {
  44. return &Filter{
  45. port: port,
  46. reqmod: noop,
  47. resmod: noop,
  48. }
  49. }
  50. // SetRequestModifier sets the request modifier.
  51. func (f *Filter) SetRequestModifier(reqmod martian.RequestModifier) {
  52. if reqmod == nil {
  53. reqmod = noop
  54. }
  55. f.reqmod = reqmod
  56. }
  57. // SetResponseModifier sets the response modifier.
  58. func (f *Filter) SetResponseModifier(resmod martian.ResponseModifier) {
  59. if resmod == nil {
  60. resmod = noop
  61. }
  62. f.resmod = resmod
  63. }
  64. // ModifyRequest runs the modifier if the port matches the provided port.
  65. func (f *Filter) ModifyRequest(req *http.Request) error {
  66. var defaultPort int
  67. if req.URL.Scheme == "http" {
  68. defaultPort = 80
  69. }
  70. if req.URL.Scheme == "https" {
  71. defaultPort = 443
  72. }
  73. hasPort := strings.Contains(req.URL.Host, ":")
  74. if hasPort {
  75. _, p, err := net.SplitHostPort(req.URL.Host)
  76. if err != nil {
  77. return err
  78. }
  79. pt, err := strconv.Atoi(p)
  80. if err != nil {
  81. return err
  82. }
  83. if pt == f.port {
  84. return f.reqmod.ModifyRequest(req)
  85. }
  86. return nil
  87. }
  88. // no port explictly declared - default port
  89. if f.port == defaultPort {
  90. return f.reqmod.ModifyRequest(req)
  91. }
  92. return nil
  93. }
  94. // ModifyResponse runs the modifier if the request URL matches urlMatcher.
  95. func (f *Filter) ModifyResponse(res *http.Response) error {
  96. var defaultPort int
  97. if res.Request.URL.Scheme == "http" {
  98. defaultPort = 80
  99. }
  100. if res.Request.URL.Scheme == "https" {
  101. defaultPort = 443
  102. }
  103. if !strings.Contains(res.Request.URL.Host, ":") && (f.port == defaultPort) {
  104. return f.resmod.ModifyResponse(res)
  105. }
  106. _, p, err := net.SplitHostPort(res.Request.URL.Host)
  107. if err != nil {
  108. return err
  109. }
  110. pt, err := strconv.Atoi(p)
  111. if err != nil {
  112. return err
  113. }
  114. if pt == f.port {
  115. return f.resmod.ModifyResponse(res)
  116. }
  117. return nil
  118. }
  119. func filterFromJSON(b []byte) (*parse.Result, error) {
  120. msg := &filterJSON{}
  121. if err := json.Unmarshal(b, msg); err != nil {
  122. return nil, err
  123. }
  124. filter := NewFilter(msg.Port)
  125. r, err := parse.FromJSON(msg.Modifier)
  126. if err != nil {
  127. return nil, err
  128. }
  129. reqmod := r.RequestModifier()
  130. if err != nil {
  131. return nil, err
  132. }
  133. if reqmod != nil {
  134. filter.SetRequestModifier(reqmod)
  135. }
  136. resmod := r.ResponseModifier()
  137. if resmod != nil {
  138. filter.SetResponseModifier(resmod)
  139. }
  140. return parse.NewResult(filter, msg.Scope)
  141. }