aboutsummaryrefslogtreecommitdiff
path: root/src/net/http
diff options
context:
space:
mode:
authorRandy Reddig <randy.reddig@fastly.com>2025-12-03 20:33:09 +0000
committerSean Liao <sean@liao.dev>2026-02-04 14:44:58 -0800
commitf2e7fa6d31143b2d9fbb94df7aa05b3a0919d112 (patch)
treec8906cce153bcc0c4934721ef5a8df8850d2b78f /src/net/http
parent044fe174d7a45ab0c7872500de63e6c61b01bf27 (diff)
downloadgo-f2e7fa6d31143b2d9fbb94df7aa05b3a0919d112.tar.xz
net/http/httptrace: compose ClientTrace without reflect
This is to enable use of package httptrace on TinyGo, which does not have an implementation of reflect.MakeFunc. Change-Id: I4f1f94352797bfe3553c1c2d4d1d3dca44b03e43 GitHub-Last-Rev: 4587368ad875bd55e6a8cbdcd7e13738a8d02400 GitHub-Pull-Request: golang/go#69172 Reviewed-on: https://go-review.googlesource.com/c/go/+/609763 Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Carlos Amedee <carlos@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Sean Liao <sean@liao.dev>
Diffstat (limited to 'src/net/http')
-rw-r--r--src/net/http/httptrace/trace.go105
1 files changed, 78 insertions, 27 deletions
diff --git a/src/net/http/httptrace/trace.go b/src/net/http/httptrace/trace.go
index cee13d2da8..e835c32404 100644
--- a/src/net/http/httptrace/trace.go
+++ b/src/net/http/httptrace/trace.go
@@ -12,7 +12,6 @@ import (
"internal/nettrace"
"net"
"net/textproto"
- "reflect"
"time"
)
@@ -176,34 +175,86 @@ func (t *ClientTrace) compose(old *ClientTrace) {
if old == nil {
return
}
- tv := reflect.ValueOf(t).Elem()
- ov := reflect.ValueOf(old).Elem()
- structType := tv.Type()
- for i := 0; i < structType.NumField(); i++ {
- tf := tv.Field(i)
- hookType := tf.Type()
- if hookType.Kind() != reflect.Func {
- continue
- }
- of := ov.Field(i)
- if of.IsNil() {
- continue
- }
- if tf.IsNil() {
- tf.Set(of)
- continue
- }
+ t.GetConn = compose1to0(t.GetConn, old.GetConn)
+ t.GotConn = compose1to0(t.GotConn, old.GotConn)
+ t.PutIdleConn = compose1to0(t.PutIdleConn, old.PutIdleConn)
+ t.GotFirstResponseByte = compose0to0(t.GotFirstResponseByte, old.GotFirstResponseByte)
+ t.Got100Continue = compose0to0(t.Got100Continue, old.Got100Continue)
+ t.Got1xxResponse = compose2to1(t.Got1xxResponse, old.Got1xxResponse)
+ t.DNSStart = compose1to0(t.DNSStart, old.DNSStart)
+ t.DNSDone = compose1to0(t.DNSDone, old.DNSDone)
+ t.ConnectStart = compose2to0(t.ConnectStart, old.ConnectStart)
+ t.ConnectDone = compose3to0(t.ConnectDone, old.ConnectDone)
+ t.TLSHandshakeStart = compose0to0(t.TLSHandshakeStart, old.TLSHandshakeStart)
+ t.TLSHandshakeDone = compose2to0(t.TLSHandshakeDone, old.TLSHandshakeDone)
+ t.WroteHeaderField = compose2to0(t.WroteHeaderField, old.WroteHeaderField)
+ t.WroteHeaders = compose0to0(t.WroteHeaders, old.WroteHeaders)
+ t.Wait100Continue = compose0to0(t.Wait100Continue, old.Wait100Continue)
+ t.WroteRequest = compose1to0(t.WroteRequest, old.WroteRequest)
+}
- // Make a copy of tf for tf to call. (Otherwise it
- // creates a recursive call cycle and stack overflows)
- tfCopy := reflect.ValueOf(tf.Interface())
+func compose0to0[F func()](f1, f2 F) F {
+ if f1 == nil {
+ return f2
+ }
+ if f2 == nil {
+ return f1
+ }
+ return func() {
+ f1()
+ f2()
+ }
+}
+
+func compose1to0[F func(A), A any](f1, f2 F) F {
+ if f1 == nil {
+ return f2
+ }
+ if f2 == nil {
+ return f1
+ }
+ return func(a A) {
+ f1(a)
+ f2(a)
+ }
+}
- // We need to call both tf and of in some order.
- newFunc := reflect.MakeFunc(hookType, func(args []reflect.Value) []reflect.Value {
- tfCopy.Call(args)
- return of.Call(args)
- })
- tv.Field(i).Set(newFunc)
+func compose2to0[F func(A, B), A, B any](f1, f2 F) F {
+ if f1 == nil {
+ return f2
+ }
+ if f2 == nil {
+ return f1
+ }
+ return func(a A, b B) {
+ f1(a, b)
+ f2(a, b)
+ }
+}
+
+func compose2to1[F func(A, B) R, A, B, R any](f1, f2 F) F {
+ if f1 == nil {
+ return f2
+ }
+ if f2 == nil {
+ return f1
+ }
+ return func(a A, b B) R {
+ f1(a, b)
+ return f2(a, b)
+ }
+}
+
+func compose3to0[F func(A, B, C), A, B, C any](f1, f2 F) F {
+ if f1 == nil {
+ return f2
+ }
+ if f2 == nil {
+ return f1
+ }
+ return func(a A, b B, c C) {
+ f1(a, b, c)
+ f2(a, b, c)
}
}