Skip to content

Commit a64b6e7

Browse files
committed
added http-2 support
1 parent 3319429 commit a64b6e7

File tree

4 files changed

+78
-23
lines changed

4 files changed

+78
-23
lines changed

docker-compose.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
services:
22
api-proxy:
33
image: 'ghcr.io/ariadata/api-proxy:latest'
4-
#build:
5-
#context: .
6-
#dockerfile: Dockerfile
4+
build:
5+
context: .
6+
dockerfile: Dockerfile
77
container_name: ${COMPOSE_PROJECT_NAME:-api-proxy}_api-proxy
88
restart: unless-stopped
99
hostname: api-proxy

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ module simple-api-proxy
33
go 1.22.5
44

55
require golang.org/x/net v0.34.0
6+
7+
require golang.org/x/text v0.21.0 // indirect

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
22
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
3+
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
4+
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=

main.go

+71-20
Original file line numberDiff line numberDiff line change
@@ -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

142154
func 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

411444
func 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

Comments
 (0)