Source file src/pkg/net/http/request.go
1
2
3
4
5
6
7 package http
8
9 import (
10 "bufio"
11 "bytes"
12 "crypto/tls"
13 "encoding/base64"
14 "errors"
15 "fmt"
16 "io"
17 "io/ioutil"
18 "mime"
19 "mime/multipart"
20 "net/textproto"
21 "net/url"
22 "strconv"
23 "strings"
24 )
25
26 const (
27 maxValueLength = 4096
28 maxHeaderLines = 1024
29 chunkSize = 4 << 10
30 defaultMaxMemory = 32 << 20
31 )
32
33
34
35 var ErrMissingFile = errors.New("http: no such file")
36
37
38 type ProtocolError struct {
39 ErrorString string
40 }
41
42 func (err *ProtocolError) Error() string { return err.ErrorString }
43
44 var (
45 ErrHeaderTooLong = &ProtocolError{"header too long"}
46 ErrShortBody = &ProtocolError{"entity body too short"}
47 ErrNotSupported = &ProtocolError{"feature not supported"}
48 ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"}
49 ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
50 ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"}
51 ErrMissingBoundary = &ProtocolError{"no multipart boundary param in Content-Type"}
52 )
53
54 type badStringError struct {
55 what string
56 str string
57 }
58
59 func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }
60
61
62 var reqWriteExcludeHeader = map[string]bool{
63 "Host": true,
64 "User-Agent": true,
65 "Content-Length": true,
66 "Transfer-Encoding": true,
67 "Trailer": true,
68 }
69
70
71
72 type Request struct {
73 Method string
74
75
76
77
78
79
80 URL *url.URL
81
82
83
84 Proto string
85 ProtoMajor int
86 ProtoMinor int
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107 Header Header
108
109
110 Body io.ReadCloser
111
112
113
114
115
116
117 ContentLength int64
118
119
120
121
122
123
124 TransferEncoding []string
125
126
127
128 Close bool
129
130
131
132
133
134 Host string
135
136
137
138
139
140 Form url.Values
141
142
143
144
145
146 PostForm url.Values
147
148
149
150
151 MultipartForm *multipart.Form
152
153
154
155
156
157
158
159 Trailer Header
160
161
162
163
164
165
166
167
168 RemoteAddr string
169
170
171
172
173
174 RequestURI string
175
176
177
178
179
180
181
182
183 TLS *tls.ConnectionState
184 }
185
186
187
188 func (r *Request) ProtoAtLeast(major, minor int) bool {
189 return r.ProtoMajor > major ||
190 r.ProtoMajor == major && r.ProtoMinor >= minor
191 }
192
193
194 func (r *Request) UserAgent() string {
195 return r.Header.Get("User-Agent")
196 }
197
198
199 func (r *Request) Cookies() []*Cookie {
200 return readCookies(r.Header, "")
201 }
202
203 var ErrNoCookie = errors.New("http: named cookie not present")
204
205
206
207 func (r *Request) Cookie(name string) (*Cookie, error) {
208 for _, c := range readCookies(r.Header, name) {
209 return c, nil
210 }
211 return nil, ErrNoCookie
212 }
213
214
215
216
217
218 func (r *Request) AddCookie(c *Cookie) {
219 s := fmt.Sprintf("%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
220 if c := r.Header.Get("Cookie"); c != "" {
221 r.Header.Set("Cookie", c+"; "+s)
222 } else {
223 r.Header.Set("Cookie", s)
224 }
225 }
226
227
228
229
230
231
232
233
234
235 func (r *Request) Referer() string {
236 return r.Header.Get("Referer")
237 }
238
239
240
241
242 var multipartByReader = &multipart.Form{
243 Value: make(map[string][]string),
244 File: make(map[string][]*multipart.FileHeader),
245 }
246
247
248
249
250
251 func (r *Request) MultipartReader() (*multipart.Reader, error) {
252 if r.MultipartForm == multipartByReader {
253 return nil, errors.New("http: MultipartReader called twice")
254 }
255 if r.MultipartForm != nil {
256 return nil, errors.New("http: multipart handled by ParseMultipartForm")
257 }
258 r.MultipartForm = multipartByReader
259 return r.multipartReader()
260 }
261
262 func (r *Request) multipartReader() (*multipart.Reader, error) {
263 v := r.Header.Get("Content-Type")
264 if v == "" {
265 return nil, ErrNotMultipart
266 }
267 d, params, err := mime.ParseMediaType(v)
268 if err != nil || d != "multipart/form-data" {
269 return nil, ErrNotMultipart
270 }
271 boundary, ok := params["boundary"]
272 if !ok {
273 return nil, ErrMissingBoundary
274 }
275 return multipart.NewReader(r.Body, boundary), nil
276 }
277
278
279 func valueOrDefault(value, def string) string {
280 if value != "" {
281 return value
282 }
283 return def
284 }
285
286 const defaultUserAgent = "Go 1.1 package http"
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301 func (r *Request) Write(w io.Writer) error {
302 return r.write(w, false, nil)
303 }
304
305
306
307
308
309
310
311 func (r *Request) WriteProxy(w io.Writer) error {
312 return r.write(w, true, nil)
313 }
314
315
316 func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) error {
317 host := req.Host
318 if host == "" {
319 if req.URL == nil {
320 return errors.New("http: Request.Write on Request with no Host or URL set")
321 }
322 host = req.URL.Host
323 }
324
325 ruri := req.URL.RequestURI()
326 if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" {
327 ruri = req.URL.Scheme + "://" + host + ruri
328 } else if req.Method == "CONNECT" && req.URL.Path == "" {
329
330 ruri = host
331 }
332
333
334
335
336
337
338 var bw *bufio.Writer
339 if _, ok := w.(io.ByteWriter); !ok {
340 bw = bufio.NewWriter(w)
341 w = bw
342 }
343
344 fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri)
345
346
347 fmt.Fprintf(w, "Host: %s\r\n", host)
348
349
350
351 userAgent := defaultUserAgent
352 if req.Header != nil {
353 if ua := req.Header["User-Agent"]; len(ua) > 0 {
354 userAgent = ua[0]
355 }
356 }
357 if userAgent != "" {
358 fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent)
359 }
360
361
362 tw, err := newTransferWriter(req)
363 if err != nil {
364 return err
365 }
366 err = tw.WriteHeader(w)
367 if err != nil {
368 return err
369 }
370
371
372 err = req.Header.WriteSubset(w, reqWriteExcludeHeader)
373 if err != nil {
374 return err
375 }
376
377 if extraHeaders != nil {
378 err = extraHeaders.Write(w)
379 if err != nil {
380 return err
381 }
382 }
383
384 io.WriteString(w, "\r\n")
385
386
387 err = tw.WriteBody(w)
388 if err != nil {
389 return err
390 }
391
392 if bw != nil {
393 return bw.Flush()
394 }
395 return nil
396 }
397
398
399
400 func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
401 const Big = 1000000
402 switch vers {
403 case "HTTP/1.1":
404 return 1, 1, true
405 case "HTTP/1.0":
406 return 1, 0, true
407 }
408 if !strings.HasPrefix(vers, "HTTP/") {
409 return 0, 0, false
410 }
411 dot := strings.Index(vers, ".")
412 if dot < 0 {
413 return 0, 0, false
414 }
415 major, err := strconv.Atoi(vers[5:dot])
416 if err != nil || major < 0 || major > Big {
417 return 0, 0, false
418 }
419 minor, err = strconv.Atoi(vers[dot+1:])
420 if err != nil || minor < 0 || minor > Big {
421 return 0, 0, false
422 }
423 return major, minor, true
424 }
425
426
427 func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
428 u, err := url.Parse(urlStr)
429 if err != nil {
430 return nil, err
431 }
432 rc, ok := body.(io.ReadCloser)
433 if !ok && body != nil {
434 rc = ioutil.NopCloser(body)
435 }
436 req := &Request{
437 Method: method,
438 URL: u,
439 Proto: "HTTP/1.1",
440 ProtoMajor: 1,
441 ProtoMinor: 1,
442 Header: make(Header),
443 Body: rc,
444 Host: u.Host,
445 }
446 if body != nil {
447 switch v := body.(type) {
448 case *bytes.Buffer:
449 req.ContentLength = int64(v.Len())
450 case *bytes.Reader:
451 req.ContentLength = int64(v.Len())
452 case *strings.Reader:
453 req.ContentLength = int64(v.Len())
454 }
455 }
456
457 return req, nil
458 }
459
460
461
462
463
464
465 func (r *Request) SetBasicAuth(username, password string) {
466 s := username + ":" + password
467 r.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(s)))
468 }
469
470
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 {
475 return
476 }
477 s2 += s1 + 1
478 return line[:s1], line[s1+1 : s2], line[s2+1:], true
479 }
480
481
482 var textprotoReaderCache = make(chan *textproto.Reader, 4)
483
484 func newTextprotoReader(br *bufio.Reader) *textproto.Reader {
485 select {
486 case r := <-textprotoReaderCache:
487 r.R = br
488 return r
489 default:
490 return textproto.NewReader(br)
491 }
492 }
493
494 func putTextprotoReader(r *textproto.Reader) {
495 r.R = nil
496 select {
497 case textprotoReaderCache <- r:
498 default:
499 }
500 }
501
502
503 func ReadRequest(b *bufio.Reader) (req *Request, err error) {
504
505 tp := newTextprotoReader(b)
506 req = new(Request)
507
508
509 var s string
510 if s, err = tp.ReadLine(); err != nil {
511 return nil, err
512 }
513 defer func() {
514 putTextprotoReader(tp)
515 if err == io.EOF {
516 err = io.ErrUnexpectedEOF
517 }
518 }()
519
520 var ok bool
521 req.Method, req.RequestURI, req.Proto, ok = parseRequestLine(s)
522 if !ok {
523 return nil, &badStringError{"malformed HTTP request", s}
524 }
525 rawurl := req.RequestURI
526 if req.ProtoMajor, req.ProtoMinor, ok = ParseHTTPVersion(req.Proto); !ok {
527 return nil, &badStringError{"malformed HTTP version", req.Proto}
528 }
529
530
531
532
533
534
535
536
537
538
539 justAuthority := req.Method == "CONNECT" && !strings.HasPrefix(rawurl, "/")
540 if justAuthority {
541 rawurl = "http://" + rawurl
542 }
543
544 if req.URL, err = url.ParseRequestURI(rawurl); err != nil {
545 return nil, err
546 }
547
548 if justAuthority {
549
550 req.URL.Scheme = ""
551 }
552
553
554 mimeHeader, err := tp.ReadMIMEHeader()
555 if err != nil {
556 return nil, err
557 }
558 req.Header = Header(mimeHeader)
559
560
561
562
563
564
565
566
567 req.Host = req.URL.Host
568 if req.Host == "" {
569 req.Host = req.Header.get("Host")
570 }
571 delete(req.Header, "Host")
572
573 fixPragmaCacheControl(req.Header)
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601 err = readTransfer(req, b)
602 if err != nil {
603 return nil, err
604 }
605
606 return req, nil
607 }
608
609
610
611
612
613
614
615
616
617 func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser {
618 return &maxBytesReader{w: w, r: r, n: n}
619 }
620
621 type maxBytesReader struct {
622 w ResponseWriter
623 r io.ReadCloser
624 n int64
625 stopped bool
626 }
627
628 func (l *maxBytesReader) Read(p []byte) (n int, err error) {
629 if l.n <= 0 {
630 if !l.stopped {
631 l.stopped = true
632 if res, ok := l.w.(*response); ok {
633 res.requestTooLarge()
634 }
635 }
636 return 0, errors.New("http: request body too large")
637 }
638 if int64(len(p)) > l.n {
639 p = p[:l.n]
640 }
641 n, err = l.r.Read(p)
642 l.n -= int64(n)
643 return
644 }
645
646 func (l *maxBytesReader) Close() error {
647 return l.r.Close()
648 }
649
650 func copyValues(dst, src url.Values) {
651 for k, vs := range src {
652 for _, value := range vs {
653 dst.Add(k, value)
654 }
655 }
656 }
657
658 func parsePostForm(r *Request) (vs url.Values, err error) {
659 if r.Body == nil {
660 err = errors.New("missing form body")
661 return
662 }
663 ct := r.Header.Get("Content-Type")
664 ct, _, err = mime.ParseMediaType(ct)
665 switch {
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)
671 reader = io.LimitReader(r.Body, maxFormSize+1)
672 }
673 b, e := ioutil.ReadAll(reader)
674 if e != nil {
675 if err == nil {
676 err = e
677 }
678 break
679 }
680 if int64(len(b)) > maxFormSize {
681 err = errors.New("http: POST too large")
682 return
683 }
684 vs, e = url.ParseQuery(string(b))
685 if err == nil {
686 err = e
687 }
688 case ct == "multipart/form-data":
689
690
691
692
693
694
695 }
696 return
697 }
698
699
700
701
702
703
704
705
706
707
708
709
710
711 func (r *Request) ParseForm() error {
712 var err error
713 if r.PostForm == nil {
714 if r.Method == "POST" || r.Method == "PUT" {
715 r.PostForm, err = parsePostForm(r)
716 }
717 if r.PostForm == nil {
718 r.PostForm = make(url.Values)
719 }
720 }
721 if r.Form == nil {
722 if len(r.PostForm) > 0 {
723 r.Form = make(url.Values)
724 copyValues(r.Form, r.PostForm)
725 }
726 var newValues url.Values
727 if r.URL != nil {
728 var e error
729 newValues, e = url.ParseQuery(r.URL.RawQuery)
730 if err == nil {
731 err = e
732 }
733 }
734 if newValues == nil {
735 newValues = make(url.Values)
736 }
737 if r.Form == nil {
738 r.Form = newValues
739 } else {
740 copyValues(r.Form, newValues)
741 }
742 }
743 return err
744 }
745
746
747
748
749
750
751
752 func (r *Request) ParseMultipartForm(maxMemory int64) error {
753 if r.MultipartForm == multipartByReader {
754 return errors.New("http: multipart handled by MultipartReader")
755 }
756 if r.Form == nil {
757 err := r.ParseForm()
758 if err != nil {
759 return err
760 }
761 }
762 if r.MultipartForm != nil {
763 return nil
764 }
765
766 mr, err := r.multipartReader()
767 if err == ErrNotMultipart {
768 return nil
769 } else if err != nil {
770 return err
771 }
772
773 f, err := mr.ReadForm(maxMemory)
774 if err != nil {
775 return err
776 }
777 for k, v := range f.Value {
778 r.Form[k] = append(r.Form[k], v...)
779 }
780 r.MultipartForm = f
781
782 return nil
783 }
784
785
786
787
788
789 func (r *Request) FormValue(key string) string {
790 if r.Form == nil {
791 r.ParseMultipartForm(defaultMaxMemory)
792 }
793 if vs := r.Form[key]; len(vs) > 0 {
794 return vs[0]
795 }
796 return ""
797 }
798
799
800
801
802 func (r *Request) PostFormValue(key string) string {
803 if r.PostForm == nil {
804 r.ParseMultipartForm(defaultMaxMemory)
805 }
806 if vs := r.PostForm[key]; len(vs) > 0 {
807 return vs[0]
808 }
809 return ""
810 }
811
812
813
814 func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
815 if r.MultipartForm == multipartByReader {
816 return nil, nil, errors.New("http: multipart handled by MultipartReader")
817 }
818 if r.MultipartForm == nil {
819 err := r.ParseMultipartForm(defaultMaxMemory)
820 if err != nil {
821 return nil, nil, err
822 }
823 }
824 if r.MultipartForm != nil && r.MultipartForm.File != nil {
825 if fhs := r.MultipartForm.File[key]; len(fhs) > 0 {
826 f, err := fhs[0].Open()
827 return f, fhs[0], err
828 }
829 }
830 return nil, nil, ErrMissingFile
831 }
832
833 func (r *Request) expectsContinue() bool {
834 return hasToken(r.Header.get("Expect"), "100-continue")
835 }
836
837 func (r *Request) wantsHttp10KeepAlive() bool {
838 if r.ProtoMajor != 1 || r.ProtoMinor != 0 {
839 return false
840 }
841 return hasToken(r.Header.get("Connection"), "keep-alive")
842 }
843
844 func (r *Request) wantsClose() bool {
845 return hasToken(r.Header.get("Connection"), "close")
846 }
View as plain text