返回 DeepSeek-Reasonix
transport_diagnostic.go
根目录 / internal / provider / transport_diagnostic.go
1 package provider
2
3 import (
4 "errors"
5 "reflect"
6
7 "golang.org/x/net/http2"
8 )
9
10 // HTTP2TransportCode classifies typed transport evidence without authorizing
11 // retries. API response bodies and arbitrary error wording are not evidence.
12 func HTTP2TransportCode(err error) string {
13 var response *APIError
14 if errors.As(err, &response) {
15 return ""
16 }
17 var connection http2.ConnectionError
18 var stream http2.StreamError
19 var goAway http2.GoAwayError
20 var connectionPtr *http2.ConnectionError
21 var streamPtr *http2.StreamError
22 var goAwayPtr *http2.GoAwayError
23 switch {
24 case errors.As(err, &connection):
25 return http2CodeName(uint64(connection))
26 case errors.As(err, &stream):
27 return http2CodeName(uint64(stream.Code))
28 case errors.As(err, &goAway):
29 return http2CodeName(uint64(goAway.ErrCode))
30 case errors.As(err, &connectionPtr) && connectionPtr != nil:
31 return http2CodeName(uint64(*connectionPtr))
32 case errors.As(err, &streamPtr) && streamPtr != nil:
33 return http2CodeName(uint64(streamPtr.Code))
34 case errors.As(err, &goAwayPtr) && goAwayPtr != nil:
35 return http2CodeName(uint64(goAwayPtr.ErrCode))
36 default:
37 return bundledHTTP2Code(err)
38 }
39 }
40
41 func http2CodeName(code uint64) string {
42 if code > uint64(http2.ErrCodeHTTP11Required) {
43 return ""
44 }
45 return http2.ErrCode(code).String()
46 }
47
48 // net/http bundles private equivalents of x/net's types. Inspect only those
49 // exact package/type identities and uint32 fields; unknown layouts fail closed.
50 // Real TLS fixtures guard this adapter against Go toolchain changes.
51 func bundledHTTP2Code(err error) string {
52 if err == nil {
53 return ""
54 }
55 v := reflect.ValueOf(err)
56 if v.Kind() == reflect.Pointer && !v.IsNil() {
57 v = v.Elem()
58 }
59 if v.Type().PkgPath() == "net/http" {
60 switch v.Type().Name() {
61 case "http2ConnectionError":
62 if v.Kind() == reflect.Uint32 {
63 return http2CodeName(v.Uint())
64 }
65 case "http2StreamError":
66 return bundledHTTP2Field(v, "Code")
67 case "http2GoAwayError":
68 return bundledHTTP2Field(v, "ErrCode")
69 }
70 }
71 if joined, ok := err.(interface{ Unwrap() []error }); ok {
72 for _, cause := range joined.Unwrap() {
73 if code := bundledHTTP2Code(cause); code != "" {
74 return code
75 }
76 }
77 return ""
78 }
79 return bundledHTTP2Code(errors.Unwrap(err))
80 }
81
82 func bundledHTTP2Field(v reflect.Value, name string) string {
83 if v.Kind() != reflect.Struct {
84 return ""
85 }
86 field := v.FieldByName(name)
87 if field.IsValid() && field.Kind() == reflect.Uint32 {
88 return http2CodeName(field.Uint())
89 }
90 return ""
91 }
92
92 lines GO