http2, internal/httpcommon: factor out server header logic for h2/h3 · golang/net@1d78a08 (original) (raw)
`@@ -2233,25 +2233,25 @@ func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream
`
2233
2233
`func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*responseWriter, *http.Request, error) {
`
2234
2234
`sc.serveG.check()
`
2235
2235
``
2236
``
`-
rp := requestParam{
`
2237
``
`-
method: f.PseudoValue("method"),
`
2238
``
`-
scheme: f.PseudoValue("scheme"),
`
2239
``
`-
authority: f.PseudoValue("authority"),
`
2240
``
`-
path: f.PseudoValue("path"),
`
2241
``
`-
protocol: f.PseudoValue("protocol"),
`
``
2236
`+
rp := httpcommon.ServerRequestParam{
`
``
2237
`+
Method: f.PseudoValue("method"),
`
``
2238
`+
Scheme: f.PseudoValue("scheme"),
`
``
2239
`+
Authority: f.PseudoValue("authority"),
`
``
2240
`+
Path: f.PseudoValue("path"),
`
``
2241
`+
Protocol: f.PseudoValue("protocol"),
`
2242
2242
` }
`
2243
2243
``
2244
2244
`// extended connect is disabled, so we should not see :protocol
`
2245
``
`-
if disableExtendedConnectProtocol && rp.protocol != "" {
`
``
2245
`+
if disableExtendedConnectProtocol && rp.Protocol != "" {
`
2246
2246
`return nil, nil, sc.countError("bad_connect", streamError(f.StreamID, ErrCodeProtocol))
`
2247
2247
` }
`
2248
2248
``
2249
``
`-
isConnect := rp.method == "CONNECT"
`
``
2249
`+
isConnect := rp.Method == "CONNECT"
`
2250
2250
`if isConnect {
`
2251
``
`-
if rp.protocol == "" && (rp.path != "" || rp.scheme != "" || rp.authority == "") {
`
``
2251
`+
if rp.Protocol == "" && (rp.Path != "" || rp.Scheme != "" || rp.Authority == "") {
`
2252
2252
`return nil, nil, sc.countError("bad_connect", streamError(f.StreamID, ErrCodeProtocol))
`
2253
2253
` }
`
2254
``
`-
} else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") {
`
``
2254
`+
} else if rp.Method == "" || rp.Path == "" || (rp.Scheme != "https" && rp.Scheme != "http") {
`
2255
2255
`// See 8.1.2.6 Malformed Requests and Responses:
`
2256
2256
`//
`
2257
2257
`// Malformed requests or responses that are detected
`
`@@ -2265,15 +2265,16 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
`
2265
2265
`return nil, nil, sc.countError("bad_path_method", streamError(f.StreamID, ErrCodeProtocol))
`
2266
2266
` }
`
2267
2267
``
2268
``
`-
rp.header = make(http.Header)
`
``
2268
`+
header := make(http.Header)
`
``
2269
`+
rp.Header = header
`
2269
2270
`for _, hf := range f.RegularFields() {
`
2270
``
`-
rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value)
`
``
2271
`+
header.Add(sc.canonicalHeader(hf.Name), hf.Value)
`
2271
2272
` }
`
2272
``
`-
if rp.authority == "" {
`
2273
``
`-
rp.authority = rp.header.Get("Host")
`
``
2273
`+
if rp.Authority == "" {
`
``
2274
`+
rp.Authority = header.Get("Host")
`
2274
2275
` }
`
2275
``
`-
if rp.protocol != "" {
`
2276
``
`-
rp.header.Set(":protocol", rp.protocol)
`
``
2276
`+
if rp.Protocol != "" {
`
``
2277
`+
header.Set(":protocol", rp.Protocol)
`
2277
2278
` }
`
2278
2279
``
2279
2280
`rw, req, err := sc.newWriterAndRequestNoBody(st, rp)
`
`@@ -2282,7 +2283,7 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
`
2282
2283
` }
`
2283
2284
`bodyOpen := !f.StreamEnded()
`
2284
2285
`if bodyOpen {
`
2285
``
`-
if vv, ok := rp.header["Content-Length"]; ok {
`
``
2286
`+
if vv, ok := rp.Header["Content-Length"]; ok {
`
2286
2287
`if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil {
`
2287
2288
`req.ContentLength = int64(cl)
`
2288
2289
` } else {
`
`@@ -2298,84 +2299,38 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
`
2298
2299
`return rw, req, nil
`
2299
2300
`}
`
2300
2301
``
2301
``
`-
type requestParam struct {
`
2302
``
`-
method string
`
2303
``
`-
scheme, authority, path string
`
2304
``
`-
protocol string
`
2305
``
`-
header http.Header
`
2306
``
`-
}
`
2307
``
-
2308
``
`-
func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*responseWriter, *http.Request, error) {
`
``
2302
`+
func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp httpcommon.ServerRequestParam) (*responseWriter, *http.Request, error) {
`
2309
2303
`sc.serveG.check()
`
2310
2304
``
2311
2305
`var tlsState *tls.ConnectionState // nil if not scheme https
`
2312
``
`-
if rp.scheme == "https" {
`
``
2306
`+
if rp.Scheme == "https" {
`
2313
2307
`tlsState = sc.tlsState
`
2314
2308
` }
`
2315
2309
``
2316
``
`-
needsContinue := httpguts.HeaderValuesContainsToken(rp.header["Expect"], "100-continue")
`
2317
``
`-
if needsContinue {
`
2318
``
`-
rp.header.Del("Expect")
`
2319
``
`-
}
`
2320
``
`-
// Merge Cookie headers into one "; "-delimited value.
`
2321
``
`-
if cookies := rp.header["Cookie"]; len(cookies) > 1 {
`
2322
``
`-
rp.header.Set("Cookie", strings.Join(cookies, "; "))
`
2323
``
`-
}
`
2324
``
-
2325
``
`-
// Setup Trailers
`
2326
``
`-
var trailer http.Header
`
2327
``
`-
for _, v := range rp.header["Trailer"] {
`
2328
``
`-
for _, key := range strings.Split(v, ",") {
`
2329
``
`-
key = http.CanonicalHeaderKey(textproto.TrimString(key))
`
2330
``
`-
switch key {
`
2331
``
`-
case "Transfer-Encoding", "Trailer", "Content-Length":
`
2332
``
`-
// Bogus. (copy of http1 rules)
`
2333
``
`-
// Ignore.
`
2334
``
`-
default:
`
2335
``
`-
if trailer == nil {
`
2336
``
`-
trailer = make(http.Header)
`
2337
``
`-
}
`
2338
``
`-
trailer[key] = nil
`
2339
``
`-
}
`
2340
``
`-
}
`
2341
``
`-
}
`
2342
``
`-
delete(rp.header, "Trailer")
`
2343
``
-
2344
``
`-
var url_ *url.URL
`
2345
``
`-
var requestURI string
`
2346
``
`-
if rp.method == "CONNECT" && rp.protocol == "" {
`
2347
``
`-
url_ = &url.URL{Host: rp.authority}
`
2348
``
`-
requestURI = rp.authority // mimic HTTP/1 server behavior
`
2349
``
`-
} else {
`
2350
``
`-
var err error
`
2351
``
`-
url_, err = url.ParseRequestURI(rp.path)
`
2352
``
`-
if err != nil {
`
2353
``
`-
return nil, nil, sc.countError("bad_path", streamError(st.id, ErrCodeProtocol))
`
2354
``
`-
}
`
2355
``
`-
requestURI = rp.path
`
``
2310
`+
res := httpcommon.NewServerRequest(rp)
`
``
2311
`+
if res.InvalidReason != "" {
`
``
2312
`+
return nil, nil, sc.countError(res.InvalidReason, streamError(st.id, ErrCodeProtocol))
`
2356
2313
` }
`
2357
2314
``
2358
2315
`body := &requestBody{
`
2359
2316
`conn: sc,
`
2360
2317
`stream: st,
`
2361
``
`-
needsContinue: needsContinue,
`
``
2318
`+
needsContinue: res.NeedsContinue,
`
2362
2319
` }
`
2363
``
`-
req := &http.Request{
`
2364
``
`-
Method: rp.method,
`
2365
``
`-
URL: url_,
`
``
2320
`+
req := (&http.Request{
`
``
2321
`+
Method: rp.Method,
`
``
2322
`+
URL: res.URL,
`
2366
2323
`RemoteAddr: sc.remoteAddrStr,
`
2367
``
`-
Header: rp.header,
`
2368
``
`-
RequestURI: requestURI,
`
``
2324
`+
Header: rp.Header,
`
``
2325
`+
RequestURI: res.RequestURI,
`
2369
2326
`Proto: "HTTP/2.0",
`
2370
2327
`ProtoMajor: 2,
`
2371
2328
`ProtoMinor: 0,
`
2372
2329
`TLS: tlsState,
`
2373
``
`-
Host: rp.authority,
`
``
2330
`+
Host: rp.Authority,
`
2374
2331
`Body: body,
`
2375
``
`-
Trailer: trailer,
`
2376
``
`-
}
`
2377
``
`-
req = req.WithContext(st.ctx)
`
2378
``
-
``
2332
`+
Trailer: res.Trailer,
`
``
2333
`+
}).WithContext(st.ctx)
`
2379
2334
`rw := sc.newResponseWriter(st, req)
`
2380
2335
`return rw, req, nil
`
2381
2336
`}
`
`@@ -3270,12 +3225,12 @@ func (sc *serverConn) startPush(msg *startPushRequest) {
`
3270
3225
`// we start in "half closed (remote)" for simplicity.
`
3271
3226
`// See further comments at the definition of stateHalfClosedRemote.
`
3272
3227
`promised := sc.newStream(promisedID, msg.parent.id, stateHalfClosedRemote)
`
3273
``
`-
rw, req, err := sc.newWriterAndRequestNoBody(promised, requestParam{
`
3274
``
`-
method: msg.method,
`
3275
``
`-
scheme: msg.url.Scheme,
`
3276
``
`-
authority: msg.url.Host,
`
3277
``
`-
path: msg.url.RequestURI(),
`
3278
``
`-
header: cloneHeader(msg.header), // clone since handler runs concurrently with writing the PUSH_PROMISE
`
``
3228
`+
rw, req, err := sc.newWriterAndRequestNoBody(promised, httpcommon.ServerRequestParam{
`
``
3229
`+
Method: msg.method,
`
``
3230
`+
Scheme: msg.url.Scheme,
`
``
3231
`+
Authority: msg.url.Host,
`
``
3232
`+
Path: msg.url.RequestURI(),
`
``
3233
`+
Header: cloneHeader(msg.header), // clone since handler runs concurrently with writing the PUSH_PROMISE
`
3279
3234
` })
`
3280
3235
`if err != nil {
`
3281
3236
`// Should not happen, since we've already validated msg.url.
`