| // Copyright 2016 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package httptest provides utilities for HTTP testing. |
| package httptest |
| |
| import ( |
| "bufio" |
| "bytes" |
| "context" |
| "crypto/tls" |
| "io" |
| "net/http" |
| "strings" |
| ) |
| |
| // NewRequest wraps NewRequestWithContext using context.Background. |
| func NewRequest(method, target string, body io.Reader) *http.Request { |
| return NewRequestWithContext(context.Background(), method, target, body) |
| } |
| |
| // NewRequestWithContext returns a new incoming server Request, suitable |
| // for passing to an [http.Handler] for testing. |
| // |
| // The target is the RFC 7230 "request-target": it may be either a |
| // path or an absolute URL. If target is an absolute URL, the host name |
| // from the URL is used. Otherwise, "example.com" is used. |
| // |
| // The TLS field is set to a non-nil dummy value if target has scheme |
| // "https". |
| // |
| // The Request.Proto is always HTTP/1.1. |
| // |
| // An empty method means "GET". |
| // |
| // The provided body may be nil. If the body is of type *bytes.Reader, |
| // *strings.Reader, or *bytes.Buffer, the Request.ContentLength is |
| // set. |
| // |
| // NewRequest panics on error for ease of use in testing, where a |
| // panic is acceptable. |
| // |
| // To generate a client HTTP request instead of a server request, see |
| // the NewRequest function in the net/http package. |
| func NewRequestWithContext(ctx context.Context, method, target string, body io.Reader) *http.Request { |
| if method == "" { |
| method = "GET" |
| } |
| req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(method + " " + target + " HTTP/1.0\r\n\r\n"))) |
| if err != nil { |
| panic("invalid NewRequest arguments; " + err.Error()) |
| } |
| req = req.WithContext(ctx) |
| |
| // HTTP/1.0 was used above to avoid needing a Host field. Change it to 1.1 here. |
| req.Proto = "HTTP/1.1" |
| req.ProtoMinor = 1 |
| req.Close = false |
| |
| if body != nil { |
| switch v := body.(type) { |
| case *bytes.Buffer: |
| req.ContentLength = int64(v.Len()) |
| case *bytes.Reader: |
| req.ContentLength = int64(v.Len()) |
| case *strings.Reader: |
| req.ContentLength = int64(v.Len()) |
| default: |
| req.ContentLength = -1 |
| } |
| if rc, ok := body.(io.ReadCloser); ok { |
| req.Body = rc |
| } else { |
| req.Body = io.NopCloser(body) |
| } |
| } |
| |
| // 192.0.2.0/24 is "TEST-NET" in RFC 5737 for use solely in |
| // documentation and example source code and should not be |
| // used publicly. |
| req.RemoteAddr = "192.0.2.1:1234" |
| |
| if req.Host == "" { |
| req.Host = "example.com" |
| } |
| |
| if strings.HasPrefix(target, "https://") { |
| req.TLS = &tls.ConnectionState{ |
| Version: tls.VersionTLS12, |
| HandshakeComplete: true, |
| ServerName: req.Host, |
| } |
| } |
| |
| return req |
| } |