OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [http/] [request.go] - Blame information for rev 858

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2009 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
// HTTP Request reading and parsing.
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
        "strings"
23
)
24
 
25
const (
26
        maxValueLength   = 4096
27
        maxHeaderLines   = 1024
28
        chunkSize        = 4 << 10  // 4 KB chunks
29
        defaultMaxMemory = 32 << 20 // 32 MB
30
)
31
 
32
// ErrMissingFile is returned by FormFile when the provided file field name
33
// is either not present in the request or not a file field.
34
var ErrMissingFile = errors.New("http: no such file")
35
 
36
// HTTP request parsing errors.
37
type ProtocolError struct {
38
        ErrorString string
39
}
40
 
41
func (err *ProtocolError) Error() string { return err.ErrorString }
42
 
43
var (
44
        ErrHeaderTooLong        = &ProtocolError{"header too long"}
45
        ErrShortBody            = &ProtocolError{"entity body too short"}
46
        ErrNotSupported         = &ProtocolError{"feature not supported"}
47
        ErrUnexpectedTrailer    = &ProtocolError{"trailer header without chunked transfer encoding"}
48
        ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
49
        ErrNotMultipart         = &ProtocolError{"request Content-Type isn't multipart/form-data"}
50
        ErrMissingBoundary      = &ProtocolError{"no multipart boundary param Content-Type"}
51
)
52
 
53
type badStringError struct {
54
        what string
55
        str  string
56
}
57
 
58
func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }
59
 
60
// Headers that Request.Write handles itself and should be skipped.
61
var reqWriteExcludeHeader = map[string]bool{
62
        "Host":              true, // not in Header map anyway
63
        "User-Agent":        true,
64
        "Content-Length":    true,
65
        "Transfer-Encoding": true,
66
        "Trailer":           true,
67
}
68
 
69
// A Request represents an HTTP request received by a server
70
// or to be sent by a client.
71
type Request struct {
72
        Method string // GET, POST, PUT, etc.
73
        URL    *url.URL
74
 
75
        // The protocol version for incoming requests.
76
        // Outgoing requests always use HTTP/1.1.
77
        Proto      string // "HTTP/1.0"
78
        ProtoMajor int    // 1
79
        ProtoMinor int    // 0
80
 
81
        // A header maps request lines to their values.
82
        // If the header says
83
        //
84
        //      accept-encoding: gzip, deflate
85
        //      Accept-Language: en-us
86
        //      Connection: keep-alive
87
        //
88
        // then
89
        //
90
        //      Header = map[string][]string{
91
        //              "Accept-Encoding": {"gzip, deflate"},
92
        //              "Accept-Language": {"en-us"},
93
        //              "Connection": {"keep-alive"},
94
        //      }
95
        //
96
        // HTTP defines that header names are case-insensitive.
97
        // The request parser implements this by canonicalizing the
98
        // name, making the first character and any characters
99
        // following a hyphen uppercase and the rest lowercase.
100
        Header Header
101
 
102
        // The message body.
103
        Body io.ReadCloser
104
 
105
        // ContentLength records the length of the associated content.
106
        // The value -1 indicates that the length is unknown.
107
        // Values >= 0 indicate that the given number of bytes may
108
        // be read from Body.
109
        // For outgoing requests, a value of 0 means unknown if Body is not nil.
110
        ContentLength int64
111
 
112
        // TransferEncoding lists the transfer encodings from outermost to
113
        // innermost. An empty list denotes the "identity" encoding.
114
        // TransferEncoding can usually be ignored; chunked encoding is
115
        // automatically added and removed as necessary when sending and
116
        // receiving requests.
117
        TransferEncoding []string
118
 
119
        // Close indicates whether to close the connection after
120
        // replying to this request.
121
        Close bool
122
 
123
        // The host on which the URL is sought.
124
        // Per RFC 2616, this is either the value of the Host: header
125
        // or the host name given in the URL itself.
126
        Host string
127
 
128
        // Form contains the parsed form data, including both the URL
129
        // field's query parameters and the POST or PUT form data.
130
        // This field is only available after ParseForm is called.
131
        // The HTTP client ignores Form and uses Body instead.
132
        Form url.Values
133
 
134
        // MultipartForm is the parsed multipart form, including file uploads.
135
        // This field is only available after ParseMultipartForm is called.
136
        // The HTTP client ignores MultipartForm and uses Body instead.
137
        MultipartForm *multipart.Form
138
 
139
        // Trailer maps trailer keys to values.  Like for Header, if the
140
        // response has multiple trailer lines with the same key, they will be
141
        // concatenated, delimited by commas.
142
        // For server requests, Trailer is only populated after Body has been
143
        // closed or fully consumed.
144
        // Trailer support is only partially complete.
145
        Trailer Header
146
 
147
        // RemoteAddr allows HTTP servers and other software to record
148
        // the network address that sent the request, usually for
149
        // logging. This field is not filled in by ReadRequest and
150
        // has no defined format. The HTTP server in this package
151
        // sets RemoteAddr to an "IP:port" address before invoking a
152
        // handler.
153
        // This field is ignored by the HTTP client.
154
        RemoteAddr string
155
 
156
        // RequestURI is the unmodified Request-URI of the
157
        // Request-Line (RFC 2616, Section 5.1) as sent by the client
158
        // to a server. Usually the URL field should be used instead.
159
        // It is an error to set this field in an HTTP client request.
160
        RequestURI string
161
 
162
        // TLS allows HTTP servers and other software to record
163
        // information about the TLS connection on which the request
164
        // was received. This field is not filled in by ReadRequest.
165
        // The HTTP server in this package sets the field for
166
        // TLS-enabled connections before invoking a handler;
167
        // otherwise it leaves the field nil.
168
        // This field is ignored by the HTTP client.
169
        TLS *tls.ConnectionState
170
}
171
 
