GRPC: Log user-initiated cancellations as HTTP 408 (#5546)

- Log user-initiated cancellations as HTTP 408 instead of HTTP 500
- Only check status code of `err` if an error was intercepted

Fixes #5444
This commit is contained in:
Samantha 2021-07-30 16:10:16 -07:00 committed by GitHub
parent 0be4679a9b
commit 631f6dfa0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 7 deletions

View File

@ -15,6 +15,7 @@ import (
"google.golang.org/grpc/status"
berrors "github.com/letsencrypt/boulder/errors"
"github.com/letsencrypt/boulder/probs"
)
const (
@ -201,12 +202,15 @@ func (ci *clientInterceptor) intercept(
err := invoker(localCtx, fullMethod, req, reply, cc, opts...)
if err != nil {
err = unwrapError(err, respMD)
}
if status.Code(err) == codes.DeadlineExceeded {
return deadlineDetails{
service: service,
method: method,
latency: ci.clk.Since(begin),
switch status.Code(err) {
case codes.DeadlineExceeded:
return deadlineDetails{
service: service,
method: method,
latency: ci.clk.Since(begin),
}
case codes.Canceled:
return probs.Canceled(err.Error())
}
}
return err

View File

@ -5,6 +5,7 @@ import (
"errors"
"log"
"net"
"net/http"
"strconv"
"strings"
"sync"
@ -16,9 +17,11 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"github.com/letsencrypt/boulder/grpc/test_proto"
"github.com/letsencrypt/boulder/metrics"
"github.com/letsencrypt/boulder/probs"
"github.com/letsencrypt/boulder/test"
)
@ -33,8 +36,11 @@ func testHandler(_ context.Context, i interface{}) (interface{}, error) {
}
func testInvoker(_ context.Context, method string, _, _ interface{}, _ *grpc.ClientConn, opts ...grpc.CallOption) error {
if method == "-service-brokeTest" {
switch method {
case "-service-brokeTest":
return errors.New("")
case "-service-requesterCanceledTest":
return status.Error(1, context.Canceled.Error())
}
fc.Sleep(time.Second)
return nil
@ -71,6 +77,14 @@ func TestClientInterceptor(t *testing.T) {
err = ci.intercept(context.Background(), "-service-brokeTest", nil, nil, nil, testInvoker)
test.AssertError(t, err, "ci.intercept didn't fail when handler returned a error")
err = ci.intercept(context.Background(), "-service-requesterCanceledTest", nil, nil, nil, testInvoker)
test.AssertError(t, err, "ci.intercept didn't fail when handler returned a error")
var probDetails *probs.ProblemDetails
test.AssertErrorWraps(t, err, &probDetails)
test.AssertEquals(t, probDetails.Type, probs.MalformedProblem)
test.AssertEquals(t, probDetails.HTTPStatus, http.StatusRequestTimeout)
}
// TestFailFastFalse sends a gRPC request to a backend that is

View File

@ -161,6 +161,19 @@ func Malformed(detail string, args ...interface{}) *ProblemDetails {
}
}
// Canceled returns a ProblemDetails with a MalformedProblem and a 408 Request
// Timeout status code.
func Canceled(detail string, args ...interface{}) *ProblemDetails {
if len(args) > 0 {
detail = fmt.Sprintf(detail, args...)
}
return &ProblemDetails{
Type: MalformedProblem,
Detail: detail,
HTTPStatus: http.StatusRequestTimeout,
}
}
// BadSignatureAlgorithm returns a ProblemDetails with a BadSignatureAlgorithmProblem
// and a 400 Bad Request status code.
func BadSignatureAlgorithm(detail string, a ...interface{}) *ProblemDetails {