~john-koepi/ubuntu/trusty/golang/default

« back to all changes in this revision

Viewing changes to src/pkg/http/request.go

  • Committer: Bazaar Package Importer
  • Author(s): Ondřej Surý
  • Date: 2011-08-03 17:04:59 UTC
  • mfrom: (14.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20110803170459-wzd99m3567y80ila
Tags: 1:59-1
* Imported Upstream version 59
* Refresh patches to a new release
* Fix FTBFS on ARM (Closes: #634270)
* Update version.bash to work with Debian packaging and not hg
  repository

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
 
36
36
// ErrMissingFile is returned by FormFile when the provided file field name
37
37
// is either not present in the request or not a file field.
38
 
var ErrMissingFile = os.ErrorString("http: no such file")
 
38
var ErrMissingFile = os.NewError("http: no such file")
39
39
 
40
40
// HTTP request parsing errors.
41
41
type ProtocolError struct {
42
 
        os.ErrorString
 
42
        ErrorString string
43
43
}
44
44
 
 
45
func (err *ProtocolError) String() string { return err.ErrorString }
 
46
 
45
47
var (
46
48
        ErrLineTooLong          = &ProtocolError{"header line too long"}
47
49
        ErrHeaderTooLong        = &ProtocolError{"header too long"}
60
62
 
61
63
func (e *badStringError) String() string { return fmt.Sprintf("%s %q", e.what, e.str) }
62
64
 
63
 
var reqExcludeHeader = map[string]bool{
 
65
// Headers that Request.Write handles itself and should be skipped.
 
66
var reqWriteExcludeHeader = map[string]bool{
64
67
        "Host":              true,
65
68
        "User-Agent":        true,
66
 
        "Referer":           true,
67
69
        "Content-Length":    true,
68
70
        "Transfer-Encoding": true,
69
71
        "Trailer":           true,
102
104
        // following a hyphen uppercase and the rest lowercase.
103
105
        Header Header
104
106
 
105
 
        // Cookie records the HTTP cookies sent with the request.
106
 
        Cookie []*Cookie
107
 
 
108
107
        // The message body.
109
108
        Body io.ReadCloser
110
109
 
125
124
        // or the host name given in the URL itself.
126
125
        Host string
127
126
 
128
 
        // The referring URL, if sent in the request.
129
 
        //
130
 
        // Referer is misspelled as in the request itself,
131
 
        // a mistake from the earliest days of HTTP.
132
 
        // This value can also be fetched from the Header map
133
 
        // as Header["Referer"]; the benefit of making it
134
 
        // available as a structure field is that the compiler
135
 
        // can diagnose programs that use the alternate
136
 
        // (correct English) spelling req.Referrer but cannot
137
 
        // diagnose programs that use Header["Referrer"].
138
 
        Referer string
139
 
 
140
 
        // The User-Agent: header string, if sent in the request.
141
 
        UserAgent string
142
 
 
143
127
        // The parsed form. Only available after ParseForm is called.
144
128
        Form Values
145
129
 
176
160
                r.ProtoMajor == major && r.ProtoMinor >= minor
177
161
}
178
162
 
 
163
// UserAgent returns the client's User-Agent, if sent in the request.
 
164
func (r *Request) UserAgent() string {
 
165
        return r.Header.Get("User-Agent")
 
166
}
 
167
 
 
168
// Cookies parses and returns the HTTP cookies sent with the request.
 
169
func (r *Request) Cookies() []*Cookie {
 
170
        return readCookies(r.Header, "")
 
171
}
 
172
 
 
173
var ErrNoCookie = os.NewError("http: named cookied not present")
 
174
 
 
175
// Cookie returns the named cookie provided in the request or
 
176
// ErrNoCookie if not found.
 
177
func (r *Request) Cookie(name string) (*Cookie, os.Error) {
 
178
        for _, c := range readCookies(r.Header, name) {
 
179
                return c, nil
 
180
        }
 
181
        return nil, ErrNoCookie
 
182
}
 
183
 
 
184
// AddCookie adds a cookie to the request.  Per RFC 6265 section 5.4,
 
185
// AddCookie does not attach more than one Cookie header field.  That
 
186
// means all cookies, if any, are written into the same line,
 
187
// separated by semicolon.
 
188
func (r *Request) AddCookie(c *Cookie) {
 
189
        s := fmt.Sprintf("%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
 
190
        if c := r.Header.Get("Cookie"); c != "" {
 
191
                r.Header.Set("Cookie", c+"; "+s)
 
192
        } else {
 
193
                r.Header.Set("Cookie", s)
 
194
        }
 
195
}
 
196
 
 
197
// Referer returns the referring URL, if sent in the request.
 
198
//
 
199
// Referer is misspelled as in the request itself, a mistake from the
 
200
// earliest days of HTTP.  This value can also be fetched from the
 
201
// Header map as Header["Referer"]; the benefit of making it available
 
202
// as a method is that the compiler can diagnose programs that use the
 
203
// alternate (correct English) spelling req.Referrer() but cannot
 
204
// diagnose programs that use Header["Referrer"].
 
205
func (r *Request) Referer() string {
 
206
        return r.Header.Get("Referer")
 
207
}
 
208
 
179
209
// multipartByReader is a sentinel value.
180
210
// Its presence in Request.MultipartForm indicates that parsing of the request
181
211
// body has been handed off to a MultipartReader instead of ParseMultipartFrom.
188
218
// multipart/form-data POST request, else returns nil and an error.
189
219
// Use this function instead of ParseMultipartForm to
190
220
// process the request body as a stream.
191
 
func (r *Request) MultipartReader() (multipart.Reader, os.Error) {
 
221
func (r *Request) MultipartReader() (*multipart.Reader, os.Error) {
192
222
        if r.MultipartForm == multipartByReader {
193
223
                return nil, os.NewError("http: MultipartReader called twice")
194
224
        }
199
229
        return r.multipartReader()
200
230
}
201
231
 
202
 
func (r *Request) multipartReader() (multipart.Reader, os.Error) {
 
232
func (r *Request) multipartReader() (*multipart.Reader, os.Error) {
203
233
        v := r.Header.Get("Content-Type")
204
234
        if v == "" {
205
235
                return nil, ErrNotMultipart
230
260
//      Host
231
261
//      RawURL, if non-empty, or else URL
232
262
//      Method (defaults to "GET")
233
 
//      UserAgent (defaults to defaultUserAgent)
234
 
//      Referer
235
 
//      Header (only keys not already in this list)
236
 
//      Cookie
 
263
//      Header
237
264
//      ContentLength
238
265
//      TransferEncoding
239
266
//      Body
277
304
                }
278
305
        }
279
306
 
280
 
        fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), uri)
 
307
        bw := bufio.NewWriter(w)
 
308
        fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), uri)
281
309
 
282
310
        // Header lines
283
 
        fmt.Fprintf(w, "Host: %s\r\n", host)
284
 
        fmt.Fprintf(w, "User-Agent: %s\r\n", valueOrDefault(req.UserAgent, defaultUserAgent))
285
 
        if req.Referer != "" {
286
 
                fmt.Fprintf(w, "Referer: %s\r\n", req.Referer)
 
311
        fmt.Fprintf(bw, "Host: %s\r\n", host)
 
312
 
 
313
        // Use the defaultUserAgent unless the Header contains one, which
 
314
        // may be blank to not send the header.
 
315
        userAgent := defaultUserAgent
 
316
        if req.Header != nil {
 
317
                if ua := req.Header["User-Agent"]; len(ua) > 0 {
 
318
                        userAgent = ua[0]
 
319
                }
 
320
        }
 
321
        if userAgent != "" {
 
322
                fmt.Fprintf(bw, "User-Agent: %s\r\n", userAgent)
287
323
        }
288
324
 
289
325
        // Process Body,ContentLength,Close,Trailer
291
327
        if err != nil {
292
328
                return err
293
329
        }
294
 
        err = tw.WriteHeader(w)
 
330
        err = tw.WriteHeader(bw)
295
331
        if err != nil {
296
332
                return err
297
333
        }
298
334
 
299
335
        // TODO: split long values?  (If so, should share code with Conn.Write)
300
 
        // TODO: if Header includes values for Host, User-Agent, or Referer, this
301
 
        // may conflict with the User-Agent or Referer headers we add manually.
302
 
        // One solution would be to remove the Host, UserAgent, and Referer fields
303
 
        // from Request, and introduce Request methods along the lines of
304
 
        // Response.{GetHeader,AddHeader} and string constants for "Host",
305
 
        // "User-Agent" and "Referer".
306
 
        err = req.Header.WriteSubset(w, reqExcludeHeader)
 
336
        err = req.Header.WriteSubset(bw, reqWriteExcludeHeader)
307
337
        if err != nil {
308
338
                return err
309
339
        }
310
340
 
311
 
        if err = writeCookies(w, req.Cookie); err != nil {
312
 
                return err
313
 
        }
314
 
 
315
 
        io.WriteString(w, "\r\n")
 
341
        io.WriteString(bw, "\r\n")
316
342
 
317
343
        // Write body and trailer
318
 
        err = tw.WriteBody(w)
 
344
        err = tw.WriteBody(bw)
319
345
        if err != nil {
320
346
                return err
321
347
        }
322
 
 
 
348
        bw.Flush()
323
349
        return nil
324
350
}
325
351
 
402
428
        err os.Error
403
429
}
404
430
 
405
 
func newChunkedReader(r *bufio.Reader) *chunkedReader {
406
 
        return &chunkedReader{r: r}
407
 
}
408
 
 
409
431
func (cr *chunkedReader) beginChunk() {
410
432
        // chunk-size CRLF
411
433
        var line string
485
507
                        req.ContentLength = int64(v.Len())
486
508
                case *bytes.Buffer:
487
509
                        req.ContentLength = int64(v.Len())
488
 
                default:
489
 
                        req.ContentLength = -1 // chunked
490
 
                }
491
 
                if req.ContentLength == 0 {
492
 
                        // To prevent chunking and disambiguate this
493
 
                        // from the default ContentLength zero value.
494
 
                        req.TransferEncoding = []string{"identity"}
495
510
                }
496
511
        }
497
512
 
524
539
        }
