Source file src/net/http/httptest/httptest.go

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package httptest provides utilities for HTTP testing.
     6  package httptest
     7  
     8  import (
     9  	"bufio"
    10  	"bytes"
    11  	"context"
    12  	"crypto/tls"
    13  	"io"
    14  	"net/http"
    15  	"strings"
    16  )
    17  
    18  // NewRequest wraps NewRequestWithContext using context.Background.
    19  func NewRequest(method, target string, body io.Reader) *http.Request {
    20  	return NewRequestWithContext(context.Background(), method, target, body)
    21  }
    22  
    23  // NewRequestWithContext returns a new incoming server Request, suitable
    24  // for passing to an [http.Handler] for testing.
    25  //
    26  // The target is the RFC 7230 "request-target": it may be either a
    27  // path or an absolute URL. If target is an absolute URL, the host name
    28  // from the URL is used. Otherwise, "example.com" is used.
    29  //
    30  // The TLS field is set to a non-nil dummy value if target has scheme
    31  // "https".
    32  //
    33  // The Request.Proto is always HTTP/1.1.
    34  //
    35  // An empty method means "GET".
    36  //
    37  // The provided body may be nil. If the body is of type *bytes.Reader,
    38  // *strings.Reader, or *bytes.Buffer, the Request.ContentLength is
    39  // set.
    40  //
    41  // NewRequest panics on error for ease of use in testing, where a
    42  // panic is acceptable.
    43  //
    44  // To generate a client HTTP request instead of a server request, see
    45  // the NewRequest function in the net/http package.
    46  func NewRequestWithContext(ctx context.Context, method, target string, body io.Reader) *http.Request {
    47  	if method == "" {
    48  		method = "GET"
    49  	}
    50  	req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(method + " " + target + " HTTP/1.0\r\n\r\n")))
    51  	if err != nil {
    52  		panic("invalid NewRequest arguments; " + err.Error())
    53  	}
    54  	req = req.WithContext(ctx)
    55  
    56  	// HTTP/1.0 was used above to avoid needing a Host field. Change it to 1.1 here.
    57  	req.Proto = "HTTP/1.1"
    58  	req.ProtoMinor = 1
    59  	req.Close = false
    60  
    61  	if body != nil {
    62  		switch v := body.(type) {
    63  		case *bytes.Buffer:
    64  			req.ContentLength = int64(v.Len())
    65  		case *bytes.Reader:
    66  			req.ContentLength = int64(v.Len())
    67  		case *strings.Reader:
    68  			req.ContentLength = int64(v.Len())
    69  		default:
    70  			req.ContentLength = -1
    71  		}
    72  		if rc, ok := body.(io.ReadCloser); ok {
    73  			req.Body = rc
    74  		} else {
    75  			req.Body = io.NopCloser(body)
    76  		}
    77  	}
    78  
    79  	// 192.0.2.0/24 is "TEST-NET" in RFC 5737 for use solely in
    80  	// documentation and example source code and should not be
    81  	// used publicly.
    82  	req.RemoteAddr = "192.0.2.1:1234"
    83  
    84  	if req.Host == "" {
    85  		req.Host = "example.com"
    86  	}
    87  
    88  	if strings.HasPrefix(target, "https://") {
    89  		req.TLS = &tls.ConnectionState{
    90  			Version:           tls.VersionTLS12,
    91  			HandshakeComplete: true,
    92  			ServerName:        req.Host,
    93  		}
    94  	}
    95  
    96  	return req
    97  }
    98  

View as plain text