1
2
3
4
5 package http3
6
7 import (
8 "errors"
9 "fmt"
10 "io"
11 "net"
12 "net/http"
13 "net/textproto"
14 "strings"
15 "sync"
16
17 "golang.org/x/net/http/httpguts"
18 )
19
20
21
22
23 func extractTrailerFromHeader(header, trailer http.Header) {
24 for _, names := range header["Trailer"] {
25 names = textproto.TrimString(names)
26 for name := range strings.SplitSeq(names, ",") {
27 name = textproto.CanonicalMIMEHeaderKey(textproto.TrimString(name))
28 if !httpguts.ValidTrailerHeader(name) {
29 continue
30 }
31 trailer[name] = nil
32 }
33 }
34 }
35
36
37
38 type bodyWriter struct {
39 st *stream
40 remain int64
41 flush bool
42 name string
43 trailer http.Header
44 enc *qpackEncoder
45 }
46
47 func (w *bodyWriter) write(ps ...[]byte) (n int, err error) {
48 var size int64
49 for _, p := range ps {
50 size += int64(len(p))
51 }
52
53
54 if size == 0 {
55 return 0, nil
56 }
57 if w.remain >= 0 && size > w.remain {
58 return 0, &streamError{
59 code: errH3InternalError,
60 message: w.name + " body longer than specified content length",
61 }
62 }
63 w.st.writeVarint(int64(frameTypeData))
64 w.st.writeVarint(size)
65 for _, p := range ps {
66 var n2 int
67 n2, err = w.st.Write(p)
68 n += n2
69 if w.remain >= 0 {
70 w.remain -= int64(n)
71 }
72 if err != nil {
73 break
74 }
75 }
76 if w.flush && err == nil {
77 err = w.st.Flush()
78 }
79 if err != nil {
80 err = fmt.Errorf("writing %v body: %w", w.name, err)
81 }
82 return n, err
83 }
84
85 func (w *bodyWriter) Write(p []byte) (n int, err error) {
86 return w.write(p)
87 }
88
89 func (w *bodyWriter) Close() error {
90 if w.remain > 0 {
91 return errors.New(w.name + " body shorter than specified content length")
92 }
93 if len(w.trailer) > 0 {
94 encTrailer := w.enc.encode(func(f func(itype indexType, name, value string)) {
95 for name, values := range w.trailer {
96 if !httpguts.ValidHeaderFieldName(name) {
97 continue
98 }
99 for _, val := range values {
100 if !httpguts.ValidHeaderFieldValue(val) {
101 continue
102 }
103 f(mayIndex, name, val)
104 }
105 }
106 })
107 w.st.writeVarint(int64(frameTypeHeaders))
108 w.st.writeVarint(int64(len(encTrailer)))
109 w.st.Write(encTrailer)
110 }
111 if w.st != nil {
112 w.st.CloseWrite()
113 }
114 return nil
115 }
116
117
118 type bodyReader struct {
119 st *stream
120
121 mu sync.Mutex
122 remain int64
123 err error
124
125
126
127
128
129
130 trailer http.Header
131 filterTrailer bool
132 }
133
134 func (r *bodyReader) Read(p []byte) (n int, err error) {
135
136
137
138 r.mu.Lock()
139 defer r.mu.Unlock()
140 if r.err != nil {
141 return 0, r.err
142 }
143 defer func() {
144 if err != nil {
145 r.err = err
146 }
147 }()
148 if r.st.lim == 0 {
149
150 if err := r.st.endFrame(); err != nil {
151 return 0, err
152 }
153 }
154
155
156 for r.st.lim < 0 {
157 ftype, err := r.st.readFrameHeader()
158 if err == io.EOF && r.remain > 0 {
159 return 0, &streamError{
160 code: errH3MessageError,
161 message: "body shorter than content-length",
162 }
163 }
164 if err != nil {
165 return 0, err
166 }
167 switch ftype {
168 case frameTypeData:
169 if r.remain >= 0 && r.st.lim > r.remain {
170 return 0, &streamError{
171 code: errH3MessageError,
172 message: "body longer than content-length",
173 }
174 }
175
176 case frameTypeHeaders:
177
178 if r.remain > 0 {
179 return 0, &streamError{
180 code: errH3MessageError,
181 message: "body shorter than content-length",
182 }
183 }
184 var dec qpackDecoder
185 if err := dec.decode(r.st, func(_ indexType, name, value string) error {
186 if r.trailer == nil {
187 return nil
188 }
189 if !validWireHeaderFieldName(name) || !httpguts.ValidHeaderFieldValue(value) {
190 return nil
191 }
192 name = textproto.CanonicalMIMEHeaderKey(textproto.TrimString(name))
193 if !r.filterTrailer {
194 r.trailer.Add(name, value)
195 } else if _, ok := r.trailer[name]; ok {
196 r.trailer.Add(name, value)
197 }
198 return nil
199 }); err != nil {
200 return 0, err
201 }
202 if err := r.st.discardFrame(); err != nil {
203 return 0, err
204 }
205 return 0, io.EOF
206 default:
207 if err := r.st.discardUnknownFrame(ftype); err != nil {
208 return 0, err
209 }
210 }
211 }
212
213
214
215 if int64(len(p)) > r.st.lim {
216 p = p[:r.st.lim]
217 }
218 n, err = r.st.Read(p)
219 if r.remain > 0 {
220 r.remain -= int64(n)
221 }
222 return n, err
223 }
224
225 func (r *bodyReader) Close() error {
226
227
228 r.st.CloseRead()
229
230
231 r.mu.Lock()
232 defer r.mu.Unlock()
233 r.err = net.ErrClosed
234 r.remain = 0
235 return nil
236 }
237
View as plain text