1
0
mirror of https://github.com/golang/go synced 2024-11-16 22:14:45 -07:00

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 <dneil@google.com>
Auto-Submit: Damien Neil <dneil@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Akshay Shah 2022-08-22 16:08:13 -07:00 committed by Gopher Robot
parent bcd1ac7120
commit 4d13aabdf6
2 changed files with 82 additions and 0 deletions

38
src/net/http/h2_error.go Normal file
View File

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

View File

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