From 4d13aabdf62a15d19a6f41a781aa7e85f02f3f26 Mon Sep 17 00:00:00 2001 From: Akshay Shah Date: Mon, 22 Aug 2022 16:08:13 -0700 Subject: [PATCH] net/http: add errors.As support for x/net/http2.StreamError To make it easier to extract the HTTP/2 error code (if any) from net/http errors, implement an As method on the vendored copy of golang.org/x/net/http2.StreamError. The new As method lets users work with the vendored error type as though it were the x/net/http2 StreamError. Fixes #53896. Change-Id: Ib18eb428adc05a3c0e19a946ece936e2378e1c7c Reviewed-on: https://go-review.googlesource.com/c/go/+/425104 Run-TryBot: Damien Neil Auto-Submit: Damien Neil TryBot-Result: Gopher Robot Reviewed-by: Damien Neil Reviewed-by: David Chase --- src/net/http/h2_error.go | 38 ++++++++++++++++++++++++++++++ src/net/http/h2_error_test.go | 44 +++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/net/http/h2_error.go create mode 100644 src/net/http/h2_error_test.go diff --git a/src/net/http/h2_error.go b/src/net/http/h2_error.go new file mode 100644 index 00000000000..0391d31e5b4 --- /dev/null +++ b/src/net/http/h2_error.go @@ -0,0 +1,38 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !nethttpomithttp2 +// +build !nethttpomithttp2 + +package http + +import ( + "reflect" +) + +func (e http2StreamError) As(target any) bool { + dst := reflect.ValueOf(target).Elem() + dstType := dst.Type() + if dstType.Kind() != reflect.Struct { + return false + } + src := reflect.ValueOf(e) + srcType := src.Type() + numField := srcType.NumField() + if dstType.NumField() != numField { + return false + } + for i := 0; i < numField; i++ { + sf := srcType.Field(i) + df := dstType.Field(i) + if sf.Name != df.Name || !sf.Type.ConvertibleTo(df.Type) { + return false + } + } + for i := 0; i < numField; i++ { + df := dst.Field(i) + df.Set(src.Field(i).Convert(df.Type())) + } + return true +} diff --git a/src/net/http/h2_error_test.go b/src/net/http/h2_error_test.go new file mode 100644 index 00000000000..0d85e2f36c3 --- /dev/null +++ b/src/net/http/h2_error_test.go @@ -0,0 +1,44 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !nethttpomithttp2 +// +build !nethttpomithttp2 + +package http + +import ( + "errors" + "fmt" + "testing" +) + +type externalStreamErrorCode uint32 + +type externalStreamError struct { + StreamID uint32 + Code externalStreamErrorCode + Cause error +} + +func (e externalStreamError) Error() string { + return fmt.Sprintf("ID %v, code %v", e.StreamID, e.Code) +} + +func TestStreamError(t *testing.T) { + var target externalStreamError + streamErr := http2streamError(42, http2ErrCodeProtocol) + ok := errors.As(streamErr, &target) + if !ok { + t.Fatalf("errors.As failed") + } + if target.StreamID != streamErr.StreamID { + t.Errorf("got StreamID %v, expected %v", target.StreamID, streamErr.StreamID) + } + if target.Cause != streamErr.Cause { + t.Errorf("got Cause %v, expected %v", target.Cause, streamErr.Cause) + } + if uint32(target.Code) != uint32(streamErr.Code) { + t.Errorf("got Code %v, expected %v", target.Code, streamErr.Code) + } +}