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