-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathhttp_utils.go
More file actions
91 lines (73 loc) · 2.06 KB
/
http_utils.go
File metadata and controls
91 lines (73 loc) · 2.06 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
package limen
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"strings"
)
type bodyContextKey struct{}
// normalizePath normalizes the base path to start with a slash.
func normalizePath(basePath string) string {
if !strings.HasPrefix(basePath, "/") {
basePath = "/" + basePath
}
basePath = strings.TrimSuffix(basePath, "/")
return basePath
}
// GetBody extracts the parsed JSON body from the request context
func GetJSONBody(req *http.Request) map[string]any {
if req == nil {
return nil
}
if body, ok := req.Context().Value(bodyContextKey{}).(map[string]any); ok {
return body
}
return nil
}
// shouldParseBody checks if the request body should be parsed as JSON
func shouldParseBody(req *http.Request) bool {
if req.Method != "POST" && req.Method != "PUT" && req.Method != "PATCH" {
return false
}
contentType := req.Header.Get("Content-Type")
return strings.HasPrefix(contentType, "application/json") && req.Body != nil
}
// parseJSONBody reads and parses the JSON body from the request
// Returns the parsed body map and the original body bytes for restoration
func parseJSONBody(req *http.Request) (map[string]any, []byte, error) {
defer req.Body.Close()
bodyBytes, err := io.ReadAll(req.Body)
if err != nil {
return nil, nil, err
}
var body map[string]any
if err := json.Unmarshal(bodyBytes, &body); err != nil {
return nil, bodyBytes, err
}
return body, bodyBytes, nil
}
// parseAndStoreBody parses the JSON body if needed and stores it in context.
func parseAndStoreBody(req *http.Request) *http.Request {
if GetJSONBody(req) != nil {
return req
}
if !shouldParseBody(req) {
return req
}
body, bodyBytes, err := parseJSONBody(req)
if err != nil {
return req
}
req = req.WithContext(context.WithValue(req.Context(), bodyContextKey{}, body))
// Restore body for handlers that need to read it
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
return req
}
func getCurrentRouteFromContext(ctx context.Context) *route {
if route, ok := ctx.Value(currentRouteContextKey{}).(*route); ok {
return route
}
return nil
}