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(n2)
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 maxHeaderBytes int64
133 maxHeaderValueCount int64
134 }
135
136 func (r *bodyReader) Read(p []byte) (n int, err error) {
137
138
139
140 r.mu.Lock()
141 defer r.mu.Unlock()
142 if r.err != nil {
143 return 0, r.err
144 }
145 defer func() {
146 if err != nil {
147 r.err = err
148 }
149 }()
150 if r.st.lim == 0 {
151
152 if err := r.st.endFrame(); err != nil {
153 return 0, err
154 }
155 }
156
157
158 for r.st.lim < 0 {
159 ftype, err := r.st.readFrameHeader()
160 if err == io.EOF && r.remain > 0 {
161 return 0, &streamError{
162 code: errH3MessageError,
163 message: "body shorter than content-length",
164 }
165 }
166 if err != nil {
167 return 0, err
168 }
169 switch ftype {
170 case frameTypeData:
171 if r.remain >= 0 && r.st.lim > r.remain {
172 return 0, &streamError{
173 code: errH3MessageError,
174 message: "body longer than content-length",
175 }
176 }
177
178 case frameTypeHeaders:
179
180 if r.remain > 0 {
181 return 0, &streamError{
182 code: errH3MessageError,
183 message: "body shorter than content-length",
184 }
185 }
186
187
188 if r.maxHeaderBytes > 0 && r.st.lim > r.maxHeaderBytes {
189 return 0, errHeadersTooLarge
190 }
191 var dec qpackDecoder
192 var totalSize, valueCount int64
193 if err := dec.decode(r.st, func(_ indexType, name, value string) error {
194 totalSize += int64(len(name)) + int64(len(value)) + headerFieldOverhead
195 valueCount++
196 if (r.maxHeaderBytes > 0 && totalSize > r.maxHeaderBytes) ||
197 (r.maxHeaderValueCount > 0 && valueCount > r.maxHeaderValueCount) {
198 return errHeadersTooLarge
199 }
200 if r.trailer == nil {
201 return nil
202 }
203 if !validWireHeaderFieldName(name) || !httpguts.ValidHeaderFieldValue(value) {
204 return nil
205 }
206 name = textproto.CanonicalMIMEHeaderKey(textproto.TrimString(name))
207 if !r.filterTrailer {
208 r.trailer.Add(name, value)
209 } else if _, ok := r.trailer[name]; ok {
210 r.trailer.Add(name, value)
211 }
212 return nil
213 }); err != nil {
214 return 0, err
215 }
216 if err := r.st.discardFrame(); err != nil {
217 return 0, err
218 }
219 return 0, io.EOF
220 default:
221 if err := r.st.discardUnknownFrame(ftype); err != nil {
222 return 0, err
223 }
224 }
225 }
226
227
228
229 if int64(len(p)) > r.st.lim {
230 p = p[:r.st.lim]
231 }
232 n, err = r.st.Read(p)
233 if r.remain > 0 {
234 r.remain -= int64(n)
235 }
236 return n, err
237 }
238
239 func (r *bodyReader) Close() error {
240
241
242 r.st.CloseRead(uint64(errH3NoError))
243
244
245 r.mu.Lock()
246 defer r.mu.Unlock()
247 r.err = net.ErrClosed
248 r.remain = 0
249 return nil
250 }
251
View as plain text