@@ -304,7 +304,7 @@ type Request struct {
304
304
//
305
305
// For server requests, this field is not applicable.
306
306
//
307
- // Deprecated: Use the Context and WithContext methods
307
+ // Deprecated: Set the Request's context with NewRequestWithContext
308
308
// instead. If a Request's Cancel field and context are both
309
309
// set, it is undefined whether Cancel is respected.
310
310
Cancel <- chan struct {}
@@ -345,23 +345,50 @@ func (r *Request) Context() context.Context {
345
345
// For outgoing client request, the context controls the entire
346
346
// lifetime of a request and its response: obtaining a connection,
347
347
// sending the request, and reading the response headers and body.
348
+ //
349
+ // To create a new request with a context, use NewRequestWithContext.
350
+ // To change the context of a request (such as an incoming) you then
351
+ // also want to modify to send back out, use Request.Clone. Between
352
+ // those two uses, it's rare to need WithContext.
348
353
func (r * Request ) WithContext (ctx context.Context ) * Request {
349
354
if ctx == nil {
350
355
panic ("nil context" )
351
356
}
352
357
r2 := new (Request )
353
358
* r2 = * r
354
359
r2 .ctx = ctx
360
+ r2 .URL = cloneURL (r .URL ) // legacy behavior; TODO: try to remove. Issue 23544
361
+ return r2
362
+ }
355
363
356
- // Deep copy the URL because it isn't
357
- // a map and the URL is mutable by users
358
- // of WithContext.
359
- if r .URL != nil {
360
- r2URL := new (url.URL )
361
- * r2URL = * r .URL
362
- r2 .URL = r2URL
364
+ // Clone returns a deep copy of r with its context changed to ctx.
365
+ // The provided ctx must be non-nil.
366
+ //
367
+ // For an outgoing client request, the context controls the entire
368
+ // lifetime of a request and its response: obtaining a connection,
369
+ // sending the request, and reading the response headers and body.
370
+ func (r * Request ) Clone (ctx context.Context ) * Request {
371
+ if ctx == nil {
372
+ panic ("nil context" )
363
373
}
364
-
374
+ r2 := new (Request )
375
+ * r2 = * r
376
+ r2 .ctx = ctx
377
+ r2 .URL = cloneURL (r .URL )
378
+ if r .Header != nil {
379
+ r2 .Header = r .Header .Clone ()
380
+ }
381
+ if r .Trailer != nil {
382
+ r2 .Trailer = r .Trailer .Clone ()
383
+ }
384
+ if s := r .TransferEncoding ; s != nil {
385
+ s2 := make ([]string , len (s ))
386
+ copy (s2 , s )
387
+ r2 .TransferEncoding = s
388
+ }
389
+ r2 .Form = cloneURLValues (r .Form )
390
+ r2 .PostForm = cloneURLValues (r .PostForm )
391
+ r2 .MultipartForm = cloneMultipartForm (r .MultipartForm )
365
392
return r2
366
393
}
367
394
@@ -781,25 +808,34 @@ func validMethod(method string) bool {
781
808
return len (method ) > 0 && strings .IndexFunc (method , isNotToken ) == - 1
782
809
}
783
810
784
- // NewRequest returns a new Request given a method, URL, and optional body.
811
+ // NewRequest wraps NewRequestWithContext using the background context.
812
+ func NewRequest (method , url string , body io.Reader ) (* Request , error ) {
813
+ return NewRequestWithContext (context .Background (), method , url , body )
814
+ }
815
+
816
+ // NewRequestWithContext returns a new Request given a method, URL, and
817
+ // optional body.
785
818
//
786
819
// If the provided body is also an io.Closer, the returned
787
820
// Request.Body is set to body and will be closed by the Client
788
821
// methods Do, Post, and PostForm, and Transport.RoundTrip.
789
822
//
790
- // NewRequest returns a Request suitable for use with Client.Do or
791
- // Transport.RoundTrip. To create a request for use with testing a
792
- // Server Handler, either use the NewRequest function in the
823
+ // NewRequestWithContext returns a Request suitable for use with
824
+ // Client.Do or Transport.RoundTrip. To create a request for use with
825
+ // testing a Server Handler, either use the NewRequest function in the
793
826
// net/http/httptest package, use ReadRequest, or manually update the
794
- // Request fields. See the Request type's documentation for the
795
- // difference between inbound and outbound request fields.
827
+ // Request fields. For an outgoing client request, the context
828
+ // controls the entire lifetime of a request and its response:
829
+ // obtaining a connection, sending the request, and reading the
830
+ // response headers and body. See the Request type's documentation for
831
+ // the difference between inbound and outbound request fields.
796
832
//
797
833
// If body is of type *bytes.Buffer, *bytes.Reader, or
798
834
// *strings.Reader, the returned request's ContentLength is set to its
799
835
// exact value (instead of -1), GetBody is populated (so 307 and 308
800
836
// redirects can replay the body), and Body is set to NoBody if the
801
837
// ContentLength is 0.
802
- func NewRequest ( method , url string , body io.Reader ) (* Request , error ) {
838
+ func NewRequestWithContext ( ctx context. Context , method , url string , body io.Reader ) (* Request , error ) {
803
839
if method == "" {
804
840
// We document that "" means "GET" for Request.Method, and people have
805
841
// relied on that from NewRequest, so keep that working.
@@ -809,6 +845,9 @@ func NewRequest(method, url string, body io.Reader) (*Request, error) {
809
845
if ! validMethod (method ) {
810
846
return nil , fmt .Errorf ("net/http: invalid method %q" , method )
811
847
}
848
+ if ctx == nil {
849
+ return nil , errors .New ("net/http: nil Context" )
850
+ }
812
851
u , err := parseURL (url ) // Just url.Parse (url is shadowed for godoc).
813
852
if err != nil {
814
853
return nil , err
@@ -820,6 +859,7 @@ func NewRequest(method, url string, body io.Reader) (*Request, error) {
820
859
// The host's colon:port should be normalized. See Issue 14836.
821
860
u .Host = removeEmptyPort (u .Host )
822
861
req := & Request {
862
+ ctx : ctx ,
823
863
Method : method ,
824
864
URL : u ,
825
865
Proto : "HTTP/1.1" ,
0 commit comments