172
// ProtoAtLeast returns whether the HTTP protocol used
173
// in the request is at least major.minor.
174
func (r *Request) ProtoAtLeast(major, minor int) bool {
175
        return r.ProtoMajor > major ||
176
                r.ProtoMajor == major && r.ProtoMinor >= minor
177
}
178
 
179
// UserAgent returns the client's User-Agent, if sent in the request.
180
func (r *Request) UserAgent() string {
181
        return r.Header.Get("User-Agent")
182
}
183
 
184
// Cookies parses and returns the HTTP cookies sent with the request.
185
func (r *Request) Cookies() []*Cookie {
186
        return readCookies(r.Header, "")
187
}
188
 
189
var ErrNoCookie = errors.New("http: named cookied not present")
190
 
191
// Cookie returns the named cookie provided in the request or
192
// ErrNoCookie if not found.
193
func (r *Request) Cookie(name string) (*Cookie, error) {
194
        for _, c := range readCookies(r.Header, name) {
195
                return c, nil
196
        }
197
        return nil, ErrNoCookie
198
}
199
 
200
// AddCookie adds a cookie to the request.  Per RFC 6265 section 5.4,
201
// AddCookie does not attach more than one Cookie header field.  That
202
// means all cookies, if any, are written into the same line,
203
// separated by semicolon.
204
func (r *Request) AddCookie(c *Cookie) {
205
        s := fmt.Sprintf("%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
206
        if c := r.Header.Get("Cookie"); c != "" {
207
                r.Header.Set("Cookie", c+"; "+s)
208
        } else {
209
                r.Header.Set("Cookie", s)
210
        }
211
}
212
 
213
// Referer returns the referring URL, if sent in the request.
214
//
215
// Referer is misspelled as in the request itself, a mistake from the
216
// earliest days of HTTP.  This value can also be fetched from the
217
// Header map as Header["Referer"]; the benefit of making it available
218
// as a method is that the compiler can diagnose programs that use the
219
// alternate (correct English) spelling req.Referrer() but cannot
220
// diagnose programs that use Header["Referrer"].
221
func (r *Request) Referer() string {
222
        return r.Header.Get("Referer")
223
}
224
 
225
// multipartByReader is a sentinel value.
226
// Its presence in Request.MultipartForm indicates that parsing of the request
227
// body has been handed off to a MultipartReader instead of ParseMultipartFrom.
228
var multipartByReader = &multipart.Form{
229
        Value: make(map[string][]string),
230
        File:  make(map[string][]*multipart.FileHeader),
231
}
232
 
233
// MultipartReader returns a MIME multipart reader if this is a
234
// multipart/form-data POST request, else returns nil and an error.
235
// Use this function instead of ParseMultipartForm to
236
// process the request body as a stream.
237
func (r *Request) MultipartReader() (*multipart.Reader, error) {
238
        if r.MultipartForm == multipartByReader {
239
                return nil, errors.New("http: MultipartReader called twice")
240
        }
241
        if r.MultipartForm != nil {
242
                return nil, errors.New("http: multipart handled by ParseMultipartForm")
243
        }
244
        r.MultipartForm = multipartByReader
245
        return r.multipartReader()
246
}
247
 
248
func (r *Request) multipartReader() (*multipart.Reader, error) {
249
        v := r.Header.Get("Content-Type")
250
        if v == "" {
251
                return nil, ErrNotMultipart
252
        }
253
        d, params, err := mime.ParseMediaType(v)
254
        if err != nil || d != "multipart/form-data" {
255
                return nil, ErrNotMultipart
256
        }
257
        boundary, ok := params["boundary"]
258
        if !ok {
259
                return nil, ErrMissingBoundary
260
        }
261
        return multipart.NewReader(r.Body, boundary), nil
262
}
263
 
264
// Return value if nonempty, def otherwise.
265
func valueOrDefault(value, def string) string {
266
        if value != "" {
267
                return value
268
        }
269
        return def
270
}
271
 
272
const defaultUserAgent = "Go http package"
273
 
274
// Write writes an HTTP/1.1 request -- header and body -- in wire format.
275
// This method consults the following fields of the request:
276
//      Host
277
//      URL
278
//      Method (defaults to "GET")
279
//      Header
280
//      ContentLength
281
//      TransferEncoding
282
//      Body
283
//
284
// If Body is present, Content-Length is <= 0 and TransferEncoding
285
// hasn't been set to "identity", Write adds "Transfer-Encoding:
286
// chunked" to the header. Body is closed after it is sent.
287
func (r *Request) Write(w io.Writer) error {
288
        return r.write(w, false, nil)
289
}
290
 
291
// WriteProxy is like Write but writes the request in the form
292
// expected by an HTTP proxy.  In particular, WriteProxy writes the
293
// initial Request-URI line of the request with an absolute URI, per
294
// section 5.1.2 of RFC 2616, including the scheme and host.
295
// In either case, WriteProxy also writes a Host header, using
296
// either r.Host or r.URL.Host.
297
func (r *Request) WriteProxy(w io.Writer) error {
298
        return r.write(w, true, nil)
299
}
300
 
301
// extraHeaders may be nil
302
func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) error {
303
        host := req.Host
304
        if host == "" {
305
                if req.URL == nil {
306
                        return errors.New("http: Request.Write on Request with no Host or URL set")
307
                }
308
                host = req.URL.Host
309
        }
310
 
311
        ruri := req.URL.RequestURI()
312
        if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" {
313
                ruri = req.URL.Scheme + "://" + host + ruri
314
        } else if req.Method == "CONNECT" && req.URL.Path == "" {
315
                // CONNECT requests normally give just the host and port, not a full URL.
316
                ruri = host
317
        }
