http_proxy_js_response.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package http_proxy
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "net/http"
  7. "strings"
  8. "github.com/elazarl/goproxy"
  9. )
  10. type JSResponse struct {
  11. Status int
  12. ContentType string
  13. Headers string
  14. Body string
  15. refHash string
  16. resp *http.Response
  17. bodyRead bool
  18. bodyClear bool
  19. }
  20. func NewJSResponse(res *http.Response) *JSResponse {
  21. cType := ""
  22. headers := ""
  23. code := 200
  24. if res != nil {
  25. code = res.StatusCode
  26. for name, values := range res.Header {
  27. for _, value := range values {
  28. headers += name + ": " + value + "\r\n"
  29. if strings.ToLower(name) == "content-type" {
  30. cType = value
  31. }
  32. }
  33. }
  34. }
  35. resp := &JSResponse{
  36. Status: code,
  37. ContentType: cType,
  38. Headers: headers,
  39. resp: res,
  40. bodyRead: false,
  41. bodyClear: false,
  42. }
  43. resp.UpdateHash()
  44. return resp
  45. }
  46. func (j *JSResponse) NewHash() string {
  47. return fmt.Sprintf("%d.%s.%s", j.Status, j.ContentType, j.Headers)
  48. }
  49. func (j *JSResponse) UpdateHash() {
  50. j.refHash = j.NewHash()
  51. }
  52. func (j *JSResponse) WasModified() bool {
  53. if j.bodyRead {
  54. // body was read
  55. return true
  56. } else if j.bodyClear {
  57. // body was cleared manually
  58. return true
  59. } else if j.Body != "" {
  60. // body was not read but just set
  61. return true
  62. }
  63. // check if any of the fields has been changed
  64. return j.NewHash() != j.refHash
  65. }
  66. func (j *JSResponse) GetHeader(name, deflt string) string {
  67. headers := strings.Split(j.Headers, "\r\n")
  68. for i := 0; i < len(headers); i++ {
  69. if headers[i] != "" {
  70. header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
  71. if len(header_parts) != 0 && len(header_parts[0]) == 3 {
  72. header_name := string(header_parts[0][1])
  73. header_value := string(header_parts[0][2])
  74. if strings.ToLower(name) == strings.ToLower(header_name) {
  75. return header_value
  76. }
  77. }
  78. }
  79. }
  80. return deflt
  81. }
  82. func (j *JSResponse) SetHeader(name, value string) {
  83. name = strings.TrimSpace(name)
  84. value = strings.TrimSpace(value)
  85. if strings.ToLower(name) == "content-type" {
  86. j.ContentType = value
  87. }
  88. headers := strings.Split(j.Headers, "\r\n")
  89. for i := 0; i < len(headers); i++ {
  90. if headers[i] != "" {
  91. header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
  92. if len(header_parts) != 0 && len(header_parts[0]) == 3 {
  93. header_name := string(header_parts[0][1])
  94. header_value := string(header_parts[0][2])
  95. if strings.ToLower(name) == strings.ToLower(header_name) {
  96. old_header := header_name + ": " + header_value + "\r\n"
  97. new_header := name + ": " + value + "\r\n"
  98. j.Headers = strings.Replace(j.Headers, old_header, new_header, 1)
  99. return
  100. }
  101. }
  102. }
  103. }
  104. j.Headers += name + ": " + value + "\r\n"
  105. }
  106. func (j *JSResponse) RemoveHeader(name string) {
  107. headers := strings.Split(j.Headers, "\r\n")
  108. for i := 0; i < len(headers); i++ {
  109. if headers[i] != "" {
  110. header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
  111. if len(header_parts) != 0 && len(header_parts[0]) == 3 {
  112. header_name := string(header_parts[0][1])
  113. header_value := string(header_parts[0][2])
  114. if strings.ToLower(name) == strings.ToLower(header_name) {
  115. removed_header := header_name + ": " + header_value + "\r\n"
  116. j.Headers = strings.Replace(j.Headers, removed_header, "", 1)
  117. return
  118. }
  119. }
  120. }
  121. }
  122. }
  123. func (j *JSResponse) ClearBody() {
  124. j.Body = ""
  125. j.bodyClear = true
  126. }
  127. func (j *JSResponse) ToResponse(req *http.Request) (resp *http.Response) {
  128. resp = goproxy.NewResponse(req, j.ContentType, j.Status, j.Body)
  129. headers := strings.Split(j.Headers, "\r\n")
  130. for i := 0; i < len(headers); i++ {
  131. if headers[i] != "" {
  132. header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
  133. if len(header_parts) != 0 && len(header_parts[0]) == 3 {
  134. header_name := string(header_parts[0][1])
  135. header_value := string(header_parts[0][2])
  136. resp.Header.Add(header_name, header_value)
  137. }
  138. }
  139. }
  140. return
  141. }
  142. func (j *JSResponse) ReadBody() string {
  143. defer j.resp.Body.Close()
  144. raw, err := ioutil.ReadAll(j.resp.Body)
  145. if err != nil {
  146. return ""
  147. }
  148. j.Body = string(raw)
  149. j.bodyRead = true
  150. j.bodyClear = false
  151. // reset the response body to the original unread state
  152. j.resp.Body = ioutil.NopCloser(bytes.NewBuffer(raw))
  153. return j.Body
  154. }