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

@ -219,6 +219,17 @@ 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 {
// Check for GOAWAY error and retry once if applicable
const goawayMsg = "http2: Transport received Server's graceful shutdown GOAWAY"
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 { if err != nil {
tracing.EndWithErrorStatus(ttfbSpan, err) tracing.EndWithErrorStatus(ttfbSpan, err)
if err := roundTripReq.Context().Err(); err != nil { if err := roundTripReq.Context().Err(); err != nil {
@ -226,6 +237,7 @@ func (p *Proxy) proxyHTTPRequest(
} }
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)
defer resp.Body.Close() defer resp.Body.Close()

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)
}
}