mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-28 13:36:08 +08:00
Merge pull request #1522 from soilSpoon/feature/canceled
feature(proxy): Adds special handling for client cancellations in proxy error handler
This commit is contained in:
@@ -3,6 +3,8 @@ package amp
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -188,6 +190,10 @@ func createReverseProxy(upstreamURL string, secretSource SecretSource) (*httputi
|
|||||||
|
|
||||||
// Error handler for proxy failures
|
// Error handler for proxy failures
|
||||||
proxy.ErrorHandler = func(rw http.ResponseWriter, req *http.Request, err error) {
|
proxy.ErrorHandler = func(rw http.ResponseWriter, req *http.Request, err error) {
|
||||||
|
// Client-side cancellations are common during polling; suppress logging in this case
|
||||||
|
if errors.Is(err, context.Canceled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
log.Errorf("amp upstream proxy error for %s %s: %v", req.Method, req.URL.Path, err)
|
log.Errorf("amp upstream proxy error for %s %s: %v", req.Method, req.URL.Path, err)
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
rw.WriteHeader(http.StatusBadGateway)
|
rw.WriteHeader(http.StatusBadGateway)
|
||||||
|
|||||||
@@ -493,6 +493,30 @@ func TestReverseProxy_ErrorHandler(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReverseProxy_ErrorHandler_ContextCanceled(t *testing.T) {
|
||||||
|
// Test that context.Canceled errors return 499 without generic error response
|
||||||
|
proxy, err := createReverseProxy("http://example.com", NewStaticSecretSource(""))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a canceled context to trigger the cancellation path
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
cancel() // Cancel immediately
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/test", nil).WithContext(ctx)
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
|
||||||
|
// Directly invoke the ErrorHandler with context.Canceled
|
||||||
|
proxy.ErrorHandler(rr, req, context.Canceled)
|
||||||
|
|
||||||
|
// Body should be empty for canceled requests (no JSON error response)
|
||||||
|
body := rr.Body.Bytes()
|
||||||
|
if len(body) > 0 {
|
||||||
|
t.Fatalf("expected empty body for canceled context, got: %s", body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestReverseProxy_FullRoundTrip_Gzip(t *testing.T) {
|
func TestReverseProxy_FullRoundTrip_Gzip(t *testing.T) {
|
||||||
// Upstream returns gzipped JSON without Content-Encoding header
|
// Upstream returns gzipped JSON without Content-Encoding header
|
||||||
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
Reference in New Issue
Block a user