318
        // TODO(bradfitz): escape at least newlines in ruri?
319
 
320
        bw := bufio.NewWriter(w)
321
        fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri)
322
 
323
        // Header lines
324
        fmt.Fprintf(bw, "Host: %s\r\n", host)
325
 
326
        // Use the defaultUserAgent unless the Header contains one, which
327
        // may be blank to not send the header.
328
        userAgent := defaultUserAgent
329
        if req.Header != nil {
330
                if ua := req.Header["User-Agent"]; len(ua) > 0 {
331
                        userAgent = ua[0]
332
                }
333
        }
334
        if userAgent != "" {
335
                fmt.Fprintf(bw, "User-Agent: %s\r\n", userAgent)
336
        }
337
 
338
        // Process Body,ContentLength,Close,Trailer
339
        tw, err := newTransferWriter(req)
340
        if err != nil {
341
                return err
342
        }
343
        err = tw.WriteHeader(bw)
344
        if err != nil {
345
                return err
346
        }
347
 
348
        // TODO: split long values?  (If so, should share code with Conn.Write)
349
        err = req.Header.WriteSubset(bw, reqWriteExcludeHeader)
350
        if err != nil {
351
                return err
352
        }
353
 
354
        if extraHeaders != nil {
355
                err = extraHeaders.Write(bw)
356
                if err != nil {
357
                        return err
358
                }
359
        }
360
 
