import (
"context"
"crypto/tls"
+ "encoding/hex"
"errors"
"fmt"
+ "math/rand"
"net"
"net/http"
"os"
"regexp"
"sync"
+ "time"
"go.fuhry.dev/runtime/mtls"
"go.fuhry.dev/runtime/utils/log"
}
type Listener struct {
- Addr string `yaml:"listen"`
- ProxyProtocol bool `yaml:"proxy_protocol"`
- InsecureAddr string `yaml:"listen_insecure"`
- Certificate string `yaml:"cert"`
- VirtualHosts map[string]*VirtualHost `yaml:"virtual_hosts"`
+ Addr string `yaml:"listen"`
+ ProxyProtocol bool `yaml:"proxy_protocol"`
+ InsecureAddr string `yaml:"listen_insecure"`
+ Certificate string `yaml:"cert"`
+ TrustUpstreamRequestID bool `yaml:"trust_upstream_request_id"`
+ VirtualHosts map[string]*VirtualHost `yaml:"virtual_hosts"`
}
type Server struct {
kListener
kListenAddr
kSamlDefaults
+ kRequestID
)
+var randSrc = rand.New(rand.NewSource(time.Now().UnixNano()))
var portSpec = regexp.MustCompile(":[0-9]{1,5}$")
var initHooks []initHook
var routeParseFuncs []routeParseFunc
lm := log.NewLoggingMiddlewareWithLogger(
http.HandlerFunc(l.handle),
logger.AppendPrefix(".access"))
+ lm.AddResponseHeader("x-request-id")
server := &http.Server{
Addr: l.Addr,
return
}
+ reqIdCtx := r.Context()
+ rid := r.Header.Get("x-request-id")
+ if rid == "" || !l.TrustUpstreamRequestID {
+ rid = newRequestID()
+ }
+ w.Header().Set("x-request-id", rid)
+ reqIdCtx = context.WithValue(reqIdCtx, kRequestID, rid)
+
// make sure this host is known
vhost, ok := l.VirtualHosts[r.Host]
if !ok {
}
}
- l.fulfill(w, r, vhost.Routes)
+ l.fulfill(w, r.WithContext(reqIdCtx), vhost.Routes)
}
func (l *Listener) fulfill(w http.ResponseWriter, r *http.Request, routes []*Route) {
func LoggerFromContext(ctx context.Context) log.Logger {
l := ctx.Value(kLogger)
if logger, ok := l.(log.Logger); ok {
+ if v, ok := ctx.Value(kRequestID).(string); ok {
+ logger = logger.AppendPrefix(fmt.Sprintf("<id=%s>", v))
+ }
return logger
}
return nil
}
+
+func newRequestID() string {
+ buf := make([]byte, 10)
+ _, _ = randSrc.Read(buf)
+
+ return hex.EncodeToString(buf)
+}