5
5
"context"
6
6
"fmt"
7
7
"io"
8
- "net"
9
8
"net/http"
10
9
"net/url"
11
10
"time"
@@ -27,13 +26,13 @@ type ProxyController interface {
27
26
}
28
27
29
28
type proxyController struct {
30
- ctx context.Context
31
- cfg * config.Config
32
- logger logging.Logger
33
- metrics metric.MetricService
34
- target * url.URL
35
- mirror * url.URL
36
- transport * http.Transport
29
+ ctx context.Context
30
+ cfg * config.Config
31
+ logger logging.Logger
32
+ metrics metric.MetricService
33
+ target * url.URL
34
+ mirror * url.URL
35
+ client * http.Client
37
36
}
38
37
39
38
type requestType string
@@ -70,27 +69,62 @@ func NewProxyController(
70
69
logger .Fatalf ("invalid mirror URL: %v" , err )
71
70
}
72
71
}
73
- // Configure transport with timeouts
74
- transport := & http.Transport {
75
- Proxy : http .ProxyFromEnvironment ,
76
- DialContext : ( & net. Dialer {
77
- Timeout : cfg . Proxy . DialTimeout ,
78
- }). DialContext ,
79
- ForceAttemptHTTP2 : true ,
80
- IdleConnTimeout : cfg . Proxy . IdleTimeout ,
72
+
73
+ client := & http.Client {
74
+ CheckRedirect : func ( req * http.Request , via [] * http. Request ) error {
75
+ if len ( via ) >= 10 {
76
+ return fmt . Errorf ( "stopped after 10 redirects" )
77
+ }
78
+ return nil
79
+ } ,
81
80
}
82
81
83
82
return & proxyController {
84
- ctx : ctx ,
85
- cfg : cfg ,
86
- logger : logger ,
87
- metrics : metrics ,
88
- target : target ,
89
- mirror : mirror ,
90
- transport : transport ,
83
+ ctx : ctx ,
84
+ cfg : cfg ,
85
+ logger : logger ,
86
+ metrics : metrics ,
87
+ target : target ,
88
+ mirror : mirror ,
89
+ client : client ,
91
90
}
92
91
}
93
92
93
+ func (_this proxyController ) createRequest (
94
+ ctx context.Context ,
95
+ originalReq * http.Request ,
96
+ bodyBytes []byte ,
97
+ ) (* http.Request , error ) {
98
+ // Create new request with appropriate context
99
+ newReq , err := http .NewRequestWithContext (
100
+ ctx ,
101
+ originalReq .Method ,
102
+ originalReq .URL .String (),
103
+ bytes .NewBuffer (bodyBytes ),
104
+ )
105
+ if err != nil {
106
+ return nil , fmt .Errorf ("failed to create request: %w" , err )
107
+ }
108
+
109
+ // Copy headers from original request
110
+ for k , vv := range originalReq .Header {
111
+ for _ , v := range vv {
112
+ newReq .Header .Add (k , v )
113
+ }
114
+ }
115
+
116
+ // Add Content-Length header if body exists
117
+ if len (bodyBytes ) > 0 {
118
+ newReq .Header .Add ("Content-Length" , fmt .Sprintf ("%d" , len (bodyBytes )))
119
+ // Ensure content type is preserved
120
+ if contentType := originalReq .Header .Get ("Content-Type" ); contentType != "" {
121
+ newReq .Header .Set ("Content-Type" , contentType )
122
+ }
123
+ }
124
+
125
+ return newReq , nil
126
+ }
127
+
94
128
func (_this proxyController ) proxyRequest (c * gin.Context ) {
95
129
// Read the original request body
96
130
bodyBytes , err := io .ReadAll (c .Request .Body )
@@ -99,14 +133,24 @@ func (_this proxyController) proxyRequest(c *gin.Context) {
99
133
c .JSON (http .StatusInternalServerError , gin.H {"error" : "failed to read request" })
100
134
return
101
135
}
102
- // Ignore error since we are closing the body anyway
103
136
_ = c .Request .Body .Close ()
104
137
138
+ // Restore the request body for downstream middleware/handlers
139
+ c .Request .Body = io .NopCloser (bytes .NewBuffer (bodyBytes ))
140
+
141
+ // Create proxy request
142
+ proxyReq , err := _this .createRequest (c .Request .Context (), c .Request , bodyBytes )
143
+ if err != nil {
144
+ _this .logger .Errorw ("failed to create proxy request" , "error" , err )
145
+ c .JSON (http .StatusInternalServerError , gin.H {"error" : "failed to create request" })
146
+ return
147
+ }
148
+
105
149
// Handle proxy request
106
150
_this .handleRequest (requestContext {
107
151
reqType : proxyRequest ,
108
152
ginContext : c ,
109
- request : c . Request ,
153
+ request : proxyReq ,
110
154
bodyBytes : bodyBytes ,
111
155
startTime : time .Now (),
112
156
targetURL : _this .target ,
@@ -118,9 +162,15 @@ func (_this proxyController) proxyRequest(c *gin.Context) {
118
162
ctx , cancel := context .WithTimeout (_this .ctx , _this .cfg .Proxy .MirrorTimeout )
119
163
defer cancel ()
120
164
165
+ mirrorReq , err := _this .createRequest (ctx , c .Request , bodyBytes )
166
+ if err != nil {
167
+ _this .logger .Errorw ("failed to create mirror request" , "error" , err )
168
+ return
169
+ }
170
+
121
171
_this .handleRequest (requestContext {
122
172
reqType : mirrorRequest ,
123
- request : c . Request . Clone ( ctx ) ,
173
+ request : mirrorReq ,
124
174
bodyBytes : bodyBytes ,
125
175
startTime : time .Now (),
126
176
targetURL : _this .mirror ,
@@ -131,7 +181,7 @@ func (_this proxyController) proxyRequest(c *gin.Context) {
131
181
132
182
func (_this proxyController ) handleRequest (reqCtx requestContext ) {
133
183
// Prepare the request
134
- req := reqCtx .request . Clone ( reqCtx . request . Context ())
184
+ req := reqCtx .request
135
185
req .URL .Scheme = reqCtx .targetURL .Scheme
136
186
req .URL .Host = reqCtx .targetURL .Host
137
187
req .Host = reqCtx .targetURL .Host
@@ -155,7 +205,7 @@ func (_this proxyController) handleRequest(reqCtx requestContext) {
155
205
}
156
206
157
207
// Make the request
158
- resp , err := _this .transport . RoundTrip (req )
208
+ resp , err := _this .client . Do (req )
159
209
if err != nil {
160
210
_this .logger .Errorw (fmt .Sprintf ("%s error" , reqCtx .reqType ), "error" , err )
161
211
if reqCtx .reqType == proxyRequest {
0 commit comments