361
        io.WriteString(bw, "\r\n")
362
 
363
        // Write body and trailer
364
        err = tw.WriteBody(bw)
365
        if err != nil {
366
                return err
367
        }
368
 
369
        return bw.Flush()
370
}
371
 
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) {
376
        const Big = 1000000
377
        if i >= len(s) || s[i] < '0' || s[i] > '9' {
378
                return 0, 0, false
379
        }
380
        n = 0
381
        for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
382
                n = n*10 + int(s[i]-'0')
383
                if n > Big {
384
                        return 0, 0, false
385
                }
386
        }
387
        return n, i, true
388
}
389
 
390
// ParseHTTPVersion parses a HTTP version string.
391
// "HTTP/1.0" returns (1, 0, true).
392
func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
393
        if len(vers) < 5 || vers[0:5] != "HTTP/" {
394
                return 0, 0, false
395
        }
396
        major, i, ok := atoi(vers, 5)
397
        if !ok || i >= len(vers) || vers[i] != '.' {
398
                return 0, 0, false
399
        }
400
        minor, i, ok = atoi(vers, i+1)
401
        if !ok || i != len(vers) {
402
                return 0, 0, false
403
        }
404
        return major, minor, true
405
}
406
 
407
// NewRequest returns a new Request given a method, URL, and optional body.
408
func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
409
        u, err := url.Parse(urlStr)
410
        if err != nil {
411
                return nil, err
412
        }
413
        rc, ok := body.(io.ReadCloser)
414
        if !ok && body != nil {
415
                rc = ioutil.NopCloser(body)
416
        }
417
        req := &Request{
418
                Method:     method,
419
                URL:        u,
420
                Proto:      "HTTP/1.1",
421
                ProtoMajor: 1,
422
                ProtoMinor: 1,
423
                Header:     make(Header),
424
                Body:       rc,
425
                Host:       u.Host,
426
        }
427
        if body != nil {
428
                switch v := body.(type) {
429
                case *strings.Reader:
430
                        req.ContentLength = int64(v.Len())
431
                case *bytes.Buffer:
432
                        req.ContentLength = int64(v.Len())
433
                }
434
        }
435
 
436
        return req, nil
437
}
438
 
439
// SetBasicAuth sets the request's Authorization header to use HTTP
440
// Basic Authentication with the provided username and password.
441
//
442
// With HTTP Basic Authentication the provided username and password
443
// are not encrypted.
444
func (r *Request) SetBasicAuth(username, password string) {
445
        s := username + ":" + password
446
        r.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(s)))
447
}
448
 