525
540
 
526
541
        var f []string
527
 
        if f = strings.Split(s, " ", 3); len(f) < 3 {
 
542
        if f = strings.SplitN(s, " ", 3); len(f) < 3 {
528
543
                return nil, &badStringError{"malformed HTTP request", s}
529
544
        }
530
545
        req.Method, req.RawURL, req.Proto = f[0], f[1], f[2]
559
574
 
560
575
        fixPragmaCacheControl(req.Header)
561
576
 
562
 
        // Pull out useful fields as a convenience to clients.
563
 
        req.Referer = req.Header.Get("Referer")
564
 
        req.Header.Del("Referer")
565
 
 
566
 
        req.UserAgent = req.Header.Get("User-Agent")
567
 
        req.Header.Del("User-Agent")
568
 
 
569
577
        // TODO: Parse specific header values:
570
578
        //      Accept
571
579
        //      Accept-Encoding
597
605
                return nil, err
598
606
        }
599
607
 
600
 
        req.Cookie = readCookies(req.Header)
601
 
 
602
608
        return req, nil
603
609
}
604
610
 
652
658
}
653
659
 
654
660
func parseQuery(m Values, query string) (err os.Error) {
655
 
        for _, kv := range strings.Split(query, "&", -1) {
 
661
        for _, kv := range strings.Split(query, "&") {
656
662
                if len(kv) == 0 {
657
663
                        continue
658
664
                }
659
 
                kvPair := strings.Split(kv, "=", 2)
 
665
                kvPair := strings.SplitN(kv, "=", 2)
660
666
 
661
667
                var key, value string
662
668
                var e os.Error
690
696
        }
691
697
        if r.Method == "POST" {
692
698
                if r.Body == nil {
693
 
                        return os.ErrorString("missing form body")
 
699
                        return os.NewError("missing form body")
694
700
                }
695
701
                ct := r.Header.Get("Content-Type")
696
 
                switch strings.Split(ct, ";", 2)[0] {
 
702
                switch strings.SplitN(ct, ";", 2)[0] {
697
703
                case "text/plain", "application/x-www-form-urlencoded", "":
698
704
                        const maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
699
705
                        b, e := ioutil.ReadAll(io.LimitReader(r.Body, maxFormSize+1))