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.

`