-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathresponse.go
More file actions
126 lines (117 loc) · 3.21 KB
/
response.go
File metadata and controls
126 lines (117 loc) · 3.21 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
package treblle
import (
"encoding/json"
"fmt"
"net/http/httptest"
"time"
)
// Define the maximum response size (2MB in bytes)
const maxResponseSize = 2 * 1024 * 1024
type ResponseInfo struct {
Headers json.RawMessage `json:"headers"`
Code int `json:"code"`
Size int `json:"size"`
LoadTime float64 `json:"load_time"`
Body json.RawMessage `json:"body"`
Errors []ErrorInfo `json:"errors"`
}
// getResponseInfo extracts information from the response matching Laravel SDK structure
func getResponseInfo(response *httptest.ResponseRecorder, startTime time.Time, errorProvider *ErrorProvider) ResponseInfo {
// Process headers (similar to Laravel's collect()->first())
headers := make(map[string]interface{})
for key, values := range response.Header() {
if len(values) == 0 {
continue
}
// For multiple values, keep them as an array
if len(values) > 1 {
// If the field should be masked, mask each value
if shouldMaskField(key) {
maskedValues := make([]interface{}, len(values))
for i := range values {
maskedValues[i] = maskValue(values[i], key)
}
headers[key] = maskedValues
} else {
headers[key] = values
}
} else {
// Single value
if shouldMaskField(key) {
headers[key] = maskValue(values[0], key)
} else {
headers[key] = values[0]
}
}
}
headerJSON, err := json.Marshal(headers)
if err != nil {
headerJSON = json.RawMessage("{}")
errorProvider.AddCustomError(
fmt.Sprintf("failed to marshal response headers: %v", err),
MarshalError,
"getResponseInfo",
)
}
// Get response body
body := response.Body.Bytes()
var bodyJSON json.RawMessage
var size int
if len(body) > 0 {
if len(body) > maxResponseSize {
// Replace with empty JSON object
bodyJSON = json.RawMessage("{}")
// Set size to 0 as we're not sending the actual body
size = 0
errorProvider.AddCustomError(
"JSON response size is over 2MB",
ServerError,
"response_size_limit",
)
} else {
// Check if response is JSON
contentType := response.Header().Get("Content-Type")
if contentType == "application/json" {
maskedBody, err := getMaskedJSON(body)
if err != nil {
bodyJSON = json.RawMessage("{}")
errorProvider.AddCustomError(
fmt.Sprintf("failed to mask response body: %v", err),
MarshalError,
"getResponseInfo",
)
} else {
bodyJSON = maskedBody
}
} else {
// For non-JSON responses, wrap the raw string in JSON quotes
bodyStr := string(body)
bodyBytes, err := json.Marshal(bodyStr)
if err != nil {
bodyJSON = json.RawMessage("{}")
errorProvider.AddCustomError(
fmt.Sprintf("failed to marshal non-JSON response: %v", err),
MarshalError,
"getResponseInfo",
)
} else {
bodyJSON = bodyBytes
}
}
size = len(body)
}
} else {
bodyJSON = json.RawMessage("{}")
size = 0
}
// Calculate load time in milliseconds (matching Laravel's precision)
loadTime := float64(time.Since(startTime).Microseconds()) / 1000.0
return ResponseInfo{
Headers: headerJSON,
Code: response.Code,
Size: size,
LoadTime: loadTime,
Body: bodyJSON,
Errors: errorProvider.GetErrors(),
}
}