diff options
| author | Brad Fitzpatrick <bradfitz@golang.org> | 2019-04-29 17:57:10 +0000 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@golang.org> | 2019-05-03 15:20:15 +0000 |
| commit | f5c43b919499899fe006896643bbfebbea9d1995 (patch) | |
| tree | cede962785bd69bbece692e6782b2a40f8ce47e4 /src/net/http/request.go | |
| parent | 5e404b362098318b5237673ef24834ef88912caa (diff) | |
| download | go-f5c43b919499899fe006896643bbfebbea9d1995.tar.xz | |
net/http: add func NewRequestWithContext, Request.Clone
Fixes #23544
Change-Id: Iaa31d76c4cda8ce22412d73c9025fc57e4fb1967
Reviewed-on: https://go-review.googlesource.com/c/go/+/174324
Reviewed-by: Andrew Bonventre <andybons@golang.org>
Diffstat (limited to 'src/net/http/request.go')
| -rw-r--r-- | src/net/http/request.go | 72 |
1 files changed, 56 insertions, 16 deletions
diff --git a/src/net/http/request.go b/src/net/http/request.go index 8afe1a7c0c..fa63175c20 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -304,7 +304,7 @@ type Request struct { // // For server requests, this field is not applicable. // - // Deprecated: Use the Context and WithContext methods + // Deprecated: Set the Request's context with NewRequestWithContext // instead. If a Request's Cancel field and context are both // set, it is undefined whether Cancel is respected. Cancel <-chan struct{} @@ -345,6 +345,11 @@ func (r *Request) Context() context.Context { // For outgoing client request, the context controls the entire // lifetime of a request and its response: obtaining a connection, // sending the request, and reading the response headers and body. +// +// To create a new request with a context, use NewRequestWithContext. +// To change the context of a request (such as an incoming) you then +// also want to modify to send back out, use Request.Clone. Between +// those two uses, it's rare to need WithContext. func (r *Request) WithContext(ctx context.Context) *Request { if ctx == nil { panic("nil context") @@ -352,16 +357,38 @@ func (r *Request) WithContext(ctx context.Context) *Request { r2 := new(Request) *r2 = *r r2.ctx = ctx + r2.URL = cloneURL(r.URL) // legacy behavior; TODO: try to remove. Issue 23544 + return r2 +} - // Deep copy the URL because it isn't - // a map and the URL is mutable by users - // of WithContext. - if r.URL != nil { - r2URL := new(url.URL) - *r2URL = *r.URL - r2.URL = r2URL +// Clone returns a deep copy of r with its context changed to ctx. +// The provided ctx must be non-nil. +// +// For an outgoing client request, the context controls the entire +// lifetime of a request and its response: obtaining a connection, +// sending the request, and reading the response headers and body. +func (r *Request) Clone(ctx context.Context) *Request { + if ctx == nil { + panic("nil context") } - + r2 := new(Request) + *r2 = *r + r2.ctx = ctx + r2.URL = cloneURL(r.URL) + if r.Header != nil { + r2.Header = r.Header.Clone() + } + if r.Trailer != nil { + r2.Trailer = r.Trailer.Clone() + } + if s := r.TransferEncoding; s != nil { + s2 := make([]string, len(s)) + copy(s2, s) + r2.TransferEncoding = s + } + r2.Form = cloneURLValues(r.Form) + r2.PostForm = cloneURLValues(r.PostForm) + r2.MultipartForm = cloneMultipartForm(r.MultipartForm) return r2 } @@ -781,25 +808,34 @@ func validMethod(method string) bool { return len(method) > 0 && strings.IndexFunc(method, isNotToken) == -1 } -// NewRequest returns a new Request given a method, URL, and optional body. +// NewRequest wraps NewRequestWithContext using the background context. +func NewRequest(method, url string, body io.Reader) (*Request, error) { + return NewRequestWithContext(context.Background(), method, url, body) +} + +// NewRequestWithContext returns a new Request given a method, URL, and +// optional body. // // If the provided body is also an io.Closer, the returned // Request.Body is set to body and will be closed by the Client // methods Do, Post, and PostForm, and Transport.RoundTrip. // -// NewRequest returns a Request suitable for use with Client.Do or -// Transport.RoundTrip. To create a request for use with testing a -// Server Handler, either use the NewRequest function in the +// NewRequestWithContext returns a Request suitable for use with +// Client.Do or Transport.RoundTrip. To create a request for use with +// testing a Server Handler, either use the NewRequest function in the // net/http/httptest package, use ReadRequest, or manually update the -// Request fields. See the Request type's documentation for the -// difference between inbound and outbound request fields. +// Request fields. For an outgoing client request, the context +// controls the entire lifetime of a request and its response: +// obtaining a connection, sending the request, and reading the +// response headers and body. See the Request type's documentation for +// the difference between inbound and outbound request fields. // // If body is of type *bytes.Buffer, *bytes.Reader, or // *strings.Reader, the returned request's ContentLength is set to its // exact value (instead of -1), GetBody is populated (so 307 and 308 // redirects can replay the body), and Body is set to NoBody if the // ContentLength is 0. -func NewRequest(method, url string, body io.Reader) (*Request, error) { +func NewRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*Request, error) { if method == "" { // We document that "" means "GET" for Request.Method, and people have // relied on that from NewRequest, so keep that working. @@ -809,6 +845,9 @@ func NewRequest(method, url string, body io.Reader) (*Request, error) { if !validMethod(method) { return nil, fmt.Errorf("net/http: invalid method %q", method) } + if ctx == nil { + return nil, errors.New("net/http: nil Context") + } u, err := parseURL(url) // Just url.Parse (url is shadowed for godoc). if err != nil { return nil, err @@ -820,6 +859,7 @@ func NewRequest(method, url string, body io.Reader) (*Request, error) { // The host's colon:port should be normalized. See Issue 14836. u.Host = removeEmptyPort(u.Host) req := &Request{ + ctx: ctx, Method: method, URL: u, Proto: "HTTP/1.1", |
