http.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package raven
  2. import (
  3. "errors"
  4. "fmt"
  5. "net"
  6. "net/http"
  7. "net/url"
  8. "runtime/debug"
  9. "strings"
  10. )
  11. func NewHttp(req *http.Request) *Http {
  12. proto := "http"
  13. if req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https" {
  14. proto = "https"
  15. }
  16. h := &Http{
  17. Method: req.Method,
  18. Cookies: req.Header.Get("Cookie"),
  19. Query: sanitizeQuery(req.URL.Query()).Encode(),
  20. URL: proto + "://" + req.Host + req.URL.Path,
  21. Headers: make(map[string]string, len(req.Header)),
  22. }
  23. if addr, port, err := net.SplitHostPort(req.RemoteAddr); err == nil {
  24. h.Env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port}
  25. }
  26. for k, v := range req.Header {
  27. h.Headers[k] = strings.Join(v, ",")
  28. }
  29. h.Headers["Host"] = req.Host
  30. return h
  31. }
  32. var querySecretFields = []string{"password", "passphrase", "passwd", "secret"}
  33. func sanitizeQuery(query url.Values) url.Values {
  34. for _, keyword := range querySecretFields {
  35. for field := range query {
  36. if strings.Contains(field, keyword) {
  37. query[field] = []string{"********"}
  38. }
  39. }
  40. }
  41. return query
  42. }
  43. // https://docs.getsentry.com/hosted/clientdev/interfaces/#context-interfaces
  44. type Http struct {
  45. // Required
  46. URL string `json:"url"`
  47. Method string `json:"method"`
  48. Query string `json:"query_string,omitempty"`
  49. // Optional
  50. Cookies string `json:"cookies,omitempty"`
  51. Headers map[string]string `json:"headers,omitempty"`
  52. Env map[string]string `json:"env,omitempty"`
  53. // Must be either a string or map[string]string
  54. Data interface{} `json:"data,omitempty"`
  55. }
  56. func (h *Http) Class() string { return "request" }
  57. // Recovery handler to wrap the stdlib net/http Mux.
  58. // Example:
  59. // http.HandleFunc("/", raven.RecoveryHandler(func(w http.ResponseWriter, r *http.Request) {
  60. // ...
  61. // }))
  62. func RecoveryHandler(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
  63. return Recoverer(http.HandlerFunc(handler)).ServeHTTP
  64. }
  65. // Recovery handler to wrap the stdlib net/http Mux.
  66. // Example:
  67. // mux := http.NewServeMux
  68. // ...
  69. // http.Handle("/", raven.Recoverer(mux))
  70. func Recoverer(handler http.Handler) http.Handler {
  71. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  72. defer func() {
  73. if rval := recover(); rval != nil {
  74. debug.PrintStack()
  75. rvalStr := fmt.Sprint(rval)
  76. var packet *Packet
  77. if err, ok := rval.(error); ok {
  78. packet = NewPacket(rvalStr, NewException(errors.New(rvalStr), GetOrNewStacktrace(err, 2, 3, nil)), NewHttp(r))
  79. } else {
  80. packet = NewPacket(rvalStr, NewException(errors.New(rvalStr), NewStacktrace(2, 3, nil)), NewHttp(r))
  81. }
  82. Capture(packet, nil)
  83. w.WriteHeader(http.StatusInternalServerError)
  84. }
  85. }()
  86. handler.ServeHTTP(w, r)
  87. })
  88. }