diff options
Diffstat (limited to 'libgo/go/net/http/request.go')
-rw-r--r-- | libgo/go/net/http/request.go | 80 |
1 files changed, 62 insertions, 18 deletions
diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go index dcad2b6..fa63175 100644 --- a/libgo/go/net/http/request.go +++ b/libgo/go/net/http/request.go @@ -26,7 +26,7 @@ import ( "strings" "sync" - "internal/x/net/idna" + "golang.org/x/net/idna" ) const ( @@ -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{} @@ -327,7 +327,7 @@ type Request struct { // The returned context is always non-nil; it defaults to the // background context. // -// For outgoing client requests, the context controls cancelation. +// For outgoing client requests, the context controls cancellation. // // For incoming server requests, the context is canceled when the // client's connection closes, the request is canceled (with HTTP/2), @@ -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", @@ -912,6 +952,10 @@ func parseBasicAuth(auth string) (username, password string, ok bool) { // // With HTTP Basic Authentication the provided username and password // are not encrypted. +// +// Some protocols may impose additional requirements on pre-escaping the +// username and password. For instance, when used with OAuth2, both arguments +// must be URL encoded first with url.QueryEscape. func (r *Request) SetBasicAuth(username, password string) { r.Header.Set("Authorization", "Basic "+basicAuth(username, password)) } |