318
332
// TODO(bradfitz): escape at least newlines in ruri?
320
bw := bufio.NewWriter(w)
321
fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri)
334
// Wrap the writer in a bufio Writer if it's not already buffered.
335
// Don't always call NewWriter, as that forces a bytes.Buffer
336
// and other small bufio Writers to have a minimum 4k buffer
339
if _, ok := w.(io.ByteWriter); !ok {
340
bw = bufio.NewWriter(w)
344
fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri)
324
fmt.Fprintf(bw, "Host: %s\r\n", host)
347
fmt.Fprintf(w, "Host: %s\r\n", host)
326
349
// Use the defaultUserAgent unless the Header contains one, which
327
350
// may be blank to not send the header.
343
err = tw.WriteHeader(bw)
366
err = tw.WriteHeader(w)
348
371
// TODO: split long values? (If so, should share code with Conn.Write)
349
err = req.Header.WriteSubset(bw, reqWriteExcludeHeader)
372
err = req.Header.WriteSubset(w, reqWriteExcludeHeader)
354
377
if extraHeaders != nil {
355
err = extraHeaders.Write(bw)
378
err = extraHeaders.Write(w)
361
io.WriteString(bw, "\r\n")
384
io.WriteString(w, "\r\n")
363
386
// Write body and trailer
364
err = tw.WriteBody(bw)
387
err = tw.WriteBody(w)
372
// Convert decimal at s[i:len(s)] to integer,
373
// returning value, string position where the digits stopped,
374
// and whether there was a valid number (digits, not too big).
375
func atoi(s string, i int) (n, i1 int, ok bool) {
377
if i >= len(s) || s[i] < '0' || s[i] > '9' {
381
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
382
n = n*10 + int(s[i]-'0')
390
398
// ParseHTTPVersion parses a HTTP version string.
391
399
// "HTTP/1.0" returns (1, 0, true).
392
400
func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
393
if len(vers) < 5 || vers[0:5] != "HTTP/" {
396
major, i, ok := atoi(vers, 5)
397
if !ok || i >= len(vers) || vers[i] != '.' {
400
minor, i, ok = atoi(vers, i+1)
401
if !ok || i != len(vers) {
401
const Big = 1000000 // arbitrary upper bound
408
if !strings.HasPrefix(vers, "HTTP/") {
411
dot := strings.Index(vers, ".")
415
major, err := strconv.Atoi(vers[5:dot])
416
if err != nil || major < 0 || major > Big {
419
minor, err = strconv.Atoi(vers[dot+1:])
420
if err != nil || minor < 0 || minor > Big {
402
421
return 0, 0, false
404
423
return major, minor, true
446
467
r.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(s)))
470
// parseRequestLine parses "GET /foo HTTP/1.1" into its three parts.
471
func parseRequestLine(line string) (method, requestURI, proto string, ok bool) {
472
s1 := strings.Index(line, " ")
473
s2 := strings.Index(line[s1+1:], " ")
474
if s1 < 0 || s2 < 0 {
478
return line[:s1], line[s1+1 : s2], line[s2+1:], true
481
// TODO(bradfitz): use a sync.Cache when available
482
var textprotoReaderCache = make(chan *textproto.Reader, 4)
484
func newTextprotoReader(br *bufio.Reader) *textproto.Reader {
486
case r := <-textprotoReaderCache:
490
return textproto.NewReader(br)
494
func putTextprotoReader(r *textproto.Reader) {
497
case textprotoReaderCache <- r:
449
502
// ReadRequest reads and parses a request from b.
450
503
func ReadRequest(b *bufio.Reader) (req *Request, err error) {
452
tp := textproto.NewReader(b)
505
tp := newTextprotoReader(b)
453
506
req = new(Request)
455
508
// First line: GET /index.html HTTP/1.0
514
putTextprotoReader(tp)
461
515
if err == io.EOF {
462
516
err = io.ErrUnexpectedEOF
467
if f = strings.SplitN(s, " ", 3); len(f) < 3 {
521
req.Method, req.RequestURI, req.Proto, ok = parseRequestLine(s)
468
523
return nil, &badStringError{"malformed HTTP request", s}
470
req.Method, req.RequestURI, req.Proto = f[0], f[1], f[2]
471
525
rawurl := req.RequestURI
473
526
if req.ProtoMajor, req.ProtoMinor, ok = ParseHTTPVersion(req.Proto); !ok {
474
527
return nil, &badStringError{"malformed HTTP version", req.Proto}
594
647
return l.r.Close()
597
// ParseForm parses the raw query from the URL.
599
// For POST or PUT requests, it also parses the request body as a form.
650
func copyValues(dst, src url.Values) {
651
for k, vs := range src {
652
for _, value := range vs {
658
func parsePostForm(r *Request) (vs url.Values, err error) {
660
err = errors.New("missing form body")
663
ct := r.Header.Get("Content-Type")
664
ct, _, err = mime.ParseMediaType(ct)
666
case ct == "application/x-www-form-urlencoded":
667
var reader io.Reader = r.Body
668
maxFormSize := int64(1<<63 - 1)
669
if _, ok := r.Body.(*maxBytesReader); !ok {
670
maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
671
reader = io.LimitReader(r.Body, maxFormSize+1)
673
b, e := ioutil.ReadAll(reader)
680
if int64(len(b)) > maxFormSize {
681
err = errors.New("http: POST too large")
684
vs, e = url.ParseQuery(string(b))
688
case ct == "multipart/form-data":
689
// handled by ParseMultipartForm (which is calling us, or should be)
690
// TODO(bradfitz): there are too many possible
691
// orders to call too many functions here.
692
// Clean this up and write more tests.
693
// request_test.go contains the start of this,
694
// in TestRequestMultipartCallOrder.
699
// ParseForm parses the raw query from the URL and updates r.Form.
701
// For POST or PUT requests, it also parses the request body as a form and
702
// put the results into both r.PostForm and r.Form.
703
// POST and PUT body parameters take precedence over URL query string values
600
706
// If the request Body's size has not already been limited by MaxBytesReader,
601
707
// the size is capped at 10MB.
603
709
// ParseMultipartForm calls ParseForm automatically.
604
710
// It is idempotent.
605
func (r *Request) ParseForm() (err error) {
610
r.Form, err = url.ParseQuery(r.URL.RawQuery)
612
if r.Method == "POST" || r.Method == "PUT" {
614
return errors.New("missing form body")
616
ct := r.Header.Get("Content-Type")
617
ct, _, err = mime.ParseMediaType(ct)
619
case ct == "application/x-www-form-urlencoded":
620
var reader io.Reader = r.Body
621
maxFormSize := int64(1<<63 - 1)
622
if _, ok := r.Body.(*maxBytesReader); !ok {
623
maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
624
reader = io.LimitReader(r.Body, maxFormSize+1)
626
b, e := ioutil.ReadAll(reader)
633
if int64(len(b)) > maxFormSize {
634
return errors.New("http: POST too large")
636
var newValues url.Values
637
newValues, e = url.ParseQuery(string(b))
711
func (r *Request) ParseForm() error {
713
if r.PostForm == nil {
714
if r.Method == "POST" || r.Method == "PUT" {
715
r.PostForm, err = parsePostForm(r)
717
if r.PostForm == nil {
718
r.PostForm = make(url.Values)
722
if len(r.PostForm) > 0 {
723
r.Form = make(url.Values)
724
copyValues(r.Form, r.PostForm)
726
var newValues url.Values
729
newValues, e = url.ParseQuery(r.URL.RawQuery)
642
r.Form = make(url.Values)
644
// Copy values into r.Form. TODO: make this smoother.
645
for k, vs := range newValues {
646
for _, value := range vs {
650
case ct == "multipart/form-data":
651
// handled by ParseMultipartForm (which is calling us, or should be)
652
// TODO(bradfitz): there are too many possible
653
// orders to call too many functions here.
654
// Clean this up and write more tests.
655
// request_test.go contains the start of this,
656
// in TestRequestMultipartCallOrder.
734
if newValues == nil {
735
newValues = make(url.Values)
740
copyValues(r.Form, newValues)