This commit is contained in:
Ganey 2025-11-22 22:58:30 -05:00 committed by GitHub
commit 0e5a02095c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 75 additions and 4 deletions

View File

@ -220,11 +220,23 @@ func (p *Proxy) proxyHTTPRequest(
_, ttfbSpan := tr.Tracer().Start(tr.Context(), "ttfb_origin") _, ttfbSpan := tr.Tracer().Start(tr.Context(), "ttfb_origin")
resp, err := httpService.RoundTrip(roundTripReq) resp, err := httpService.RoundTrip(roundTripReq)
if err != nil { if err != nil {
tracing.EndWithErrorStatus(ttfbSpan, err) // Check for GOAWAY error and retry once if applicable
if err := roundTripReq.Context().Err(); err != nil { const goawayMsg = "http2: Transport received Server's graceful shutdown GOAWAY"
return errors.Wrap(err, "Incoming request ended abruptly") if err.Error() == goawayMsg && roundTripReq.GetBody != nil {
// Reset the body for retry
newBody, getBodyErr := roundTripReq.GetBody()
if getBodyErr == nil {
roundTripReq.Body = newBody
resp, err = httpService.RoundTrip(roundTripReq)
}
}
if err != nil {
tracing.EndWithErrorStatus(ttfbSpan, err)
if err := roundTripReq.Context().Err(); err != nil {
return errors.Wrap(err, "Incoming request ended abruptly")
}
return errors.Wrap(err, "Unable to reach the origin service. The service may be down or it may not be responding to traffic from cloudflared")
} }
return errors.Wrap(err, "Unable to reach the origin service. The service may be down or it may not be responding to traffic from cloudflared")
} }
tracing.EndWithStatusCode(ttfbSpan, resp.StatusCode) tracing.EndWithStatusCode(ttfbSpan, resp.StatusCode)

View File

@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"context" "context"
"errors"
"flag" "flag"
"fmt" "fmt"
"io" "io"
@ -1014,3 +1015,61 @@ func runEchoWSService(t *testing.T, l net.Listener) {
} }
}() }()
} }
func TestHandleGOAWAYRetry(t *testing.T) {
// Simulate a request body
bodyContent := "test body content"
body := io.NopCloser(strings.NewReader(bodyContent))
// Create a mock request with a body
roundTripReq := &http.Request{
Body: body,
}
// Simulate the GOAWAY error
goawayError := errors.New("http2: Transport received Server's graceful shutdown GOAWAY")
// Assign the GetBody function
roundTripReq.GetBody = func() (io.ReadCloser, error) {
if goawayError.Error() == "http2: Transport received Server's graceful shutdown GOAWAY" {
return roundTripReq.Body, nil
}
return nil, goawayError
}
// Test the GetBody function
retriedBody, err := roundTripReq.GetBody()
if err != nil {
t.Fatalf("Expected no error, got: %v", err)
}
// Verify the retried body content
retriedContent, _ := io.ReadAll(retriedBody)
if string(retriedContent) != bodyContent {
t.Fatalf("Expected body content '%s', got '%s'", bodyContent, string(retriedContent))
}
}
func TestHandleGOAWAYRetryError(t *testing.T) {
// Simulate a request body
bodyContent := "test body content"
body := io.NopCloser(strings.NewReader(bodyContent))
// Create a mock request with a body
roundTripReq := &http.Request{
Body: body,
}
// Simulate the GOAWAY error
goawayError := errors.New("http2: Transport received Server's graceful shutdown GOAWAY")
// Assign the GetBody function to return an error
roundTripReq.GetBody = func() (io.ReadCloser, error) {
return nil, goawayError
}
// Test the GetBody function
retriedBody, err := roundTripReq.GetBody()
if retriedBody != nil || err == nil {
t.Fatalf("Expected error, got body: %v, error: %v", retriedBody, err)
}
}