85 lines
2.2 KiB
Go
85 lines
2.2 KiB
Go
package raven
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"runtime/debug"
|
|
"strings"
|
|
)
|
|
|
|
func NewHttp(req *http.Request) *Http {
|
|
proto := "http"
|
|
if req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https" {
|
|
proto = "https"
|
|
}
|
|
h := &Http{
|
|
Method: req.Method,
|
|
Cookies: req.Header.Get("Cookie"),
|
|
Query: sanitizeQuery(req.URL.Query()).Encode(),
|
|
URL: proto + "://" + req.Host + req.URL.Path,
|
|
Headers: make(map[string]string, len(req.Header)),
|
|
}
|
|
if addr, port, err := net.SplitHostPort(req.RemoteAddr); err == nil {
|
|
h.Env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port}
|
|
}
|
|
for k, v := range req.Header {
|
|
h.Headers[k] = strings.Join(v, ",")
|
|
}
|
|
return h
|
|
}
|
|
|
|
var querySecretFields = []string{"password", "passphrase", "passwd", "secret"}
|
|
|
|
func sanitizeQuery(query url.Values) url.Values {
|
|
for _, keyword := range querySecretFields {
|
|
for field := range query {
|
|
if strings.Contains(field, keyword) {
|
|
query[field] = []string{"********"}
|
|
}
|
|
}
|
|
}
|
|
return query
|
|
}
|
|
|
|
// https://docs.getsentry.com/hosted/clientdev/interfaces/#context-interfaces
|
|
type Http struct {
|
|
// Required
|
|
URL string `json:"url"`
|
|
Method string `json:"method"`
|
|
Query string `json:"query_string,omitempty"`
|
|
|
|
// Optional
|
|
Cookies string `json:"cookies,omitempty"`
|
|
Headers map[string]string `json:"headers,omitempty"`
|
|
Env map[string]string `json:"env,omitempty"`
|
|
|
|
// Must be either a string or map[string]string
|
|
Data interface{} `json:"data,omitempty"`
|
|
}
|
|
|
|
func (h *Http) Class() string { return "request" }
|
|
|
|
// Recovery handler to wrap the stdlib net/http Mux.
|
|
// Example:
|
|
// http.HandleFunc("/", raven.RecoveryHandler(func(w http.ResponseWriter, r *http.Request) {
|
|
// ...
|
|
// }))
|
|
func RecoveryHandler(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
defer func() {
|
|
if rval := recover(); rval != nil {
|
|
debug.PrintStack()
|
|
rvalStr := fmt.Sprint(rval)
|
|
packet := NewPacket(rvalStr, NewException(errors.New(rvalStr), NewStacktrace(2, 3, nil)), NewHttp(r))
|
|
Capture(packet, nil)
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}
|
|
}()
|
|
|
|
handler(w, r)
|
|
}
|
|
}
|