@@ -10,12 +10,15 @@ import (
1010 "net/http"
1111 "net/url"
1212 "os"
13+ "os/signal"
1314 "path"
1415 "strings"
1516 "sync"
1617 "sync/atomic"
18+ "syscall"
1719 "time"
1820
21+ "golang.org/x/net/http2"
1922 "golang.org/x/net/proxy"
2023)
2124
@@ -101,6 +104,7 @@ func createProxyClient(proxyURL string) (*http.Client, error) {
101104 return nil , err
102105 }
103106
107+ var transport * http.Transport
104108 switch urlParsed .Scheme {
105109 case "socks5" , "socks5h" :
106110 auth := & proxy.Auth {
@@ -118,25 +122,33 @@ func createProxyClient(proxyURL string) (*http.Client, error) {
118122 return nil , err
119123 }
120124
121- transport : = & http.Transport {
125+ transport = & http.Transport {
122126 DialContext : func (ctx context.Context , network , addr string ) (net.Conn , error ) {
123127 return dialer .Dial (network , addr )
124128 },
129+ MaxIdleConns : 100 ,
130+ MaxIdleConnsPerHost : 20 ,
131+ IdleConnTimeout : 90 * time .Second ,
125132 }
126- return & http.Client {Transport : transport }, nil
127133
128134 case "http" , "https" :
129- transport : = & http.Transport {
135+ transport = & http.Transport {
130136 Proxy : http .ProxyURL (urlParsed ),
131137 DialContext : (& net.Dialer {
132138 Timeout : 30 * time .Second ,
133139 KeepAlive : 30 * time .Second ,
134140 }).DialContext ,
135141 }
136- return & http.Client {Transport : transport }, nil
142+ default :
143+ return nil , fmt .Errorf ("unsupported proxy scheme: %s" , urlParsed .Scheme )
137144 }
138145
139- return nil , fmt .Errorf ("unsupported proxy scheme: %s" , urlParsed .Scheme )
146+ // Enable HTTP/2 support for the transport
147+ if err := http2 .ConfigureTransport (transport ); err != nil {
148+ return nil , fmt .Errorf ("failed to configure HTTP/2: %v" , err )
149+ }
150+
151+ return & http.Client {Transport : transport , Timeout : 30 * time .Second }, nil
140152}
141153
142154func NewProxyServer (configPath string ) (* ProxyServer , error ) {
@@ -150,12 +162,33 @@ func NewProxyServer(configPath string) (*ProxyServer, error) {
150162 return nil , fmt .Errorf ("failed to parse config: %v" , err )
151163 }
152164
165+ // Validate site configurations
166+ for siteName , siteConfig := range config .Sites {
167+ allowedProxyTypes := map [string ]bool {"header" : true , "query" : true , "path" : true , "direct" : true }
168+ if ! allowedProxyTypes [siteConfig .ProxyType ] {
169+ return nil , fmt .Errorf ("invalid PROXY_TYPE %s for site %s" , siteConfig .ProxyType , siteName )
170+ }
171+
172+ if siteConfig .ProxyType == "direct" {
173+ for _ , keyLimit := range siteConfig .Values {
174+ for key := range keyLimit {
175+ if _ , err := url .Parse (key ); err != nil {
176+ return nil , fmt .Errorf ("invalid URL in direct proxy VALUES for site %s: %v" , siteName , key )
177+ }
178+ }
179+ }
180+ } else if (siteConfig .ProxyType == "header" || siteConfig .ProxyType == "query" ) && siteConfig .Key == "" {
181+ return nil , fmt .Errorf ("PROXY_TYPE %s requires KEY for site %s" , siteConfig .ProxyType , siteName )
182+ }
183+ }
184+
153185 server := & ProxyServer {
154186 config : config ,
155187 clients : make ([]ClientWrapper , 0 ),
156188 sites : make (map [string ]* SiteHandler ),
157189 }
158190
191+ // Initialize site handlers
159192 for siteName , siteConfig := range config .Sites {
160193 handler := & SiteHandler {
161194 config : siteConfig ,
@@ -176,13 +209,19 @@ func NewProxyServer(configPath string) (*ProxyServer, error) {
176209 server .sites [siteName ] = handler
177210 }
178211
212+ // Initialize direct client if enabled
179213 if config .GlobalSettings .DirectAccess {
214+ transport := & http.Transport {}
215+ if err := http2 .ConfigureTransport (transport ); err != nil {
216+ log .Printf ("Failed to configure HTTP/2 for direct client: %v" , err )
217+ }
180218 server .clients = append (server .clients , ClientWrapper {
181- Client : & http.Client {Timeout : 30 * time .Second },
219+ Client : & http.Client {Transport : transport , Timeout : 30 * time .Second },
182220 IsDirect : true ,
183221 })
184222 }
185223
224+ // Initialize proxy clients
186225 for _ , proxyURL := range config .GlobalSettings .Proxies {
187226 client , err := createProxyClient (proxyURL )
188227 if err != nil {
@@ -195,6 +234,7 @@ func NewProxyServer(configPath string) (*ProxyServer, error) {
195234 })
196235 }
197236
237+ // Ensure at least one client is available
198238 if len (server .clients ) == 0 {
199239 return nil , fmt .Errorf ("no working clients available" )
200240 }
@@ -237,7 +277,6 @@ func (s *ProxyServer) handleRequest(w http.ResponseWriter, r *http.Request) {
237277 return
238278 }
239279
240- // Handle base path
241280 basePath := s .config .GlobalSettings .BasePath
242281 if basePath == "" {
243282 basePath = "/proxy"
@@ -249,7 +288,6 @@ func (s *ProxyServer) handleRequest(w http.ResponseWriter, r *http.Request) {
249288 return
250289 }
251290
252- // Process remaining path after base path
253291 remainingPath := strings .TrimPrefix (r .URL .Path , basePath )
254292 remainingPath = strings .Trim (remainingPath , "/" )
255293
@@ -344,7 +382,6 @@ func (s *ProxyServer) handleRequest(w http.ResponseWriter, r *http.Request) {
344382 q .Set (siteHandler .config .Key , apiKey )
345383 outReq .URL .RawQuery = q .Encode ()
346384 case "path" :
347- // Already handled in path construction
348385 default :
349386 log .Printf ("Unknown PROXY_TYPE: %s" , siteHandler .config .ProxyType )
350387 }
@@ -375,8 +412,8 @@ func (s *ProxyServer) handleRequest(w http.ResponseWriter, r *http.Request) {
375412 outReq .Header .Del (header )
376413 }
377414
378- outReq .Header .Set ("Accept" , "application/json" )
379- outReq .Header .Set ("Content-Type" , "application/json" )
415+ // outReq.Header.Set("Accept", "application/json")
416+ // outReq.Header.Set("Content-Type", "application/json")
380417
381418 resp , err := client .Client .Do (outReq )
382419 if err != nil {
@@ -397,15 +434,11 @@ func (s *ProxyServer) handleRequest(w http.ResponseWriter, r *http.Request) {
397434 }
398435 }
399436
400- bodyBytes , err := io .ReadAll (resp .Body )
437+ w .WriteHeader (resp .StatusCode )
438+ _ , err = io .Copy (w , resp .Body )
401439 if err != nil {
402- log .Printf ("Failed to read response body: %v" , err )
403- http .Error (w , "Failed to read response" , http .StatusInternalServerError )
404- return
440+ log .Printf ("Failed to stream response: %v" , err )
405441 }
406-
407- w .WriteHeader (resp .StatusCode )
408- _ , _ = w .Write (bodyBytes )
409442}
410443
411444func main () {
@@ -422,7 +455,25 @@ func main() {
422455 http .HandleFunc ("/" , server .handleRequest )
423456
424457 log .Printf ("Starting proxy server on :3000" )
425- if err := http .ListenAndServe (":3000" , nil ); err != nil {
426- log .Fatalf ("Server error: %v" , err )
458+
459+ srv := & http.Server {
460+ Addr : ":3000" ,
461+ Handler : nil ,
462+ }
463+
464+ go func () {
465+ if err := srv .ListenAndServe (); err != nil {
466+ log .Fatalf ("Server error: %v" , err )
467+ }
468+ }()
469+
470+ stop := make (chan os.Signal , 1 )
471+ signal .Notify (stop , os .Interrupt , syscall .SIGTERM )
472+ <- stop
473+
474+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
475+ defer cancel ()
476+ if err := srv .Shutdown (ctx ); err != nil {
477+ log .Printf ("Server shutdown error: %v" , err )
427478 }
428479}
0 commit comments