449
// ReadRequest reads and parses a request from b.
450
func ReadRequest(b *bufio.Reader) (req *Request, err error) {
451
 
452
        tp := textproto.NewReader(b)
453
        req = new(Request)
454
 
455
        // First line: GET /index.html HTTP/1.0
456
        var s string
457
        if s, err = tp.ReadLine(); err != nil {
458
                if err == io.EOF {
459
                        err = io.ErrUnexpectedEOF
460
                }
461
                return nil, err
462
        }
463
 
464
        var f []string
465
        if f = strings.SplitN(s, " ", 3); len(f) < 3 {
466
                return nil, &badStringError{"malformed HTTP request", s}
467
        }
468
        req.Method, req.RequestURI, req.Proto = f[0], f[1], f[2]
469
        rawurl := req.RequestURI
470
        var ok bool
471
        if req.ProtoMajor, req.ProtoMinor, ok = ParseHTTPVersion(req.Proto); !ok {
472
                return nil, &badStringError{"malformed HTTP version", req.Proto}
473
        }
474
 
475
        // CONNECT requests are used two different ways, and neither uses a full URL:
476
        // The standard use is to tunnel HTTPS through an HTTP proxy.
477
        // It looks like "CONNECT www.google.com:443 HTTP/1.1", and the parameter is
478
        // just the authority section of a URL. This information should go in req.URL.Host.
479
        //
480
        // The net/rpc package also uses CONNECT, but there the parameter is a path
481
        // that starts with a slash. It can be parsed with the regular URL parser,
482
        // and the path will end up in req.URL.Path, where it needs to be in order for
483
        // RPC to work.
484
        justAuthority := req.Method == "CONNECT" && !strings.HasPrefix(rawurl, "/")
485
        if justAuthority {
486
                rawurl = "http://" + rawurl
487
        }
488
 
489
        if req.URL, err = url.ParseRequest(rawurl); err != nil {
490
                return nil, err
491
        }
492
 
493
        if justAuthority {
494
                // Strip the bogus "http://" back off.
495
                req.URL.Scheme = ""
496
        }
497
 
498
        // Subsequent lines: Key: value.
499
        mimeHeader, err := tp.ReadMIMEHeader()
500
        if err != nil {
501
                return nil, err
502
        }
503
        req.Header = Header(mimeHeader)
504
 
505
        // RFC2616: Must treat
506
        //      GET /index.html HTTP/1.1
507
        //      Host: www.google.com
508
        // and
509
        //      GET http://www.google.com/index.html HTTP/1.1
510
        //      Host: doesntmatter
511
        // the same.  In the second case, any Host line is ignored.
512
        req.Host = req.URL.Host
513
        if req.Host == "" {
514
                req.Host = req.Header.Get("Host")
515
        }
516
        req.Header.Del("Host")
517
 
518
        fixPragmaCacheControl(req.Header)
519
 
520
        // TODO: Parse specific header values:
521
        //      Accept
522
        //      Accept-Encoding
523
        //      Accept-Language
524
        //      Authorization
525
        //      Cache-Control
526
        //      Connection
527
        //      Date
528
        //      Expect
529
        //      From
530
        //      If-Match
531
        //      If-Modified-Since
532
        //      If-None-Match
533
        //      If-Range
534
        //      If-Unmodified-Since
535
        //      Max-Forwards
536
        //      Proxy-Authorization
537
        //      Referer [sic]
538
        //      TE (transfer-codings)
539
        //      Trailer
540
        //      Transfer-Encoding
541
        //      Upgrade
542
        //      User-Agent
543
        //      Via
544
        //      Warning
545
 
546
        err = readTransfer(req, b)
547
        if err != nil {
548
                return nil, err
549
        }
550
 
551
        return req, nil
552
}
553
 
554
// MaxBytesReader is similar to io.LimitReader but is intended for
555
// limiting the size of incoming request bodies. In contrast to
556
// io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a
557
// non-EOF error for a Read beyond the limit, and Closes the
558
// underlying reader when its Close method is called.
559
//
560
// MaxBytesReader prevents clients from accidentally or maliciously
561
// sending a large request and wasting server resources.
562
func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser {
563
        return &maxBytesReader{w: w, r: r, n: n}
564
}
565
 
566
type maxBytesReader struct {
567
        w       ResponseWriter
568
        r       io.ReadCloser // underlying reader
569
        n       int64         // max bytes remaining
570
        stopped bool
571
}
572
 
573
func (l *maxBytesReader) Read(p []byte) (n int, err error) {
574
        if l.n <= 0 {
575
                if !l.stopped {
576
                        l.stopped = true
577
                        if res, ok := l.w.(*response); ok {
578
                                res.requestTooLarge()
579
                        }
580
                }
581
                return 0, errors.New("http: request body too large")
582
        }
583
        if int64(len(p)) > l.n {
584
                p = p[:l.n]
585
        }
586
        n, err = l.r.Read(p)
587
        l.n -= int64(n)
588
        return
589
}
590
 
591
func (l *maxBytesReader) Close() error {
592
        return l.r.Close()
593
}
594
 
