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