-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinfo.go
More file actions
executable file
·134 lines (118 loc) · 3.68 KB
/
Copy pathinfo.go
File metadata and controls
executable file
·134 lines (118 loc) · 3.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright (c) 2022, Roel Schut. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package serv
import (
"context"
"net"
"net/http"
)
type ctxInfoKey struct{}
type Info struct {
ServerName string
HandlerName string
RequestID string
}
// ContextWithInfo adds an Info value to the context. It returns a derived
// context that points to the parent context.Context when Info is not already
// added. Otherwise, it will update the previously added Info with info and
// return the context as is.
func ContextWithInfo(ctx context.Context, info Info) context.Context {
if v := InfoFromContext(ctx); v != nil {
*v = info
return ctx
}
return context.WithValue(ctx, ctxInfoKey{}, &info)
}
// InfoFromContext returns the Info value from the context values, or nil.
func InfoFromContext(ctx context.Context) *Info {
if v := ctx.Value(ctxInfoKey{}); v != nil {
return v.(*Info)
}
return nil
}
// ServerName gets the server's name from the context values. Its returned
// value may be an empty string.
func ServerName(ctx context.Context) string {
if info := InfoFromContext(ctx); info != nil {
return info.ServerName
}
return ""
}
// HandlerName gets the handler's name from the context values. Its returned
// value may be an empty string.
func HandlerName(ctx context.Context) string {
if info := InfoFromContext(ctx); info != nil {
return info.HandlerName
}
return ""
}
// RequestID gets the request id from the context values. Its returned value
// may be an empty string.
func RequestID(ctx context.Context) string {
if info := InfoFromContext(ctx); info != nil {
return info.RequestID
}
return ""
}
// AddServerName sets the request context value [Info.ServerName] field with
// the value name. It should be used on a per-server basis and is done
// automatically when a [Server]'s name is set using [WithName].
func AddServerName(name string, next http.Handler) http.Handler {
return http.HandlerFunc(func(wri http.ResponseWriter, req *http.Request) {
req, info := requestWithInfo(req)
info.ServerName = name
next.ServeHTTP(wri, req)
})
}
// AddHandlerName sets the request context value [Info.HandlerName] field with
// the value name. It should be used on a per route/handler basis.
func AddHandlerName(name string, next http.Handler) http.Handler {
return http.HandlerFunc(func(wri http.ResponseWriter, req *http.Request) {
req, info := requestWithInfo(req)
info.HandlerName = name
next.ServeHTTP(wri, req)
})
}
// AddRequestID sets the request context value [Info.RequestID] field with the
// value id. It should be used on a per-request basis.
func AddRequestID(id string, next http.Handler) http.Handler {
return http.HandlerFunc(func(wri http.ResponseWriter, req *http.Request) {
req, info := requestWithInfo(req)
info.RequestID = id
next.ServeHTTP(wri, req)
})
}
func requestWithInfo(req *http.Request) (*http.Request, *Info) {
if v := InfoFromContext(req.Context()); v != nil {
return req, v
}
var info Info
return req.WithContext(
context.WithValue(req.Context(), ctxInfoKey{}, &info),
), &info
}
// RemoteAddr returns a sanitized remote address from the [http.Request].
// Add [middleware.RealIP] middleware to your [http.Handler] to handle (proxy)
// forwarded traffic.
func RemoteAddr(r *http.Request) string {
addr, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
return r.RemoteAddr
}
return addr
}
// RequestURI
// https://www.rfc-editor.org/rfc/rfc7540#section-8.3
func RequestURI(r *http.Request) string {
var uri string
if r.ProtoMajor == 2 && r.Method == "CONNECT" {
uri = r.Host
} else {
uri = r.RequestURI
}
if uri == "" {
uri = r.URL.RequestURI()
}
return uri
}