595
// ParseForm parses the raw query from the URL.
596
//
597
// For POST or PUT requests, it also parses the request body as a form.
598
// If the request Body's size has not already been limited by MaxBytesReader,
599
// the size is capped at 10MB.
600
//
601
// ParseMultipartForm calls ParseForm automatically.
602
// It is idempotent.
603
func (r *Request) ParseForm() (err error) {
604
        if r.Form != nil {
605
                return
606
        }
607
        if r.URL != nil {
608
                r.Form, err = url.ParseQuery(r.URL.RawQuery)
609
        }
610
        if r.Method == "POST" || r.Method == "PUT" {
611
                if r.Body == nil {
612
                        return errors.New("missing form body")
613
                }
614
                ct := r.Header.Get("Content-Type")
615
                ct, _, err = mime.ParseMediaType(ct)
616
                switch {
617
                case ct == "application/x-www-form-urlencoded":
618
                        var reader io.Reader = r.Body
619
                        maxFormSize := int64(1<<63 - 1)
620
                        if _, ok := r.Body.(*maxBytesReader); !ok {
621
                                maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
622
                                reader = io.LimitReader(r.Body, maxFormSize+1)
623
                        }
624
                        b, e := ioutil.ReadAll(reader)
625
                        if e != nil {
626
                                if err == nil {
627
                                        err = e
628
                                }
629
                                break
630
                        }
631
                        if int64(len(b)) > maxFormSize {
632
                                return errors.New("http: POST too large")
633
                        }
634
                        var newValues url.Values
635
                        newValues, e = url.ParseQuery(string(b))
636
                        if err == nil {
637
                                err = e
638
                        }
639
                        if r.Form == nil {
640
                                r.Form = make(url.Values)
641
                        }
642
                        // Copy values into r.Form. TODO: make this smoother.
643
                        for k, vs := range newValues {
644
                                for _, value := range vs {
645
                                        r.Form.Add(k, value)
646
                                }
647
                        }
648
                case ct == "multipart/form-data":
649
                        // handled by ParseMultipartForm (which is calling us, or should be)
650
                        // TODO(bradfitz): there are too many possible
651
                        // orders to call too many functions here.
652
                        // Clean this up and write more tests.
653
                        // request_test.go contains the start of this,
654
                        // in TestRequestMultipartCallOrder.
655
                }
656
        }
657
        return err
658
}
659
 
660
// ParseMultipartForm parses a request body as multipart/form-data.
661
// The whole request body is parsed and up to a total of maxMemory bytes of
662
// its file parts are stored in memory, with the remainder stored on
663
// disk in temporary files.
664
// ParseMultipartForm calls ParseForm if necessary.
665
// After one call to ParseMultipartForm, subsequent calls have no effect.
666
func (r *Request) ParseMultipartForm(maxMemory int64) error {
667
        if r.MultipartForm == multipartByReader {
668
                return errors.New("http: multipart handled by MultipartReader")
669
        }
670
        if r.Form == nil {
671
                err := r.ParseForm()
672
                if err != nil {
673
                        return err
674
                }
675
        }
676
        if r.MultipartForm != nil {
677
                return nil
678
        }
679
 
680
        mr, err := r.multipartReader()
681
        if err == ErrNotMultipart {
682
                return nil
683
        } else if err != nil {
684
                return err
685
        }
686
 
687
        f, err := mr.ReadForm(maxMemory)
688
        if err != nil {
689
                return err
690
        }
691
        for k, v := range f.Value {
692
                r.Form[k] = append(r.Form[k], v...)
693
        }
694
        r.MultipartForm = f
695
 
696
        return nil
697
}
698
 
699
// FormValue returns the first value for the named component of the query.
700
// FormValue calls ParseMultipartForm and ParseForm if necessary.
701
func (r *Request) FormValue(key string) string {
702
        if r.Form == nil {
703
                r.ParseMultipartForm(defaultMaxMemory)
704
        }
705
        if vs := r.Form[key]; len(vs) > 0 {
706
                return vs[0]
707
        }
708
        return ""
709
}
710
 
711
// FormFile returns the first file for the provided form key.
712
// FormFile calls ParseMultipartForm and ParseForm if necessary.
713
func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
714
        if r.MultipartForm == multipartByReader {
715
                return nil, nil, errors.New("http: multipart handled by MultipartReader")
716
        }
717
        if r.MultipartForm == nil {
718
                err := r.ParseMultipartForm(defaultMaxMemory)
719
                if err != nil {
720
                        return nil, nil, err
721
                }
722
        }
723
        if r.MultipartForm != nil && r.MultipartForm.File != nil {
724
                if fhs := r.MultipartForm.File[key]; len(fhs) > 0 {
725
                        f, err := fhs[0].Open()
726
                        return f, fhs[0], err
727
                }
728
        }
729
        return nil, nil, ErrMissingFile
730
}
731
 
732
func (r *Request) expectsContinue() bool {
733
        return strings.ToLower(r.Header.Get("Expect")) == "100-continue"
734
}
735
 
736
func (r *Request) wantsHttp10KeepAlive() bool {
737
        if r.ProtoMajor != 1 || r.ProtoMinor != 0 {
738
                return false
739
        }
740
        return strings.Contains(strings.ToLower(r.Header.Get("Connection")), "keep-alive")
741
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.