Source File
request.go
Belonging Package
net/http
package http
import (
urlpkg
)
const (
defaultMaxMemory = 32 << 20 // 32 MB
)
var ErrMissingFile = errors.New("http: no such file")
type ProtocolError struct {
ErrorString string
}
func ( *ProtocolError) () string { return .ErrorString }
ErrNotSupported = &ProtocolError{"feature not supported"}
ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"}
ErrMissingBoundary = &ProtocolError{"no multipart boundary param in Content-Type"}
ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"}
ErrHeaderTooLong = &ProtocolError{"header too long"}
ErrShortBody = &ProtocolError{"entity body too short"}
ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
)
func (, string) error { return fmt.Errorf("%s %q", , ) }
Proto string // "HTTP/1.0"
ProtoMajor int // 1
ProtoMinor int // 0
GetBody func() (io.ReadCloser, error)
Cancel <-chan struct{}
func ( *Request) ( context.Context) *Request {
if == nil {
panic("nil context")
}
:= new(Request)
* = *
.ctx =
.URL = cloneURL(.URL)
if .Header != nil {
.Header = .Header.Clone()
}
if .Trailer != nil {
.Trailer = .Trailer.Clone()
}
if := .TransferEncoding; != nil {
:= make([]string, len())
copy(, )
.TransferEncoding =
}
.Form = cloneURLValues(.Form)
.PostForm = cloneURLValues(.PostForm)
.MultipartForm = cloneMultipartForm(.MultipartForm)
return
}
func ( *Request) (, int) bool {
return .ProtoMajor > ||
.ProtoMajor == && .ProtoMinor >=
}
func ( *Request) () []*Cookie {
return readCookies(.Header, "")
}
var ErrNoCookie = errors.New("http: named cookie not present")
func ( *Request) ( string) (*Cookie, error) {
for , := range readCookies(.Header, ) {
return , nil
}
return nil, ErrNoCookie
}
func ( *Request) () (*multipart.Reader, error) {
if .MultipartForm == multipartByReader {
return nil, errors.New("http: MultipartReader called twice")
}
if .MultipartForm != nil {
return nil, errors.New("http: multipart handled by ParseMultipartForm")
}
.MultipartForm = multipartByReader
return .multipartReader(true)
}
func ( *Request) ( bool) (*multipart.Reader, error) {
:= .Header.Get("Content-Type")
if == "" {
return nil, ErrNotMultipart
}
, , := mime.ParseMediaType()
if != nil || !( == "multipart/form-data" || && == "multipart/mixed") {
return nil, ErrNotMultipart
}
, := ["boundary"]
if ! {
return nil, ErrMissingBoundary
}
return multipart.NewReader(.Body, ), nil
}
const defaultUserAgent = "Go-http-client/1.1"
var errMissingHost = errors.New("http: Request.Write on Request with no Host or URL set")
func ( *Request) ( io.Writer, bool, Header, func() bool) ( error) {
:= httptrace.ContextClientTrace(.Context())
if != nil && .WroteRequest != nil {
defer func() {
.WroteRequest(httptrace.WroteRequestInfo{
Err: ,
})
}()
}
:= false
defer func() {
if {
return
}
if := .closeBody(); != nil && == nil {
=
}
}()
= removeZone()
:= .URL.RequestURI()
if && .URL.Scheme != "" && .URL.Opaque == "" {
= .URL.Scheme + "://" + +
_, = fmt.Fprintf(, "Host: %s\r\n", )
if != nil {
return
}
if != nil && .WroteHeaderField != nil {
.WroteHeaderField("Host", []string{})
}
:= defaultUserAgent
if .Header.has("User-Agent") {
= .Header.Get("User-Agent")
}
if != "" {
_, = fmt.Fprintf(, "User-Agent: %s\r\n", )
if != nil {
return
}
if != nil && .WroteHeaderField != nil {
.WroteHeaderField("User-Agent", []string{})
}
}
, := newTransferWriter()
if != nil {
return
}
= .writeHeader(, )
if != nil {
return
}
= .Header.writeSubset(, reqWriteExcludeHeader, )
if != nil {
return
}
if != nil {
= .write(, )
if != nil {
return
}
}
_, = io.WriteString(, "\r\n")
if != nil {
return
}
if != nil && .WroteHeaders != nil {
.WroteHeaders()
}
= true
= .writeBody()
if != nil {
if .bodyReadError == {
= requestBodyReadError{}
}
return
}
if != nil {
return .Flush()
}
return nil
}
type requestBodyReadError struct{ error }
func ( string) string {
if := strings.IndexAny(, " /"); != -1 {
= [:]
}
, , := net.SplitHostPort()
if != nil { // input was just a host
, := idnaASCII()
if != nil {
return // garbage in, garbage out
}
return
}
, := idnaASCII()
if != nil {
return // garbage in, garbage out
}
return net.JoinHostPort(, )
}
func ( string) (, int, bool) {
const = 1000000 // arbitrary upper bound
switch {
case "HTTP/1.1":
return 1, 1, true
case "HTTP/1.0":
return 1, 0, true
}
if !strings.HasPrefix(, "HTTP/") {
return 0, 0, false
}
:= strings.Index(, ".")
if < 0 {
return 0, 0, false
}
, := strconv.Atoi([5:])
if != nil || < 0 || > {
return 0, 0, false
}
, = strconv.Atoi([+1:])
if != nil || < 0 || > {
return 0, 0, false
}
return , , true
}
return len() > 0 && strings.IndexFunc(, isNotToken) == -1
}
func (, string, io.Reader) (*Request, error) {
return NewRequestWithContext(context.Background(), , , )
}
.Host = removeEmptyPort(.Host)
:= &Request{
ctx: ,
Method: ,
URL: ,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: make(Header),
Body: ,
Host: .Host,
}
if != nil {
switch v := .(type) {
case *bytes.Buffer:
.ContentLength = int64(.Len())
:= .Bytes()
.GetBody = func() (io.ReadCloser, error) {
:= bytes.NewReader()
return io.NopCloser(), nil
}
case *bytes.Reader:
.ContentLength = int64(.Len())
:= *
.GetBody = func() (io.ReadCloser, error) {
:=
return io.NopCloser(&), nil
}
case *strings.Reader:
.ContentLength = int64(.Len())
:= *
.GetBody = func() (io.ReadCloser, error) {
:=
return io.NopCloser(&), nil
}
func ( string) (, , string, bool) {
:= strings.Index(, " ")
:= strings.Index([+1:], " ")
if < 0 || < 0 {
return
}
+= + 1
return [:], [+1 : ], [+1:], true
}
var textprotoReaderPool sync.Pool
func ( *bufio.Reader) *textproto.Reader {
if := textprotoReaderPool.Get(); != nil {
:= .(*textproto.Reader)
.R =
return
}
return textproto.NewReader()
}
func ( *textproto.Reader) {
.R = nil
textprotoReaderPool.Put()
}
func ( *bufio.Reader) (*Request, error) {
return readRequest(, deleteHostHeader)
}
const (
deleteHostHeader = true
keepHostHeader = false
)
func ( *bufio.Reader, bool) ( *Request, error) {
:= newTextprotoReader()
= new(Request)
var string
if , = .ReadLine(); != nil {
return nil,
}
defer func() {
putTextprotoReader()
if == io.EOF {
= io.ErrUnexpectedEOF
}
}()
var bool
.Method, .RequestURI, .Proto, = parseRequestLine()
if ! {
return nil, badStringError("malformed HTTP request", )
}
if !validMethod(.Method) {
return nil, badStringError("invalid method", .Method)
}
:= .RequestURI
if .ProtoMajor, .ProtoMinor, = ParseHTTPVersion(.Proto); ! {
return nil, badStringError("malformed HTTP version", .Proto)
}
, := .ReadMIMEHeader()
if != nil {
return nil,
}
.Header = Header()
.Host = .URL.Host
if .Host == "" {
.Host = .Header.get("Host")
}
if {
delete(.Header, "Host")
}
fixPragmaCacheControl(.Header)
.Close = shouldClose(.ProtoMajor, .ProtoMinor, .Header, false)
= readTransfer(, )
if != nil {
return nil,
}
.ContentLength = -1
func ( ResponseWriter, io.ReadCloser, int64) io.ReadCloser {
return &maxBytesReader{w: , r: , n: }
}
type maxBytesReader struct {
w ResponseWriter
r io.ReadCloser // underlying reader
n int64 // max bytes remaining
err error // sticky error
}
func ( *maxBytesReader) ( []byte) ( int, error) {
if .err != nil {
return 0, .err
}
if len() == 0 {
return 0, nil
type interface {
()
}
if , := .w.(); {
.()
}
.err = errors.New("http: request body too large")
return , .err
}
func ( *maxBytesReader) () error {
return .r.Close()
}
func (, url.Values) {
for , := range {
[] = append([], ...)
}
}
func ( *Request) ( url.Values, error) {
if .Body == nil {
= errors.New("missing form body")
return
}
if == "" {
= "application/octet-stream"
}
, _, = mime.ParseMediaType()
switch {
case == "application/x-www-form-urlencoded":
var io.Reader = .Body
:= int64(1<<63 - 1)
if , := .Body.(*maxBytesReader); ! {
= int64(10 << 20) // 10 MB is a lot of text.
= io.LimitReader(.Body, +1)
}
, := io.ReadAll()
if != nil {
if == nil {
=
}
break
}
if int64(len()) > {
= errors.New("http: POST too large")
return
}
, = url.ParseQuery(string())
if == nil {
=
}
}
return
}
func ( *Request) () error {
var error
if .PostForm == nil {
if .Method == "POST" || .Method == "PUT" || .Method == "PATCH" {
.PostForm, = parsePostForm()
}
if .PostForm == nil {
.PostForm = make(url.Values)
}
}
if .Form == nil {
if len(.PostForm) > 0 {
.Form = make(url.Values)
copyValues(.Form, .PostForm)
}
var url.Values
if .URL != nil {
var error
, = url.ParseQuery(.URL.RawQuery)
if == nil {
=
}
}
if == nil {
= make(url.Values)
}
if .Form == nil {
.Form =
} else {
copyValues(.Form, )
}
}
return
}
func ( *Request) ( int64) error {
if .MultipartForm == multipartByReader {
return errors.New("http: multipart handled by MultipartReader")
}
if .Form == nil {
:= .ParseForm()
if != nil {
return
}
}
if .MultipartForm != nil {
return nil
}
, := .multipartReader(false)
if != nil {
return
}
, := .ReadForm()
if != nil {
return
}
if .PostForm == nil {
.PostForm = make(url.Values)
}
for , := range .Value {
.PostForm[] = append(.PostForm[], ...)
}
.MultipartForm =
return nil
}
func ( *Request) ( string) string {
if .Form == nil {
.ParseMultipartForm(defaultMaxMemory)
}
if := .Form[]; len() > 0 {
return [0]
}
return ""
}
func ( *Request) ( string) string {
if .PostForm == nil {
.ParseMultipartForm(defaultMaxMemory)
}
if := .PostForm[]; len() > 0 {
return [0]
}
return ""
}
func ( *Request) ( string) (multipart.File, *multipart.FileHeader, error) {
if .MultipartForm == multipartByReader {
return nil, nil, errors.New("http: multipart handled by MultipartReader")
}
if .MultipartForm == nil {
:= .ParseMultipartForm(defaultMaxMemory)
if != nil {
return nil, nil,
}
}
if .MultipartForm != nil && .MultipartForm.File != nil {
if := .MultipartForm.File[]; len() > 0 {
, := [0].Open()
return , [0],
}
}
return nil, nil, ErrMissingFile
}
func ( *Request) () bool {
return hasToken(.Header.get("Expect"), "100-continue")
}
func ( *Request) () bool {
if .ProtoMajor != 1 || .ProtoMinor != 0 {
return false
}
return hasToken(.Header.get("Connection"), "keep-alive")
}
func ( *Request) () bool {
if .Close {
return true
}
return hasToken(.Header.get("Connection"), "close")
}
func ( *Request) () error {
if .Body == nil {
return nil
}
return .Body.Close()
}
func ( *Request) () bool {
if .Body == nil || .Body == NoBody || .GetBody != nil {
switch valueOrDefault(.Method, "GET") {
case "GET", "HEAD", "OPTIONS", "TRACE":
return true
func ( *Request) () int64 {
if .Body == nil || .Body == NoBody {
return 0
}
if .ContentLength != 0 {
return .ContentLength
}
return -1
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |