forked from quic-go/quic-go
http3: introduce a Settingser to query the client's SETTINGS (#4389)
The http.Request.Body can be type-asserted to a http3.Settingser. The Settings method on this interface blocks until the client's SETTINGS frame has been received.
This commit is contained in:
@@ -37,27 +37,28 @@ type Hijacker interface {
|
||||
StreamCreator() StreamCreator
|
||||
}
|
||||
|
||||
// The body of a http.Request or http.Response.
|
||||
// Settingser allows the server to retrieve the client's SETTINGS.
|
||||
// The http.Request.Body implements this interface.
|
||||
type Settingser interface {
|
||||
// Settings returns the client's HTTP settings.
|
||||
// It blocks until the SETTINGS frame has been received.
|
||||
// Note that it is not guaranteed that this happens during the lifetime of the request.
|
||||
Settings(context.Context) (*Settings, error)
|
||||
}
|
||||
|
||||
// The body is used in the requestBody (for a http.Request) and the responseBody (for a http.Response).
|
||||
type body struct {
|
||||
str quic.Stream
|
||||
|
||||
wasHijacked bool // set when HTTPStream is called
|
||||
}
|
||||
|
||||
var (
|
||||
_ io.ReadCloser = &body{}
|
||||
_ HTTPStreamer = &body{}
|
||||
)
|
||||
|
||||
func newRequestBody(str Stream) *body {
|
||||
return &body{str: str}
|
||||
}
|
||||
|
||||
func (r *body) HTTPStream() Stream {
|
||||
r.wasHijacked = true
|
||||
return r.str
|
||||
}
|
||||
|
||||
func (r *body) StreamID() quic.StreamID { return r.str.StreamID() }
|
||||
func (r *body) wasStreamHijacked() bool {
|
||||
return r.wasHijacked
|
||||
}
|
||||
@@ -72,6 +73,39 @@ func (r *body) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type requestBody struct {
|
||||
body
|
||||
connCtx context.Context
|
||||
rcvdSettings <-chan struct{}
|
||||
getSettings func() *Settings
|
||||
}
|
||||
|
||||
var (
|
||||
_ io.ReadCloser = &requestBody{}
|
||||
_ HTTPStreamer = &requestBody{}
|
||||
_ Settingser = &requestBody{}
|
||||
)
|
||||
|
||||
func newRequestBody(str Stream, connCtx context.Context, rcvdSettings <-chan struct{}, getSettings func() *Settings) *requestBody {
|
||||
return &requestBody{
|
||||
body: body{str: str},
|
||||
connCtx: connCtx,
|
||||
rcvdSettings: rcvdSettings,
|
||||
getSettings: getSettings,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *requestBody) Settings(ctx context.Context) (*Settings, error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, context.Cause(ctx)
|
||||
case <-r.connCtx.Done():
|
||||
return nil, context.Cause(r.connCtx)
|
||||
case <-r.rcvdSettings:
|
||||
return r.getSettings(), nil
|
||||
}
|
||||
}
|
||||
|
||||
type hijackableBody struct {
|
||||
body
|
||||
conn quic.Connection // only needed to implement Hijacker
|
||||
@@ -84,24 +118,19 @@ type hijackableBody struct {
|
||||
}
|
||||
|
||||
var (
|
||||
_ Hijacker = &hijackableBody{}
|
||||
_ HTTPStreamer = &hijackableBody{}
|
||||
_ io.ReadCloser = &hijackableBody{}
|
||||
_ Hijacker = &hijackableBody{}
|
||||
_ HTTPStreamer = &hijackableBody{}
|
||||
)
|
||||
|
||||
func newResponseBody(str Stream, conn quic.Connection, done chan<- struct{}) *hijackableBody {
|
||||
return &hijackableBody{
|
||||
body: body{
|
||||
str: str,
|
||||
},
|
||||
body: body{str: str},
|
||||
reqDone: done,
|
||||
conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *hijackableBody) StreamCreator() StreamCreator {
|
||||
return r.conn
|
||||
}
|
||||
|
||||
func (r *hijackableBody) Read(b []byte) (int, error) {
|
||||
n, err := r.str.Read(b)
|
||||
if err != nil {
|
||||
@@ -120,10 +149,6 @@ func (r *hijackableBody) requestDone() {
|
||||
r.reqDoneClosed = true
|
||||
}
|
||||
|
||||
func (r *body) StreamID() quic.StreamID {
|
||||
return r.str.StreamID()
|
||||
}
|
||||
|
||||
func (r *hijackableBody) Close() error {
|
||||
r.requestDone()
|
||||
// If the EOF was read, CancelRead() is a no-op.
|
||||
@@ -131,6 +156,5 @@ func (r *hijackableBody) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *hijackableBody) HTTPStream() Stream {
|
||||
return r.str
|
||||
}
|
||||
func (r *hijackableBody) HTTPStream() Stream { return r.str }
|
||||
func (r *hijackableBody) StreamCreator() StreamCreator { return r.conn }
|
||||
|
||||
Reference in New Issue
Block a user