(cli, srv *bufConn)
| 1047 | } |
| 1048 | |
| 1049 | func (p *proxy) proxyHTTP2(cli, srv *bufConn) error { |
| 1050 | slog.Debug("starting proxyHTTP2", "proxy", p) |
| 1051 | |
| 1052 | preface := make([]byte, len(http2.ClientPreface)) |
| 1053 | if _, err := io.ReadFull(cli, preface); err != nil { |
| 1054 | return fmt.Errorf("read preface: %w", err) |
| 1055 | } |
| 1056 | if string(preface) != http2.ClientPreface { |
| 1057 | return fmt.Errorf("bad preface") |
| 1058 | } |
| 1059 | if _, err := srv.Write(preface); err != nil { |
| 1060 | return fmt.Errorf("write preface: %w", err) |
| 1061 | } |
| 1062 | |
| 1063 | var mu sync.Mutex |
| 1064 | state := make(map[uint32]*http2Stream) |
| 1065 | |
| 1066 | getStream := func(streamID uint32) *http2Stream { |
| 1067 | mu.Lock() |
| 1068 | defer mu.Unlock() |
| 1069 | |
| 1070 | st, ok := state[streamID] |
| 1071 | if !ok { |
| 1072 | st = p.newHTTP2Stream(streamID) |
| 1073 | state[streamID] = st |
| 1074 | go func() { |
| 1075 | st.active.Wait() |
| 1076 | mu.Lock() |
| 1077 | defer mu.Unlock() |
| 1078 | delete(state, streamID) |
| 1079 | }() |
| 1080 | } |
| 1081 | return st |
| 1082 | } |
| 1083 | |
| 1084 | copySingle := func(dst *http2.Framer, src *http2.Framer, isClient bool) error { |
| 1085 | dec := hpack.NewDecoder(4096, nil) |
| 1086 | for { |
| 1087 | fr, err := src.ReadFrame() |
| 1088 | switch { |
| 1089 | case err == nil: |
| 1090 | case errors.Is(err, io.EOF): |
| 1091 | return nil |
| 1092 | case errors.Is(err, net.ErrClosed): |
| 1093 | return nil |
| 1094 | case strings.Contains(err.Error(), "connection reset by peer"): |
| 1095 | return nil |
| 1096 | default: |
| 1097 | return fmt.Errorf("read frame: %w", err) |
| 1098 | } |
| 1099 | |
| 1100 | switch fr := fr.(type) { |
| 1101 | case *http2.HeadersFrame: |
| 1102 | st := getStream(fr.StreamID) |
| 1103 | |
| 1104 | headers, err := dec.DecodeFull(fr.HeaderBlockFragment()) |
| 1105 | if err != nil { |
| 1106 | return fmt.Errorf("%T: decode fields: %w", fr, err) |
no test coverage detected