Status: | Merged |
---|---|
Approved by: | Raphaël Badin |
Approved revision: | 202 |
Merged at revision: | 197 |
Proposed branch: | lp:~rvb/gwacl/tls-fix |
Merge into: | lp:gwacl |
Diff against target: |
10735 lines (+9979/-246) 41 files modified
HACKING.txt (+0/-24) fork/LICENSE (+27/-0) fork/README (+11/-0) fork/go-tls-renegotiation.patch (+113/-0) fork/http/chunked.go (+170/-0) fork/http/client.go (+339/-0) fork/http/cookie.go (+267/-0) fork/http/doc.go (+80/-0) fork/http/filetransport.go (+123/-0) fork/http/fs.go (+367/-0) fork/http/header.go (+78/-0) fork/http/jar.go (+30/-0) fork/http/lex.go (+136/-0) fork/http/request.go (+743/-0) fork/http/response.go (+239/-0) fork/http/server.go (+1234/-0) fork/http/sniff.go (+214/-0) fork/http/status.go (+108/-0) fork/http/transfer.go (+632/-0) fork/http/transport.go (+757/-0) fork/http/triv.go (+141/-0) fork/tls/alert.go (+77/-0) fork/tls/cipher_suites.go (+188/-0) fork/tls/common.go (+322/-0) fork/tls/conn.go (+886/-0) fork/tls/generate_cert.go (+74/-0) fork/tls/handshake_client.go (+347/-0) fork/tls/handshake_messages.go (+1078/-0) fork/tls/handshake_server.go (+352/-0) fork/tls/key_agreement.go (+253/-0) fork/tls/parse-gnutls-cli-debug-log.py (+57/-0) fork/tls/prf.go (+235/-0) fork/tls/tls.go (+187/-0) httperror.go (+1/-2) management_base_test.go (+29/-5) poller_test.go (+1/-1) testhelpers_x509dispatch.go (+1/-1) x509dispatcher.go (+22/-154) x509dispatcher_test.go (+17/-42) x509session.go (+29/-3) x509session_test.go (+14/-14) |
To merge this branch: | bzr merge lp:~rvb/gwacl/tls-fix |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella | Approve | ||
Review via email: mp+176185@code.launchpad.net |
Commit message
Use a forked version of crypto/tls and net/http.
Description of the change
This branch adds a forked version of crypto/tls and net/http (crypto/tls is patched to add support for TLS renegociation and net/http is patched to use the forked version of crypto/tls).
It includes jtv's branch (lp:~jtv/gwacl/curlless) which switches from using go-curl to using the standard library's tls. (But that change is then modified to use the forked version of net/http and crypto/tls instead of the standard library.)
We forked from Go version 1.0.2 in order to support both Go 1.0.2 and Go 1.1.1 (I tried forking from crypto/tls and net/http version 1.1.1 but I was quickly overwhelmed by the number of libraries needing to be backported and the code made heavy use of Go 1.1.1-only features).
This was tested (unit tests run + script example run) with both Go 1.0.2 and Go 1.1.1.
- 197. By Raphaël Badin
-
Remove last mention of go-curl.
Gavin Panella (allenap) wrote : | # |
Before landing, do you know if licensing is okay?
- 198. By Raphaël Badin
-
Review fixes.
Raphaël Badin (rvb) wrote : | # |
> Looks good!
>
>
> [1]
>
> --- fork/README 1970-01-01 00:00:00 +0000
> +++ fork/README 2013-07-22 12:54:30 +0000
> @@ -0,0 +1,7 @@
> +This directory contains a fork of Go's standard libraries net/http and
> crypto/tls.
> ...
>
> Please wrap lines in here at no more than 80 columns. I suggest 72.
Okay, done.
> [2]
>
> === added file 'fork/go-
> --- fork/go-
> +++ fork/go-
> @@ -0,0 +1,5 @@
> +15c15
> +< "launchpad.
> +---
> +> "crypto/tls"
> +
>
> I'm not sure this is useful. Without context it's not very
> informative. It's also in the wrong direction. I suggest omitting it.
You're right, fixed.
> [3]
>
> +func performX509Requ
> (*x509Response, error) {
> ...
> + response.Header = httpResponse.Header
> + if err != nil {
> + return nil, err
> + }
>
> I don't think that condition is needed here. Could this be one of
> those Go-boilerplate-
Just a left-over from the recent refactoring, fixed.
- 199. By Raphaël Badin
-
Rename files
- 200. By Raphaël Badin
-
Add LICENSE file.
Raphaël Badin (rvb) wrote : | # |
After consulting with James Page, we got confirmation that the licencing is okay: BSD-licensed code can be included in gwacl, which is a AGPL3-licensed project. I'll add a LICENSE file in /fork and we will (in another branch) add proper COPYING/
- 201. By Raphaël Badin
-
Fix license file.
Gavin Panella (allenap) : | # |
- 202. By Raphaël Badin
-
Make format.
Julian Edwards (julian-edwards) wrote : | # |
On 23/07/13 00:03, Raphaël Badin wrote:
> After consulting with James Page, we got confirmation that the licencing is okay: BSD-licensed code can be included in gwacl, which is a AGPL3-licensed project. I'll add a LICENSE file in /fork and we will (in another branch) add proper COPYING/
>
It's actually LGPL but I think it still works though.
Preview Diff
1 | === modified file 'HACKING.txt' | |||
2 | --- HACKING.txt 2013-06-24 00:39:08 +0000 | |||
3 | +++ HACKING.txt 2013-07-22 14:27:42 +0000 | |||
4 | @@ -20,30 +20,6 @@ | |||
5 | 20 | .. _Bazaar: http://bazaar.canonical.com/ | 20 | .. _Bazaar: http://bazaar.canonical.com/ |
6 | 21 | 21 | ||
7 | 22 | 22 | ||
8 | 23 | Prerequisites | ||
9 | 24 | ------------- | ||
10 | 25 | |||
11 | 26 | The code that communicates with Azure's management API uses *libcurl*, through | ||
12 | 27 | a Go language binding called *go-curl*. You need to install the libcurl | ||
13 | 28 | headers for your OS. On Ubuntu this is:: | ||
14 | 29 | |||
15 | 30 | sudo apt-get install libcurl4-openssl-dev | ||
16 | 31 | |||
17 | 32 | If you didn't ``go get`` gwacl you may also need to install go-curl:: | ||
18 | 33 | |||
19 | 34 | go get github.com/andelf/go-curl | ||
20 | 35 | |||
21 | 36 | On Ubuntu 12.10 at least, you specifically need the given version of libcurl. | ||
22 | 37 | With other versions you will receive unexpected "403" HTTP status codes | ||
23 | 38 | ("Forbidden") from the Azure server. | ||
24 | 39 | |||
25 | 40 | Why use libcurl? At the time of writing, Go's built-in http package does not | ||
26 | 41 | support TLS renegotiation. We find that Azure forces such a renegotiation | ||
27 | 42 | when we access the management API. The use of libcurl is embedded so that | ||
28 | 43 | future implementations can swap it out for a different http library without | ||
29 | 44 | breaking compatibility. | ||
30 | 45 | |||
31 | 46 | |||
32 | 47 | API philosophy | 23 | API philosophy |
33 | 48 | -------------- | 24 | -------------- |
34 | 49 | 25 | ||
35 | 50 | 26 | ||
36 | === added directory 'fork' | |||
37 | === added file 'fork/LICENSE' | |||
38 | --- fork/LICENSE 1970-01-01 00:00:00 +0000 | |||
39 | +++ fork/LICENSE 2013-07-22 14:27:42 +0000 | |||
40 | @@ -0,0 +1,27 @@ | |||
41 | 1 | Copyright (c) 2012 The Go Authors. All rights reserved. | ||
42 | 2 | |||
43 | 3 | Redistribution and use in source and binary forms, with or without | ||
44 | 4 | modification, are permitted provided that the following conditions are | ||
45 | 5 | met: | ||
46 | 6 | |||
47 | 7 | * Redistributions of source code must retain the above copyright | ||
48 | 8 | notice, this list of conditions and the following disclaimer. | ||
49 | 9 | * Redistributions in binary form must reproduce the above | ||
50 | 10 | copyright notice, this list of conditions and the following disclaimer | ||
51 | 11 | in the documentation and/or other materials provided with the | ||
52 | 12 | distribution. | ||
53 | 13 | * Neither the name of Google Inc. nor the names of its | ||
54 | 14 | contributors may be used to endorse or promote products derived from | ||
55 | 15 | this software without specific prior written permission. | ||
56 | 16 | |||
57 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
58 | 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
59 | 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
60 | 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
61 | 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
62 | 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
63 | 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
64 | 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
65 | 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
66 | 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
67 | 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
68 | 0 | 28 | ||
69 | === added file 'fork/README' | |||
70 | --- fork/README 1970-01-01 00:00:00 +0000 | |||
71 | +++ fork/README 2013-07-22 14:27:42 +0000 | |||
72 | @@ -0,0 +1,11 @@ | |||
73 | 1 | This directory contains a fork of Go's standard libraries net/http and | ||
74 | 2 | crypto/tls. | ||
75 | 3 | |||
76 | 4 | This fork is required to support the TLS renegociation which is triggered by | ||
77 | 5 | the Windows Azure Server when establishing an https connexion. TLS | ||
78 | 6 | renegociation is currently not supported by Go's standard library. | ||
79 | 7 | |||
80 | 8 | The fork is based on go version 2:1.0.2-2. | ||
81 | 9 | The library crypto/tls is patched to support TLS renegociation (see the patch | ||
82 | 10 | file "go-tls-renegotiation.patch"). | ||
83 | 11 | The library net/http is patched to use the forked version of crypto/tls. | ||
84 | 0 | 12 | ||
85 | === added file 'fork/go-tls-renegotiation.patch' | |||
86 | --- fork/go-tls-renegotiation.patch 1970-01-01 00:00:00 +0000 | |||
87 | +++ fork/go-tls-renegotiation.patch 2013-07-22 14:27:42 +0000 | |||
88 | @@ -0,0 +1,113 @@ | |||
89 | 1 | diff -r c242bbf5fa8c src/pkg/crypto/tls/common.go | ||
90 | 2 | --- a/src/pkg/crypto/tls/common.go Wed Jul 17 14:03:27 2013 -0400 | ||
91 | 3 | +++ b/src/pkg/crypto/tls/common.go Thu Jul 18 13:45:43 2013 -0400 | ||
92 | 4 | @@ -44,6 +44,7 @@ | ||
93 | 5 | |||
94 | 6 | // TLS handshake message types. | ||
95 | 7 | const ( | ||
96 | 8 | + typeHelloRequest uint8 = 0 | ||
97 | 9 | typeClientHello uint8 = 1 | ||
98 | 10 | typeServerHello uint8 = 2 | ||
99 | 11 | typeNewSessionTicket uint8 = 4 | ||
100 | 12 | diff -r c242bbf5fa8c src/pkg/crypto/tls/conn.go | ||
101 | 13 | --- a/src/pkg/crypto/tls/conn.go Wed Jul 17 14:03:27 2013 -0400 | ||
102 | 14 | +++ b/src/pkg/crypto/tls/conn.go Thu Jul 18 13:45:43 2013 -0400 | ||
103 | 15 | @@ -146,6 +146,9 @@ | ||
104 | 16 | hc.mac = hc.nextMac | ||
105 | 17 | hc.nextCipher = nil | ||
106 | 18 | hc.nextMac = nil | ||
107 | 19 | + for i := range hc.seq { | ||
108 | 20 | + hc.seq[i] = 0 | ||
109 | 21 | + } | ||
110 | 22 | return nil | ||
111 | 23 | } | ||
112 | 24 | |||
113 | 25 | @@ -478,7 +481,7 @@ | ||
114 | 26 | func (c *Conn) readRecord(want recordType) error { | ||
115 | 27 | // Caller must be in sync with connection: | ||
116 | 28 | // handshake data if handshake not yet completed, | ||
117 | 29 | - // else application data. (We don't support renegotiation.) | ||
118 | 30 | + // else application data. | ||
119 | 31 | switch want { | ||
120 | 32 | default: | ||
121 | 33 | return c.sendAlert(alertInternalError) | ||
122 | 34 | @@ -611,7 +614,7 @@ | ||
123 | 35 | |||
124 | 36 | case recordTypeHandshake: | ||
125 | 37 | // TODO(rsc): Should at least pick off connection close. | ||
126 | 38 | - if typ != want { | ||
127 | 39 | + if typ != want && !c.isClient { | ||
128 | 40 | return c.sendAlert(alertNoRenegotiation) | ||
129 | 41 | } | ||
130 | 42 | c.hand.Write(data) | ||
131 | 43 | @@ -741,6 +744,8 @@ | ||
132 | 44 | data = c.hand.Next(4 + n) | ||
133 | 45 | var m handshakeMessage | ||
134 | 46 | switch data[0] { | ||
135 | 47 | + case typeHelloRequest: | ||
136 | 48 | + m = new(helloRequestMsg) | ||
137 | 49 | case typeClientHello: | ||
138 | 50 | m = new(clientHelloMsg) | ||
139 | 51 | case typeServerHello: | ||
140 | 52 | @@ -825,6 +830,25 @@ | ||
141 | 53 | return n + m, c.setError(err) | ||
142 | 54 | } | ||
143 | 55 | |||
144 | 56 | +func (c *Conn) handleRenegotiation() error { | ||
145 | 57 | + c.handshakeComplete = false | ||
146 | 58 | + if !c.isClient { | ||
147 | 59 | + panic("renegotiation should only happen for a client") | ||
148 | 60 | + } | ||
149 | 61 | + | ||
150 | 62 | + msg, err := c.readHandshake() | ||
151 | 63 | + if err != nil { | ||
152 | 64 | + return err | ||
153 | 65 | + } | ||
154 | 66 | + _, ok := msg.(*helloRequestMsg) | ||
155 | 67 | + if !ok { | ||
156 | 68 | + c.sendAlert(alertUnexpectedMessage) | ||
157 | 69 | + return alertUnexpectedMessage | ||
158 | 70 | + } | ||
159 | 71 | + | ||
160 | 72 | + return c.Handshake() | ||
161 | 73 | +} | ||
162 | 74 | + | ||
163 | 75 | // Read can be made to time out and return a net.Error with Timeout() == true | ||
164 | 76 | // after a fixed time limit; see SetDeadline and SetReadDeadline. | ||
165 | 77 | func (c *Conn) Read(b []byte) (n int, err error) { | ||
166 | 78 | @@ -844,6 +868,14 @@ | ||
167 | 79 | // Soft error, like EAGAIN | ||
168 | 80 | return 0, err | ||
169 | 81 | } | ||
170 | 82 | + if c.hand.Len() > 0 { | ||
171 | 83 | + // We received handshake bytes, indicating the start of | ||
172 | 84 | + // a renegotiation. | ||
173 | 85 | + if err := c.handleRenegotiation(); err != nil { | ||
174 | 86 | + return 0, err | ||
175 | 87 | + } | ||
176 | 88 | + continue | ||
177 | 89 | + } | ||
178 | 90 | } | ||
179 | 91 | if err := c.error(); err != nil { | ||
180 | 92 | return 0, err | ||
181 | 93 | diff -r c242bbf5fa8c src/pkg/crypto/tls/handshake_messages.go | ||
182 | 94 | --- a/src/pkg/crypto/tls/handshake_messages.go Wed Jul 17 14:03:27 2013 -0400 | ||
183 | 95 | +++ b/src/pkg/crypto/tls/handshake_messages.go Thu Jul 18 13:45:43 2013 -0400 | ||
184 | 96 | @@ -1243,6 +1243,17 @@ | ||
185 | 97 | return true | ||
186 | 98 | } | ||
187 | 99 | |||
188 | 100 | +type helloRequestMsg struct { | ||
189 | 101 | +} | ||
190 | 102 | + | ||
191 | 103 | +func (*helloRequestMsg) marshal() []byte { | ||
192 | 104 | + return []byte{typeHelloRequest, 0, 0, 0} | ||
193 | 105 | +} | ||
194 | 106 | + | ||
195 | 107 | +func (*helloRequestMsg) unmarshal(data []byte) bool { | ||
196 | 108 | + return len(data) == 4 | ||
197 | 109 | +} | ||
198 | 110 | + | ||
199 | 111 | func eqUint16s(x, y []uint16) bool { | ||
200 | 112 | if len(x) != len(y) { | ||
201 | 113 | return false | ||
202 | 0 | 114 | ||
203 | === added directory 'fork/http' | |||
204 | === added file 'fork/http/chunked.go' | |||
205 | --- fork/http/chunked.go 1970-01-01 00:00:00 +0000 | |||
206 | +++ fork/http/chunked.go 2013-07-22 14:27:42 +0000 | |||
207 | @@ -0,0 +1,170 @@ | |||
208 | 1 | // Copyright 2009 The Go Authors. All rights reserved. | ||
209 | 2 | // Use of this source code is governed by a BSD-style | ||
210 | 3 | // license that can be found in the LICENSE file. | ||
211 | 4 | |||
212 | 5 | // The wire protocol for HTTP's "chunked" Transfer-Encoding. | ||
213 | 6 | |||
214 | 7 | // This code is duplicated in httputil/chunked.go. | ||
215 | 8 | // Please make any changes in both files. | ||
216 | 9 | |||
217 | 10 | package http | ||
218 | 11 | |||
219 | 12 | import ( | ||
220 | 13 | "bufio" | ||
221 | 14 | "bytes" | ||
222 | 15 | "errors" | ||
223 | 16 | "io" | ||
224 | 17 | "strconv" | ||
225 | 18 | ) | ||
226 | 19 | |||
227 | 20 | const maxLineLength = 4096 // assumed <= bufio.defaultBufSize | ||
228 | 21 | |||
229 | 22 | var ErrLineTooLong = errors.New("header line too long") | ||
230 | 23 | |||
231 | 24 | // newChunkedReader returns a new chunkedReader that translates the data read from r | ||
232 | 25 | // out of HTTP "chunked" format before returning it. | ||
233 | 26 | // The chunkedReader returns io.EOF when the final 0-length chunk is read. | ||
234 | 27 | // | ||
235 | 28 | // newChunkedReader is not needed by normal applications. The http package | ||
236 | 29 | // automatically decodes chunking when reading response bodies. | ||
237 | 30 | func newChunkedReader(r io.Reader) io.Reader { | ||
238 | 31 | br, ok := r.(*bufio.Reader) | ||
239 | 32 | if !ok { | ||
240 | 33 | br = bufio.NewReader(r) | ||
241 | 34 | } | ||
242 | 35 | return &chunkedReader{r: br} | ||
243 | 36 | } | ||
244 | 37 | |||
245 | 38 | type chunkedReader struct { | ||
246 | 39 | r *bufio.Reader | ||
247 | 40 | n uint64 // unread bytes in chunk | ||
248 | 41 | err error | ||
249 | 42 | } | ||
250 | 43 | |||
251 | 44 | func (cr *chunkedReader) beginChunk() { | ||
252 | 45 | // chunk-size CRLF | ||
253 | 46 | var line string | ||
254 | 47 | line, cr.err = readLine(cr.r) | ||
255 | 48 | if cr.err != nil { | ||
256 | 49 | return | ||
257 | 50 | } | ||
258 | 51 | cr.n, cr.err = strconv.ParseUint(line, 16, 64) | ||
259 | 52 | if cr.err != nil { | ||
260 | 53 | return | ||
261 | 54 | } | ||
262 | 55 | if cr.n == 0 { | ||
263 | 56 | cr.err = io.EOF | ||
264 | 57 | } | ||
265 | 58 | } | ||
266 | 59 | |||
267 | 60 | func (cr *chunkedReader) Read(b []uint8) (n int, err error) { | ||
268 | 61 | if cr.err != nil { | ||
269 | 62 | return 0, cr.err | ||
270 | 63 | } | ||
271 | 64 | if cr.n == 0 { | ||
272 | 65 | cr.beginChunk() | ||
273 | 66 | if cr.err != nil { | ||
274 | 67 | return 0, cr.err | ||
275 | 68 | } | ||
276 | 69 | } | ||
277 | 70 | if uint64(len(b)) > cr.n { | ||
278 | 71 | b = b[0:cr.n] | ||
279 | 72 | } | ||
280 | 73 | n, cr.err = cr.r.Read(b) | ||
281 | 74 | cr.n -= uint64(n) | ||
282 | 75 | if cr.n == 0 && cr.err == nil { | ||
283 | 76 | // end of chunk (CRLF) | ||
284 | 77 | b := make([]byte, 2) | ||
285 | 78 | if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil { | ||
286 | 79 | if b[0] != '\r' || b[1] != '\n' { | ||
287 | 80 | cr.err = errors.New("malformed chunked encoding") | ||
288 | 81 | } | ||
289 | 82 | } | ||
290 | 83 | } | ||
291 | 84 | return n, cr.err | ||
292 | 85 | } | ||
293 | 86 | |||
294 | 87 | // Read a line of bytes (up to \n) from b. | ||
295 | 88 | // Give up if the line exceeds maxLineLength. | ||
296 | 89 | // The returned bytes are a pointer into storage in | ||
297 | 90 | // the bufio, so they are only valid until the next bufio read. | ||
298 | 91 | func readLineBytes(b *bufio.Reader) (p []byte, err error) { | ||
299 | 92 | if p, err = b.ReadSlice('\n'); err != nil { | ||
300 | 93 | // We always know when EOF is coming. | ||
301 | 94 | // If the caller asked for a line, there should be a line. | ||
302 | 95 | if err == io.EOF { | ||
303 | 96 | err = io.ErrUnexpectedEOF | ||
304 | 97 | } else if err == bufio.ErrBufferFull { | ||
305 | 98 | err = ErrLineTooLong | ||
306 | 99 | } | ||
307 | 100 | return nil, err | ||
308 | 101 | } | ||
309 | 102 | if len(p) >= maxLineLength { | ||
310 | 103 | return nil, ErrLineTooLong | ||
311 | 104 | } | ||
312 | 105 | |||
313 | 106 | // Chop off trailing white space. | ||
314 | 107 | p = bytes.TrimRight(p, " \r\t\n") | ||
315 | 108 | |||
316 | 109 | return p, nil | ||
317 | 110 | } | ||
318 | 111 | |||
319 | 112 | // readLineBytes, but convert the bytes into a string. | ||
320 | 113 | func readLine(b *bufio.Reader) (s string, err error) { | ||
321 | 114 | p, e := readLineBytes(b) | ||
322 | 115 | if e != nil { | ||
323 | 116 | return "", e | ||
324 | 117 | } | ||
325 | 118 | return string(p), nil | ||
326 | 119 | } | ||
327 | 120 | |||
328 | 121 | // newChunkedWriter returns a new chunkedWriter that translates writes into HTTP | ||
329 | 122 | // "chunked" format before writing them to w. Closing the returned chunkedWriter | ||
330 | 123 | // sends the final 0-length chunk that marks the end of the stream. | ||
331 | 124 | // | ||
332 | 125 | // newChunkedWriter is not needed by normal applications. The http | ||
333 | 126 | // package adds chunking automatically if handlers don't set a | ||
334 | 127 | // Content-Length header. Using newChunkedWriter inside a handler | ||
335 | 128 | // would result in double chunking or chunking with a Content-Length | ||
336 | 129 | // length, both of which are wrong. | ||
337 | 130 | func newChunkedWriter(w io.Writer) io.WriteCloser { | ||
338 | 131 | return &chunkedWriter{w} | ||
339 | 132 | } | ||
340 | 133 | |||
341 | 134 | // Writing to chunkedWriter translates to writing in HTTP chunked Transfer | ||
342 | 135 | // Encoding wire format to the underlying Wire chunkedWriter. | ||
343 | 136 | type chunkedWriter struct { | ||
344 | 137 | Wire io.Writer | ||
345 | 138 | } | ||
346 | 139 | |||
347 | 140 | // Write the contents of data as one chunk to Wire. | ||
348 | 141 | // NOTE: Note that the corresponding chunk-writing procedure in Conn.Write has | ||
349 | 142 | // a bug since it does not check for success of io.WriteString | ||
350 | 143 | func (cw *chunkedWriter) Write(data []byte) (n int, err error) { | ||
351 | 144 | |||
352 | 145 | // Don't send 0-length data. It looks like EOF for chunked encoding. | ||
353 | 146 | if len(data) == 0 { | ||
354 | 147 | return 0, nil | ||
355 | 148 | } | ||
356 | 149 | |||
357 | 150 | head := strconv.FormatInt(int64(len(data)), 16) + "\r\n" | ||
358 | 151 | |||
359 | 152 | if _, err = io.WriteString(cw.Wire, head); err != nil { | ||
360 | 153 | return 0, err | ||
361 | 154 | } | ||
362 | 155 | if n, err = cw.Wire.Write(data); err != nil { | ||
363 | 156 | return | ||
364 | 157 | } | ||
365 | 158 | if n != len(data) { | ||
366 | 159 | err = io.ErrShortWrite | ||
367 | 160 | return | ||
368 | 161 | } | ||
369 | 162 | _, err = io.WriteString(cw.Wire, "\r\n") | ||
370 | 163 | |||
371 | 164 | return | ||
372 | 165 | } | ||
373 | 166 | |||
374 | 167 | func (cw *chunkedWriter) Close() error { | ||
375 | 168 | _, err := io.WriteString(cw.Wire, "0\r\n") | ||
376 | 169 | return err | ||
377 | 170 | } | ||
378 | 0 | 171 | ||
379 | === added file 'fork/http/client.go' | |||
380 | --- fork/http/client.go 1970-01-01 00:00:00 +0000 | |||
381 | +++ fork/http/client.go 2013-07-22 14:27:42 +0000 | |||
382 | @@ -0,0 +1,339 @@ | |||
383 | 1 | // Copyright 2009 The Go Authors. All rights reserved. | ||
384 | 2 | // Use of this source code is governed by a BSD-style | ||
385 | 3 | // license that can be found in the LICENSE file. | ||
386 | 4 | |||
387 | 5 | // HTTP client. See RFC 2616. | ||
388 | 6 | // | ||
389 | 7 | // This is the high-level Client interface. | ||
390 | 8 | // The low-level implementation is in transport.go. | ||
391 | 9 | |||
392 | 10 | package http | ||
393 | 11 | |||
394 | 12 | import ( | ||
395 | 13 | "encoding/base64" | ||
396 | 14 | "errors" | ||
397 | 15 | "fmt" | ||
398 | 16 | "io" | ||
399 | 17 | "net/url" | ||
400 | 18 | "strings" | ||
401 | 19 | ) | ||
402 | 20 | |||
403 | 21 | // A Client is an HTTP client. Its zero value (DefaultClient) is a usable client | ||
404 | 22 | // that uses DefaultTransport. | ||
405 | 23 | // | ||
406 | 24 | // The Client's Transport typically has internal state (cached | ||
407 | 25 | // TCP connections), so Clients should be reused instead of created as | ||
408 | 26 | // needed. Clients are safe for concurrent use by multiple goroutines. | ||
409 | 27 | type Client struct { | ||
410 | 28 | // Transport specifies the mechanism by which individual | ||
411 | 29 | // HTTP requests are made. | ||
412 | 30 | // If nil, DefaultTransport is used. | ||
413 | 31 | Transport RoundTripper | ||
414 | 32 | |||
415 | 33 | // CheckRedirect specifies the policy for handling redirects. | ||
416 | 34 | // If CheckRedirect is not nil, the client calls it before | ||
417 | 35 | // following an HTTP redirect. The arguments req and via | ||
418 | 36 | // are the upcoming request and the requests made already, | ||
419 | 37 | // oldest first. If CheckRedirect returns an error, the client | ||
420 | 38 | // returns that error instead of issue the Request req. | ||
421 | 39 | // | ||
422 | 40 | // If CheckRedirect is nil, the Client uses its default policy, | ||
423 | 41 | // which is to stop after 10 consecutive requests. | ||
424 | 42 | CheckRedirect func(req *Request, via []*Request) error | ||
425 | 43 | |||
426 | 44 | // Jar specifies the cookie jar. | ||
427 | 45 | // If Jar is nil, cookies are not sent in requests and ignored | ||
428 | 46 | // in responses. | ||
429 | 47 | Jar CookieJar | ||
430 | 48 | } | ||
431 | 49 | |||
432 | 50 | // DefaultClient is the default Client and is used by Get, Head, and Post. | ||
433 | 51 | var DefaultClient = &Client{} | ||
434 | 52 | |||
435 | 53 | // RoundTripper is an interface representing the ability to execute a | ||
436 | 54 | // single HTTP transaction, obtaining the Response for a given Request. | ||
437 | 55 | // | ||
438 | 56 | // A RoundTripper must be safe for concurrent use by multiple | ||
439 | 57 | // goroutines. | ||
440 | 58 | type RoundTripper interface { | ||
441 | 59 | // RoundTrip executes a single HTTP transaction, returning | ||
442 | 60 | // the Response for the request req. RoundTrip should not | ||
443 | 61 | // attempt to interpret the response. In particular, | ||
444 | 62 | // RoundTrip must return err == nil if it obtained a response, | ||
445 | 63 | // regardless of the response's HTTP status code. A non-nil | ||
446 | 64 | // err should be reserved for failure to obtain a response. | ||
447 | 65 | // Similarly, RoundTrip should not attempt to handle | ||
448 | 66 | // higher-level protocol details such as redirects, | ||
449 | 67 | // authentication, or cookies. | ||
450 | 68 | // | ||
451 | 69 | // RoundTrip should not modify the request, except for | ||
452 | 70 | // consuming the Body. The request's URL and Header fields | ||
453 | 71 | // are guaranteed to be initialized. | ||
454 | 72 | RoundTrip(*Request) (*Response, error) | ||
455 | 73 | } | ||
456 | 74 | |||
457 | 75 | // Given a string of the form "host", "host:port", or "[ipv6::address]:port", | ||
458 | 76 | // return true if the string includes a port. | ||
459 | 77 | func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | ||
460 | 78 | |||
461 | 79 | // Used in Send to implement io.ReadCloser by bundling together the | ||
462 | 80 | // bufio.Reader through which we read the response, and the underlying | ||
463 | 81 | // network connection. | ||
464 | 82 | type readClose struct { | ||
465 | 83 | io.Reader | ||
466 | 84 | io.Closer | ||
467 | 85 | } | ||
468 | 86 | |||
469 | 87 | // Do sends an HTTP request and returns an HTTP response, following | ||
470 | 88 | // policy (e.g. redirects, cookies, auth) as configured on the client. | ||
471 | 89 | // | ||
472 | 90 | // A non-nil response always contains a non-nil resp.Body. | ||
473 | 91 | // | ||
474 | 92 | // Callers should close resp.Body when done reading from it. If | ||
475 | 93 | // resp.Body is not closed, the Client's underlying RoundTripper | ||
476 | 94 | // (typically Transport) may not be able to re-use a persistent TCP | ||
477 | 95 | // connection to the server for a subsequent "keep-alive" request. | ||
478 | 96 | // | ||
479 | 97 | // Generally Get, Post, or PostForm will be used instead of Do. | ||
480 | 98 | func (c *Client) Do(req *Request) (resp *Response, err error) { | ||
481 | 99 | if req.Method == "GET" || req.Method == "HEAD" { | ||
482 | 100 | return c.doFollowingRedirects(req) | ||
483 | 101 | } | ||
484 | 102 | return send(req, c.Transport) | ||
485 | 103 | } | ||
486 | 104 | |||
487 | 105 | // send issues an HTTP request. Caller should close resp.Body when done reading from it. | ||
488 | 106 | func send(req *Request, t RoundTripper) (resp *Response, err error) { | ||
489 | 107 | if t == nil { | ||
490 | 108 | t = DefaultTransport | ||
491 | 109 | if t == nil { | ||
492 | 110 | err = errors.New("http: no Client.Transport or DefaultTransport") | ||
493 | 111 | return | ||
494 | 112 | } | ||
495 | 113 | } | ||
496 | 114 | |||
497 | 115 | if req.URL == nil { | ||
498 | 116 | return nil, errors.New("http: nil Request.URL") | ||
499 | 117 | } | ||
500 | 118 | |||
501 | 119 | if req.RequestURI != "" { | ||
502 | 120 | return nil, errors.New("http: Request.RequestURI can't be set in client requests.") | ||
503 | 121 | } | ||
504 | 122 | |||
505 | 123 | // Most the callers of send (Get, Post, et al) don't need | ||
506 | 124 | // Headers, leaving it uninitialized. We guarantee to the | ||
507 | 125 | // Transport that this has been initialized, though. | ||
508 | 126 | if req.Header == nil { | ||
509 | 127 | req.Header = make(Header) | ||
510 | 128 | } | ||
511 | 129 | |||
512 | 130 | if u := req.URL.User; u != nil { | ||
513 | 131 | req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(u.String()))) | ||
514 | 132 | } | ||
515 | 133 | return t.RoundTrip(req) | ||
516 | 134 | } | ||
517 | 135 | |||
518 | 136 | // True if the specified HTTP status code is one for which the Get utility should | ||
519 | 137 | // automatically redirect. | ||
520 | 138 | func shouldRedirect(statusCode int) bool { | ||
521 | 139 | switch statusCode { | ||
522 | 140 | case StatusMovedPermanently, StatusFound, StatusSeeOther, StatusTemporaryRedirect: | ||
523 | 141 | return true | ||
524 | 142 | } | ||
525 | 143 | return false | ||
526 | 144 | } | ||
527 | 145 | |||
528 | 146 | // Get issues a GET to the specified URL. If the response is one of the following | ||
529 | 147 | // redirect codes, Get follows the redirect, up to a maximum of 10 redirects: | ||
530 | 148 | // | ||
531 | 149 | // 301 (Moved Permanently) | ||
532 | 150 | // 302 (Found) | ||
533 | 151 | // 303 (See Other) | ||
534 | 152 | // 307 (Temporary Redirect) | ||
535 | 153 | // | ||
536 | 154 | // Caller should close r.Body when done reading from it. | ||
537 | 155 | // | ||
538 | 156 | // Get is a wrapper around DefaultClient.Get. | ||
539 | 157 | func Get(url string) (r *Response, err error) { | ||
540 | 158 | return DefaultClient.Get(url) | ||
541 | 159 | } | ||
542 | 160 | |||
543 | 161 | // Get issues a GET to the specified URL. If the response is one of the | ||
544 | 162 | // following redirect codes, Get follows the redirect after calling the | ||
545 | 163 | // Client's CheckRedirect function. | ||
546 | 164 | // | ||
547 | 165 | // 301 (Moved Permanently) | ||
548 | 166 | // 302 (Found) | ||
549 | 167 | // 303 (See Other) | ||
550 | 168 | // 307 (Temporary Redirect) | ||
551 | 169 | // | ||
552 | 170 | // Caller should close r.Body when done reading from it. | ||
553 | 171 | func (c *Client) Get(url string) (r *Response, err error) { | ||
554 | 172 | req, err := NewRequest("GET", url, nil) | ||
555 | 173 | if err != nil { | ||
556 | 174 | return nil, err | ||
557 | 175 | } | ||
558 | 176 | return c.doFollowingRedirects(req) | ||
559 | 177 | } | ||
560 | 178 | |||
561 | 179 | func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) { | ||
562 | 180 | // TODO: if/when we add cookie support, the redirected request shouldn't | ||
563 | 181 | // necessarily supply the same cookies as the original. | ||
564 | 182 | var base *url.URL | ||
565 | 183 | redirectChecker := c.CheckRedirect | ||
566 | 184 | if redirectChecker == nil { | ||
567 | 185 | redirectChecker = defaultCheckRedirect | ||
568 | 186 | } | ||
569 | 187 | var via []*Request | ||
570 | 188 | |||
571 | 189 | if ireq.URL == nil { | ||
572 | 190 | return nil, errors.New("http: nil Request.URL") | ||
573 | 191 | } | ||
574 | 192 | |||
575 | 193 | jar := c.Jar | ||
576 | 194 | if jar == nil { | ||
577 | 195 | jar = blackHoleJar{} | ||
578 | 196 | } | ||
579 | 197 | |||
580 | 198 | req := ireq | ||
581 | 199 | urlStr := "" // next relative or absolute URL to fetch (after first request) | ||
582 | 200 | for redirect := 0; ; redirect++ { | ||
583 | 201 | if redirect != 0 { | ||
584 | 202 | req = new(Request) | ||
585 | 203 | req.Method = ireq.Method | ||
586 | 204 | req.Header = make(Header) | ||
587 | 205 | req.URL, err = base.Parse(urlStr) | ||
588 | 206 | if err != nil { | ||
589 | 207 | break | ||
590 | 208 | } | ||
591 | 209 | if len(via) > 0 { | ||
592 | 210 | // Add the Referer header. | ||
593 | 211 | lastReq := via[len(via)-1] | ||
594 | 212 | if lastReq.URL.Scheme != "https" { | ||
595 | 213 | req.Header.Set("Referer", lastReq.URL.String()) | ||
596 | 214 | } | ||
597 | 215 | |||
598 | 216 | err = redirectChecker(req, via) | ||
599 | 217 | if err != nil { | ||
600 | 218 | break | ||
601 | 219 | } | ||
602 | 220 | } | ||
603 | 221 | } | ||
604 | 222 | |||
605 | 223 | for _, cookie := range jar.Cookies(req.URL) { | ||
606 | 224 | req.AddCookie(cookie) | ||
607 | 225 | } | ||
608 | 226 | urlStr = req.URL.String() | ||
609 | 227 | if r, err = send(req, c.Transport); err != nil { | ||
610 | 228 | break | ||
611 | 229 | } | ||
612 | 230 | if c := r.Cookies(); len(c) > 0 { | ||
613 | 231 | jar.SetCookies(req.URL, c) | ||
614 | 232 | } | ||
615 | 233 | |||
616 | 234 | if shouldRedirect(r.StatusCode) { | ||
617 | 235 | r.Body.Close() | ||
618 | 236 | if urlStr = r.Header.Get("Location"); urlStr == "" { | ||
619 | 237 | err = errors.New(fmt.Sprintf("%d response missing Location header", r.StatusCode)) | ||
620 | 238 | break | ||
621 | 239 | } | ||
622 | 240 | base = req.URL | ||
623 | 241 | via = append(via, req) | ||
624 | 242 | continue | ||
625 | 243 | } | ||
626 | 244 | return | ||
627 | 245 | } | ||
628 | 246 | |||
629 | 247 | method := ireq.Method | ||
630 | 248 | err = &url.Error{ | ||
631 | 249 | Op: method[0:1] + strings.ToLower(method[1:]), | ||
632 | 250 | URL: urlStr, | ||
633 | 251 | Err: err, | ||
634 | 252 | } | ||
635 | 253 | return | ||
636 | 254 | } | ||
637 | 255 | |||
638 | 256 | func defaultCheckRedirect(req *Request, via []*Request) error { | ||
639 | 257 | if len(via) >= 10 { | ||
640 | 258 | return errors.New("stopped after 10 redirects") | ||
641 | 259 | } | ||
642 | 260 | return nil | ||
643 | 261 | } | ||
644 | 262 | |||
645 | 263 | // Post issues a POST to the specified URL. | ||
646 | 264 | // | ||
647 | 265 | // Caller should close r.Body when done reading from it. | ||
648 | 266 | // | ||
649 | 267 | // Post is a wrapper around DefaultClient.Post | ||
650 | 268 | func Post(url string, bodyType string, body io.Reader) (r *Response, err error) { | ||
651 | 269 | return DefaultClient.Post(url, bodyType, body) | ||
652 | 270 | } | ||
653 | 271 | |||
654 | 272 | // Post issues a POST to the specified URL. | ||
655 | 273 | // | ||
656 | 274 | // Caller should close r.Body when done reading from it. | ||
657 | 275 | func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response, err error) { | ||
658 | 276 | req, err := NewRequest("POST", url, body) | ||
659 | 277 | if err != nil { | ||
660 | 278 | return nil, err | ||
661 | 279 | } | ||
662 | 280 | req.Header.Set("Content-Type", bodyType) | ||
663 | 281 | if c.Jar != nil { | ||
664 | 282 | for _, cookie := range c.Jar.Cookies(req.URL) { | ||
665 | 283 | req.AddCookie(cookie) | ||
666 | 284 | } | ||
667 | 285 | } | ||
668 | 286 | r, err = send(req, c.Transport) | ||
669 | 287 | if err == nil && c.Jar != nil { | ||
670 | 288 | c.Jar.SetCookies(req.URL, r.Cookies()) | ||
671 | 289 | } | ||
672 | 290 | return r, err | ||
673 | 291 | } | ||
674 | 292 | |||
675 | 293 | // PostForm issues a POST to the specified URL, | ||
676 | 294 | // with data's keys and values urlencoded as the request body. | ||
677 | 295 | // | ||
678 | 296 | // Caller should close r.Body when done reading from it. | ||
679 | 297 | // | ||
680 | 298 | // PostForm is a wrapper around DefaultClient.PostForm | ||
681 | 299 | func PostForm(url string, data url.Values) (r *Response, err error) { | ||
682 | 300 | return DefaultClient.PostForm(url, data) | ||
683 | 301 | } | ||
684 | 302 | |||
685 | 303 | // PostForm issues a POST to the specified URL, | ||
686 | 304 | // with data's keys and values urlencoded as the request body. | ||
687 | 305 | // | ||
688 | 306 | // Caller should close r.Body when done reading from it. | ||
689 | 307 | func (c *Client) PostForm(url string, data url.Values) (r *Response, err error) { | ||
690 | 308 | return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) | ||
691 | 309 | } | ||
692 | 310 | |||
693 | 311 | // Head issues a HEAD to the specified URL. If the response is one of the | ||
694 | 312 | // following redirect codes, Head follows the redirect after calling the | ||
695 | 313 | // Client's CheckRedirect function. | ||
696 | 314 | // | ||
697 | 315 | // 301 (Moved Permanently) | ||
698 | 316 | // 302 (Found) | ||
699 | 317 | // 303 (See Other) | ||
700 | 318 | // 307 (Temporary Redirect) | ||
701 | 319 | // | ||
702 | 320 | // Head is a wrapper around DefaultClient.Head | ||
703 | 321 | func Head(url string) (r *Response, err error) { | ||
704 | 322 | return DefaultClient.Head(url) | ||
705 | 323 | } | ||
706 | 324 | |||
707 | 325 | // Head issues a HEAD to the specified URL. If the response is one of the | ||
708 | 326 | // following redirect codes, Head follows the redirect after calling the | ||
709 | 327 | // Client's CheckRedirect function. | ||
710 | 328 | // | ||
711 | 329 | // 301 (Moved Permanently) | ||
712 | 330 | // 302 (Found) | ||
713 | 331 | // 303 (See Other) | ||
714 | 332 | // 307 (Temporary Redirect) | ||
715 | 333 | func (c *Client) Head(url string) (r *Response, err error) { | ||
716 | 334 | req, err := NewRequest("HEAD", url, nil) | ||
717 | 335 | if err != nil { | ||
718 | 336 | return nil, err | ||
719 | 337 | } | ||
720 | 338 | return c.doFollowingRedirects(req) | ||
721 | 339 | } | ||
722 | 0 | 340 | ||
723 | === added file 'fork/http/cookie.go' | |||
724 | --- fork/http/cookie.go 1970-01-01 00:00:00 +0000 | |||
725 | +++ fork/http/cookie.go 2013-07-22 14:27:42 +0000 | |||
726 | @@ -0,0 +1,267 @@ | |||
727 | 1 | // Copyright 2009 The Go Authors. All rights reserved. | ||
728 | 2 | // Use of this source code is governed by a BSD-style | ||
729 | 3 | // license that can be found in the LICENSE file. | ||
730 | 4 | |||
731 | 5 | package http | ||
732 | 6 | |||
733 | 7 | import ( | ||
734 | 8 | "bytes" | ||
735 | 9 | "fmt" | ||
736 | 10 | "strconv" | ||
737 | 11 | "strings" | ||
738 | 12 | "time" | ||
739 | 13 | ) | ||
740 | 14 | |||
741 | 15 | // This implementation is done according to RFC 6265: | ||
742 | 16 | // | ||
743 | 17 | // http://tools.ietf.org/html/rfc6265 | ||
744 | 18 | |||
745 | 19 | // A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an | ||
746 | 20 | // HTTP response or the Cookie header of an HTTP request. | ||
747 | 21 | type Cookie struct { | ||
748 | 22 | Name string | ||
749 | 23 | Value string | ||
750 | 24 | Path string | ||
751 | 25 | Domain string | ||
752 | 26 | Expires time.Time | ||
753 | 27 | RawExpires string | ||
754 | 28 | |||
755 | 29 | // MaxAge=0 means no 'Max-Age' attribute specified. | ||
756 | 30 | // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' | ||
757 | 31 | // MaxAge>0 means Max-Age attribute present and given in seconds | ||
758 | 32 | MaxAge int | ||
759 | 33 | Secure bool | ||
760 | 34 | HttpOnly bool | ||
761 | 35 | Raw string | ||
762 | 36 | Unparsed []string // Raw text of unparsed attribute-value pairs | ||
763 | 37 | } | ||
764 | 38 | |||
765 | 39 | // readSetCookies parses all "Set-Cookie" values from | ||
766 | 40 | // the header h and returns the successfully parsed Cookies. | ||
767 | 41 | func readSetCookies(h Header) []*Cookie { | ||
768 | 42 | cookies := []*Cookie{} | ||
769 | 43 | for _, line := range h["Set-Cookie"] { | ||
770 | 44 | parts := strings.Split(strings.TrimSpace(line), ";") | ||
771 | 45 | if len(parts) == 1 && parts[0] == "" { | ||
772 | 46 | continue | ||
773 | 47 | } | ||
774 | 48 | parts[0] = strings.TrimSpace(parts[0]) | ||
775 | 49 | j := strings.Index(parts[0], "=") | ||
776 | 50 | if j < 0 { | ||
777 | 51 | continue | ||
778 | 52 | } | ||
779 | 53 | name, value := parts[0][:j], parts[0][j+1:] | ||
780 | 54 | if !isCookieNameValid(name) { | ||
781 | 55 | continue | ||
782 | 56 | } | ||
783 | 57 | value, success := parseCookieValue(value) | ||
784 | 58 | if !success { | ||
785 | 59 | continue | ||
786 | 60 | } | ||
787 | 61 | c := &Cookie{ | ||
788 | 62 | Name: name, | ||
789 | 63 | Value: value, | ||
790 | 64 | Raw: line, | ||
791 | 65 | } | ||
792 | 66 | for i := 1; i < len(parts); i++ { | ||
793 | 67 | parts[i] = strings.TrimSpace(parts[i]) | ||
794 | 68 | if len(parts[i]) == 0 { | ||
795 | 69 | continue | ||
796 | 70 | } | ||
797 | 71 | |||
798 | 72 | attr, val := parts[i], "" | ||
799 | 73 | if j := strings.Index(attr, "="); j >= 0 { | ||
800 | 74 | attr, val = attr[:j], attr[j+1:] | ||
801 | 75 | } | ||
802 | 76 | lowerAttr := strings.ToLower(attr) | ||
803 | 77 | parseCookieValueFn := parseCookieValue | ||
804 | 78 | if lowerAttr == "expires" { | ||
805 | 79 | parseCookieValueFn = parseCookieExpiresValue | ||
806 | 80 | } | ||
807 | 81 | val, success = parseCookieValueFn(val) | ||
808 | 82 | if !success { | ||
809 | 83 | c.Unparsed = append(c.Unparsed, parts[i]) | ||
810 | 84 | continue | ||
811 | 85 | } | ||
812 | 86 | switch lowerAttr { | ||
813 | 87 | case "secure": | ||
814 | 88 | c.Secure = true | ||
815 | 89 | continue | ||
816 | 90 | case "httponly": | ||
817 | 91 | c.HttpOnly = true | ||
818 | 92 | continue | ||
819 | 93 | case "domain": | ||
820 | 94 | c.Domain = val | ||
821 | 95 | // TODO: Add domain parsing | ||
822 | 96 | continue | ||
823 | 97 | case "max-age": | ||
824 | 98 | secs, err := strconv.Atoi(val) | ||
825 | 99 | if err != nil || secs != 0 && val[0] == '0' { | ||
826 | 100 | break | ||
827 | 101 | } | ||
828 | 102 | if secs <= 0 { | ||
829 | 103 | c.MaxAge = -1 | ||
830 | 104 | } else { | ||
831 | 105 | c.MaxAge = secs | ||
832 | 106 | } | ||
833 | 107 | continue | ||
834 | 108 | case "expires": | ||
835 | 109 | c.RawExpires = val | ||
836 | 110 | exptime, err := time.Parse(time.RFC1123, val) | ||
837 | 111 | if err != nil { | ||
838 | 112 | exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", val) | ||
839 | 113 | if err != nil { | ||
840 | 114 | c.Expires = time.Time{} | ||
841 | 115 | break | ||
842 | 116 | } | ||
843 | 117 | } | ||
844 | 118 | c.Expires = exptime.UTC() | ||
845 | 119 | continue | ||
846 | 120 | case "path": | ||
847 | 121 | c.Path = val | ||
848 | 122 | // TODO: Add path parsing | ||
849 | 123 | continue | ||
850 | 124 | } | ||
851 | 125 | c.Unparsed = append(c.Unparsed, parts[i]) | ||
852 | 126 | } | ||
853 | 127 | cookies = append(cookies, c) | ||
854 | 128 | } | ||
855 | 129 | return cookies | ||
856 | 130 | } | ||
857 | 131 | |||
858 | 132 | // SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers. | ||
859 | 133 | func SetCookie(w ResponseWriter, cookie *Cookie) { | ||
860 | 134 | w.Header().Add("Set-Cookie", cookie.String()) | ||
861 | 135 | } | ||
862 | 136 | |||
863 | 137 | // String returns the serialization of the cookie for use in a Cookie | ||
864 | 138 | // header (if only Name and Value are set) or a Set-Cookie response | ||
865 | 139 | // header (if other fields are set). | ||
866 | 140 | func (c *Cookie) String() string { | ||
867 | 141 | var b bytes.Buffer | ||
868 | 142 | fmt.Fprintf(&b, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value)) | ||
869 | 143 | if len(c.Path) > 0 { | ||
870 | 144 | fmt.Fprintf(&b, "; Path=%s", sanitizeValue(c.Path)) | ||
871 | 145 | } | ||
872 | 146 | if len(c.Domain) > 0 { | ||
873 | 147 | fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain)) | ||
874 | 148 | } | ||
875 | 149 | if c.Expires.Unix() > 0 { | ||
876 | 150 | fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(time.RFC1123)) | ||
877 | 151 | } | ||
878 | 152 | if c.MaxAge > 0 { | ||
879 | 153 | fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge) | ||
880 | 154 | } else if c.MaxAge < 0 { | ||
881 | 155 | fmt.Fprintf(&b, "; Max-Age=0") | ||
882 | 156 | } | ||
883 | 157 | if c.HttpOnly { | ||
884 | 158 | fmt.Fprintf(&b, "; HttpOnly") | ||
885 | 159 | } | ||
886 | 160 | if c.Secure { | ||
887 | 161 | fmt.Fprintf(&b, "; Secure") | ||
888 | 162 | } | ||
889 | 163 | return b.String() | ||
890 | 164 | } | ||
891 | 165 | |||
892 | 166 | // readCookies parses all "Cookie" values from the header h and | ||
893 | 167 | // returns the successfully parsed Cookies. | ||
894 | 168 | // | ||
895 | 169 | // if filter isn't empty, only cookies of that name are returned | ||
896 | 170 | func readCookies(h Header, filter string) []*Cookie { | ||
897 | 171 | cookies := []*Cookie{} | ||
898 | 172 | lines, ok := h["Cookie"] | ||
899 | 173 | if !ok { | ||
900 | 174 | return cookies | ||
901 | 175 | } | ||
902 | 176 | |||
903 | 177 | for _, line := range lines { | ||
904 | 178 | parts := strings.Split(strings.TrimSpace(line), ";") | ||
905 | 179 | if len(parts) == 1 && parts[0] == "" { | ||
906 | 180 | continue | ||
907 | 181 | } | ||
908 | 182 | // Per-line attributes | ||
909 | 183 | parsedPairs := 0 | ||
910 | 184 | for i := 0; i < len(parts); i++ { | ||
911 | 185 | parts[i] = strings.TrimSpace(parts[i]) | ||
912 | 186 | if len(parts[i]) == 0 { | ||
913 | 187 | continue | ||
914 | 188 | } | ||
915 | 189 | name, val := parts[i], "" | ||
916 | 190 | if j := strings.Index(name, "="); j >= 0 { | ||
917 | 191 | name, val = name[:j], name[j+1:] | ||
918 | 192 | } | ||
919 | 193 | if !isCookieNameValid(name) { | ||
920 | 194 | continue | ||
921 | 195 | } | ||
922 | 196 | if filter != "" && filter != name { | ||
923 | 197 | continue | ||
924 | 198 | } | ||
925 | 199 | val, success := parseCookieValue(val) | ||
926 | 200 | if !success { | ||
927 | 201 | continue | ||
928 | 202 | } | ||
929 | 203 | cookies = append(cookies, &Cookie{Name: name, Value: val}) | ||
930 | 204 | parsedPairs++ | ||
931 | 205 | } | ||
932 | 206 | } | ||
933 | 207 | return cookies | ||
934 | 208 | } | ||
935 | 209 | |||
936 | 210 | var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-") | ||
937 | 211 | |||
938 | 212 | func sanitizeName(n string) string { | ||
939 | 213 | return cookieNameSanitizer.Replace(n) | ||
940 | 214 | } | ||
941 | 215 | |||
942 | 216 | var cookieValueSanitizer = strings.NewReplacer("\n", " ", "\r", " ", ";", " ") | ||
943 | 217 | |||
944 | 218 | func sanitizeValue(v string) string { | ||
945 | 219 | return cookieValueSanitizer.Replace(v) | ||
946 | 220 | } | ||
947 | 221 | |||
948 | 222 | func unquoteCookieValue(v string) string { | ||
949 | 223 | if len(v) > 1 && v[0] == '"' && v[len(v)-1] == '"' { | ||
950 | 224 | return v[1 : len(v)-1] | ||
951 | 225 | } | ||
952 | 226 | return v | ||
953 | 227 | } | ||
954 | 228 | |||
955 | 229 | func isCookieByte(c byte) bool { | ||
956 | 230 | switch { | ||
957 | 231 | case c == 0x21, 0x23 <= c && c <= 0x2b, 0x2d <= c && c <= 0x3a, | ||
958 | 232 | 0x3c <= c && c <= 0x5b, 0x5d <= c && c <= 0x7e: | ||
959 | 233 | return true | ||
960 | 234 | } | ||
961 | 235 | return false | ||
962 | 236 | } | ||
963 | 237 | |||
964 | 238 | func isCookieExpiresByte(c byte) (ok bool) { | ||
965 | 239 | return isCookieByte(c) || c == ',' || c == ' ' | ||
966 | 240 | } | ||
967 | 241 | |||
968 | 242 | func parseCookieValue(raw string) (string, bool) { | ||
969 | 243 | return parseCookieValueUsing(raw, isCookieByte) | ||
970 | 244 | } | ||
971 | 245 | |||
972 | 246 | func parseCookieExpiresValue(raw string) (string, bool) { | ||
973 | 247 | return parseCookieValueUsing(raw, isCookieExpiresByte) | ||
974 | 248 | } | ||
975 | 249 | |||
976 | 250 | func parseCookieValueUsing(raw string, validByte func(byte) bool) (string, bool) { | ||
977 | 251 | raw = unquoteCookieValue(raw) | ||
978 | 252 | for i := 0; i < len(raw); i++ { | ||
979 | 253 | if !validByte(raw[i]) { | ||
980 | 254 | return "", false | ||
981 | 255 | } | ||
982 | 256 | } | ||
983 | 257 | return raw, true | ||
984 | 258 | } | ||
985 | 259 | |||
986 | 260 | func isCookieNameValid(raw string) bool { | ||
987 | 261 | for _, c := range raw { | ||
988 | 262 | if !isToken(byte(c)) { | ||
989 | 263 | return false | ||
990 | 264 | } | ||
991 | 265 | } | ||
992 | 266 | return true | ||
993 | 267 | } | ||
994 | 0 | 268 | ||
995 | === added file 'fork/http/doc.go' | |||
996 | --- fork/http/doc.go 1970-01-01 00:00:00 +0000 | |||
997 | +++ fork/http/doc.go 2013-07-22 14:27:42 +0000 | |||
998 | @@ -0,0 +1,80 @@ | |||
999 | 1 | // Copyright 2011 The Go Authors. All rights reserved. | ||
1000 | 2 | // Use of this source code is governed by a BSD-style | ||
1001 | 3 | // license that can be found in the LICENSE file. | ||
1002 | 4 | |||
1003 | 5 | /* | ||
1004 | 6 | Package http provides HTTP client and server implementations. | ||
1005 | 7 | |||
1006 | 8 | Get, Head, Post, and PostForm make HTTP requests: | ||
1007 | 9 | |||
1008 | 10 | resp, err := http.Get("http://example.com/") | ||
1009 | 11 | ... | ||
1010 | 12 | resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf) | ||
1011 | 13 | ... | ||
1012 | 14 | resp, err := http.PostForm("http://example.com/form", | ||
1013 | 15 | url.Values{"key": {"Value"}, "id": {"123"}}) | ||
1014 | 16 | |||
1015 | 17 | The client must close the response body when finished with it: | ||
1016 | 18 | |||
1017 | 19 | resp, err := http.Get("http://example.com/") | ||
1018 | 20 | if err != nil { | ||
1019 | 21 | // handle error | ||
1020 | 22 | } | ||
1021 | 23 | defer resp.Body.Close() | ||
1022 | 24 | body, err := ioutil.ReadAll(resp.Body) | ||
1023 | 25 | // ... | ||
1024 | 26 | |||
1025 | 27 | For control over HTTP client headers, redirect policy, and other | ||
1026 | 28 | settings, create a Client: | ||
1027 | 29 | |||
1028 | 30 | client := &http.Client{ | ||
1029 | 31 | CheckRedirect: redirectPolicyFunc, | ||
1030 | 32 | } | ||
1031 | 33 | |||
1032 | 34 | resp, err := client.Get("http://example.com") | ||
1033 | 35 | // ... | ||
1034 | 36 | |||
1035 | 37 | req, err := http.NewRequest("GET", "http://example.com", nil) | ||
1036 | 38 | // ... | ||
1037 | 39 | req.Header.Add("If-None-Match", `W/"wyzzy"`) | ||
1038 | 40 | resp, err := client.Do(req) | ||
1039 | 41 | // ... | ||
1040 | 42 | |||
1041 | 43 | For control over proxies, TLS configuration, keep-alives, | ||
1042 | 44 | compression, and other settings, create a Transport: | ||
1043 | 45 | |||
1044 | 46 | tr := &http.Transport{ | ||
1045 | 47 | TLSClientConfig: &tls.Config{RootCAs: pool}, | ||
1046 | 48 | DisableCompression: true, | ||
1047 | 49 | } | ||
1048 | 50 | client := &http.Client{Transport: tr} | ||
1049 | 51 | resp, err := client.Get("https://example.com") | ||
1050 | 52 | |||
1051 | 53 | Clients and Transports are safe for concurrent use by multiple | ||
1052 | 54 | goroutines and for efficiency should only be created once and re-used. | ||
1053 | 55 | |||
1054 | 56 | ListenAndServe starts an HTTP server with a given address and handler. | ||
1055 | 57 | The handler is usually nil, which means to use DefaultServeMux. | ||
1056 | 58 | Handle and HandleFunc add handlers to DefaultServeMux: | ||
1057 | 59 | |||
1058 | 60 | http.Handle("/foo", fooHandler) | ||
1059 | 61 | |||
1060 | 62 | http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { | ||
1061 | 63 | fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) | ||
1062 | 64 | }) | ||
1063 | 65 | |||
1064 | 66 | log.Fatal(http.ListenAndServe(":8080", nil)) | ||
1065 | 67 | |||
1066 | 68 | More control over the server's behavior is available by creating a | ||
1067 | 69 | custom Server: | ||
1068 | 70 | |||
1069 | 71 | s := &http.Server{ | ||
1070 | 72 | Addr: ":8080", | ||
1071 | 73 | Handler: myHandler, | ||
1072 | 74 | ReadTimeout: 10 * time.Second, | ||
1073 | 75 | WriteTimeout: 10 * time.Second, | ||
1074 | 76 | MaxHeaderBytes: 1 << 20, | ||
1075 | 77 | } | ||
1076 | 78 | log.Fatal(s.ListenAndServe()) | ||
1077 | 79 | */ | ||
1078 | 80 | package http | ||
1079 | 0 | 81 | ||
1080 | === added file 'fork/http/filetransport.go' | |||
1081 | --- fork/http/filetransport.go 1970-01-01 00:00:00 +0000 | |||
1082 | +++ fork/http/filetransport.go 2013-07-22 14:27:42 +0000 | |||
1083 | @@ -0,0 +1,123 @@ | |||
1084 | 1 | // Copyright 2011 The Go Authors. All rights reserved. | ||
1085 | 2 | // Use of this source code is governed by a BSD-style | ||
1086 | 3 | // license that can be found in the LICENSE file. | ||
1087 | 4 | |||
1088 | 5 | package http | ||
1089 | 6 | |||
1090 | 7 | import ( | ||
1091 | 8 | "fmt" | ||
1092 | 9 | "io" | ||
1093 | 10 | ) | ||
1094 | 11 | |||
1095 | 12 | // fileTransport implements RoundTripper for the 'file' protocol. | ||
1096 | 13 | type fileTransport struct { | ||
1097 | 14 | fh fileHandler | ||
1098 | 15 | } | ||
1099 | 16 | |||
1100 | 17 | // NewFileTransport returns a new RoundTripper, serving the provided | ||
1101 | 18 | // FileSystem. The returned RoundTripper ignores the URL host in its | ||
1102 | 19 | // incoming requests, as well as most other properties of the | ||
1103 | 20 | // request. | ||
1104 | 21 | // | ||
1105 | 22 | // The typical use case for NewFileTransport is to register the "file" | ||
1106 | 23 | // protocol with a Transport, as in: | ||
1107 | 24 | // | ||
1108 | 25 | // t := &http.Transport{} | ||
1109 | 26 | // t.RegisterProtocol("file", http.NewFileTransport(http.Dir("/"))) | ||
1110 | 27 | // c := &http.Client{Transport: t} | ||
1111 | 28 | // res, err := c.Get("file:///etc/passwd") | ||
1112 | 29 | // ... | ||
1113 | 30 | func NewFileTransport(fs FileSystem) RoundTripper { | ||
1114 | 31 | return fileTransport{fileHandler{fs}} | ||
1115 | 32 | } | ||
1116 | 33 | |||
1117 | 34 | func (t fileTransport) RoundTrip(req *Request) (resp *Response, err error) { | ||
1118 | 35 | // We start ServeHTTP in a goroutine, which may take a long | ||
1119 | 36 | // time if the file is large. The newPopulateResponseWriter | ||
1120 | 37 | // call returns a channel which either ServeHTTP or finish() | ||
1121 | 38 | // sends our *Response on, once the *Response itself has been | ||
1122 | 39 | // populated (even if the body itself is still being | ||
1123 | 40 | // written to the res.Body, a pipe) | ||
1124 | 41 | rw, resc := newPopulateResponseWriter() | ||
1125 | 42 | go func() { | ||
1126 | 43 | t.fh.ServeHTTP(rw, req) | ||
1127 | 44 | rw.finish() | ||
1128 | 45 | }() | ||
1129 | 46 | return <-resc, nil | ||
1130 | 47 | } | ||
1131 | 48 | |||
1132 | 49 | func newPopulateResponseWriter() (*populateResponse, <-chan *Response) { | ||
1133 | 50 | pr, pw := io.Pipe() | ||
1134 | 51 | rw := &populateResponse{ | ||
1135 | 52 | ch: make(chan *Response), | ||
1136 | 53 | pw: pw, | ||
1137 | 54 | res: &Response{ | ||
1138 | 55 | Proto: "HTTP/1.0", | ||
1139 | 56 | ProtoMajor: 1, | ||
1140 | 57 | Header: make(Header), | ||
1141 | 58 | Close: true, | ||
1142 | 59 | Body: pr, | ||
1143 | 60 | }, | ||
1144 | 61 | } | ||
1145 | 62 | return rw, rw.ch | ||
1146 | 63 | } | ||
1147 | 64 | |||
1148 | 65 | // populateResponse is a ResponseWriter that populates the *Response | ||
1149 | 66 | // in res, and writes its body to a pipe connected to the response | ||
1150 | 67 | // body. Once writes begin or finish() is called, the response is sent | ||
1151 | 68 | // on ch. | ||
1152 | 69 | type populateResponse struct { | ||
1153 | 70 | res *Response | ||
1154 | 71 | ch chan *Response | ||
1155 | 72 | wroteHeader bool | ||
1156 | 73 | hasContent bool | ||
1157 | 74 | sentResponse bool | ||
1158 | 75 | pw *io.PipeWriter | ||
1159 | 76 | } | ||
1160 | 77 | |||
1161 | 78 | func (pr *populateResponse) finish() { | ||
1162 | 79 | if !pr.wroteHeader { | ||
1163 | 80 | pr.WriteHeader(500) | ||
1164 | 81 | } | ||
1165 | 82 | if !pr.sentResponse { | ||
1166 | 83 | pr.sendResponse() | ||
1167 | 84 | } | ||
1168 | 85 | pr.pw.Close() | ||
1169 | 86 | } | ||
1170 | 87 | |||
1171 | 88 | func (pr *populateResponse) sendResponse() { | ||
1172 | 89 | if pr.sentResponse { | ||
1173 | 90 | return | ||
1174 | 91 | } | ||
1175 | 92 | pr.sentResponse = true | ||
1176 | 93 | |||
1177 | 94 | if pr.hasContent { | ||
1178 | 95 | pr.res.ContentLength = -1 | ||
1179 | 96 | } | ||
1180 | 97 | pr.ch <- pr.res | ||
1181 | 98 | } | ||
1182 | 99 | |||
1183 | 100 | func (pr *populateResponse) Header() Header { | ||
1184 | 101 | return pr.res.Header | ||
1185 | 102 | } | ||
1186 | 103 | |||
1187 | 104 | func (pr *populateResponse) WriteHeader(code int) { | ||
1188 | 105 | if pr.wroteHeader { | ||
1189 | 106 | return | ||
1190 | 107 | } | ||
1191 | 108 | pr.wroteHeader = true | ||
1192 | 109 | |||
1193 | 110 | pr.res.StatusCode = code | ||
1194 | 111 | pr.res.Status = fmt.Sprintf("%d %s", code, StatusText(code)) | ||
1195 | 112 | } | ||
1196 | 113 | |||
1197 | 114 | func (pr *populateResponse) Write(p []byte) (n int, err error) { | ||
1198 | 115 | if !pr.wroteHeader { | ||
1199 | 116 | pr.WriteHeader(StatusOK) | ||
1200 | 117 | } | ||
1201 | 118 | pr.hasContent = true | ||
1202 | 119 | if !pr.sentResponse { | ||
1203 | 120 | pr.sendResponse() | ||
1204 | 121 | } | ||
1205 | 122 | return pr.pw.Write(p) | ||
1206 | 123 | } | ||
1207 | 0 | 124 | ||
1208 | === added file 'fork/http/fs.go' | |||
1209 | --- fork/http/fs.go 1970-01-01 00:00:00 +0000 | |||
1210 | +++ fork/http/fs.go 2013-07-22 14:27:42 +0000 | |||
1211 | @@ -0,0 +1,367 @@ | |||
1212 | 1 | // Copyright 2009 The Go Authors. All rights reserved. | ||
1213 | 2 | // Use of this source code is governed by a BSD-style | ||
1214 | 3 | // license that can be found in the LICENSE file. | ||
1215 | 4 | |||
1216 | 5 | // HTTP file system request handler | ||
1217 | 6 | |||
1218 | 7 | package http | ||
1219 | 8 | |||
1220 | 9 | import ( | ||
1221 | 10 | "errors" | ||
1222 | 11 | "fmt" | ||
1223 | 12 | "io" | ||
1224 | 13 | "mime" | ||
1225 | 14 | "os" | ||
1226 | 15 | "path" | ||
1227 | 16 | "path/filepath" | ||
1228 | 17 | "strconv" | ||
1229 | 18 | "strings" | ||
1230 | 19 | "time" | ||
1231 | 20 | ) | ||
1232 | 21 | |||
1233 | 22 | // A Dir implements http.FileSystem using the native file | ||
1234 | 23 | // system restricted to a specific directory tree. | ||
1235 | 24 | // | ||
1236 | 25 | // An empty Dir is treated as ".". | ||
1237 | 26 | type Dir string | ||
1238 | 27 | |||
1239 | 28 | func (d Dir) Open(name string) (File, error) { | ||
1240 | 29 | if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 { | ||
1241 | 30 | return nil, errors.New("http: invalid character in file path") | ||
1242 | 31 | } | ||
1243 | 32 | dir := string(d) | ||
1244 | 33 | if dir == "" { | ||
1245 | 34 | dir = "." | ||
1246 | 35 | } | ||
1247 | 36 | f, err := os.Open(filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))) | ||
1248 | 37 | if err != nil { | ||
1249 | 38 | return nil, err | ||
1250 | 39 | } | ||
1251 | 40 | return f, nil | ||
1252 | 41 | } | ||
1253 | 42 | |||
1254 | 43 | // A FileSystem implements access to a collection of named files. | ||
1255 | 44 | // The elements in a file path are separated by slash ('/', U+002F) | ||
1256 | 45 | // characters, regardless of host operating system convention. | ||
1257 | 46 | type FileSystem interface { | ||
1258 | 47 | Open(name string) (File, error) | ||
1259 | 48 | } | ||
1260 | 49 | |||
1261 | 50 | // A File is returned by a FileSystem's Open method and can be | ||
1262 | 51 | // served by the FileServer implementation. | ||
1263 | 52 | type File interface { | ||
1264 | 53 | Close() error | ||
1265 | 54 | Stat() (os.FileInfo, error) | ||
1266 | 55 | Readdir(count int) ([]os.FileInfo, error) | ||
1267 | 56 | Read([]byte) (int, error) | ||
1268 | 57 | Seek(offset int64, whence int) (int64, error) | ||
1269 | 58 | } | ||
1270 | 59 | |||
1271 | 60 | func dirList(w ResponseWriter, f File) { | ||
1272 | 61 | w.Header().Set("Content-Type", "text/html; charset=utf-8") | ||
1273 | 62 | fmt.Fprintf(w, "<pre>\n") | ||
1274 | 63 | for { | ||
1275 | 64 | dirs, err := f.Readdir(100) | ||
1276 | 65 | if err != nil || len(dirs) == 0 { | ||
1277 | 66 | break | ||
1278 | 67 | } | ||
1279 | 68 | for _, d := range dirs { | ||
1280 | 69 | name := d.Name() | ||
1281 | 70 | if d.IsDir() { | ||
1282 | 71 | name += "/" | ||
1283 | 72 | } | ||
1284 | 73 | // TODO htmlescape | ||
1285 | 74 | fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", name, name) | ||
1286 | 75 | } | ||
1287 | 76 | } | ||
1288 | 77 | fmt.Fprintf(w, "</pre>\n") | ||
1289 | 78 | } | ||
1290 | 79 | |||
1291 | 80 | // ServeContent replies to the request using the content in the | ||
1292 | 81 | // provided ReadSeeker. The main benefit of ServeContent over io.Copy | ||
1293 | 82 | // is that it handles Range requests properly, sets the MIME type, and | ||
1294 | 83 | // handles If-Modified-Since requests. | ||
1295 | 84 | // | ||
1296 | 85 | // If the response's Content-Type header is not set, ServeContent | ||
1297 | 86 | // first tries to deduce the type from name's file extension and, | ||
1298 | 87 | // if that fails, falls back to reading the first block of the content | ||
1299 | 88 | // and passing it to DetectContentType. | ||
1300 | 89 | // The name is otherwise unused; in particular it can be empty and is | ||
1301 | 90 | // never sent in the response. | ||
1302 | 91 | // | ||
1303 | 92 | // If modtime is not the zero time, ServeContent includes it in a | ||
1304 | 93 | // Last-Modified header in the response. If the request includes an | ||
1305 | 94 | // If-Modified-Since header, ServeContent uses modtime to decide | ||
1306 | 95 | // whether the content needs to be sent at all. | ||
1307 | 96 | // | ||
1308 | 97 | // The content's Seek method must work: ServeContent uses | ||
1309 | 98 | // a seek to the end of the content to determine its size. | ||
1310 | 99 | // | ||
1311 | 100 | // Note that *os.File implements the io.ReadSeeker interface. | ||
1312 | 101 | func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker) { | ||
1313 | 102 | size, err := content.Seek(0, os.SEEK_END) | ||
1314 | 103 | if err != nil { | ||
1315 | 104 | Error(w, "seeker can't seek", StatusInternalServerError) | ||
1316 | 105 | return | ||
1317 | 106 | } | ||
1318 | 107 | _, err = content.Seek(0, os.SEEK_SET) | ||
1319 | 108 | if err != nil { | ||
1320 | 109 | Error(w, "seeker can't seek", StatusInternalServerError) | ||
1321 | 110 | return | ||
1322 | 111 | } | ||
1323 | 112 | serveContent(w, req, name, modtime, size, content) | ||
1324 | 113 | } | ||
1325 | 114 | |||
1326 | 115 | // if name is empty, filename is unknown. (used for mime type, before sniffing) | ||
1327 | 116 | // if modtime.IsZero(), modtime is unknown. | ||
1328 | 117 | // content must be seeked to the beginning of the file. | ||
1329 | 118 | func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, size int64, content io.ReadSeeker) { | ||
1330 | 119 | if checkLastModified(w, r, modtime) { | ||
1331 | 120 | return | ||
1332 | 121 | } | ||
1333 | 122 | |||
1334 | 123 | code := StatusOK | ||
1335 | 124 | |||
1336 | 125 | // If Content-Type isn't set, use the file's extension to find it. | ||
1337 | 126 | if w.Header().Get("Content-Type") == "" { | ||
1338 | 127 | ctype := mime.TypeByExtension(filepath.Ext(name)) | ||
1339 | 128 | if ctype == "" { | ||
1340 | 129 | // read a chunk to decide between utf-8 text and binary | ||
1341 | 130 | var buf [1024]byte | ||
1342 | 131 | n, _ := io.ReadFull(content, buf[:]) | ||
1343 | 132 | b := buf[:n] | ||
1344 | 133 | ctype = DetectContentType(b) | ||
1345 | 134 | _, err := content.Seek(0, os.SEEK_SET) // rewind to output whole file | ||
1346 | 135 | if err != nil { | ||
1347 | 136 | Error(w, "seeker can't seek", StatusInternalServerError) | ||
1348 | 137 | return | ||
1349 | 138 | } | ||
1350 | 139 | } | ||
1351 | 140 | w.Header().Set("Content-Type", ctype) | ||
1352 | 141 | } | ||
1353 | 142 | |||
1354 | 143 | // handle Content-Range header. | ||
1355 | 144 | // TODO(adg): handle multiple ranges | ||
1356 | 145 | sendSize := size | ||
1357 | 146 | if size >= 0 { | ||
1358 | 147 | ranges, err := parseRange(r.Header.Get("Range"), size) | ||
1359 | 148 | if err == nil && len(ranges) > 1 { | ||
1360 | 149 | err = errors.New("multiple ranges not supported") | ||
1361 | 150 | } | ||
1362 | 151 | if err != nil { | ||
1363 | 152 | Error(w, err.Error(), StatusRequestedRangeNotSatisfiable) | ||
1364 | 153 | return | ||
1365 | 154 | } | ||
1366 | 155 | if len(ranges) == 1 { | ||
1367 | 156 | ra := ranges[0] | ||
1368 | 157 | if _, err := content.Seek(ra.start, os.SEEK_SET); err != nil { | ||
1369 | 158 | Error(w, err.Error(), StatusRequestedRangeNotSatisfiable) | ||
1370 | 159 | return | ||
1371 | 160 | } | ||
1372 | 161 | sendSize = ra.length | ||
1373 | 162 | code = StatusPartialContent | ||
1374 | 163 | w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ra.start, ra.start+ra.length-1, size)) | ||
1375 | 164 | } | ||
1376 | 165 | |||
1377 | 166 | w.Header().Set("Accept-Ranges", "bytes") | ||
1378 | 167 | if w.Header().Get("Content-Encoding") == "" { | ||
1379 | 168 | w.Header().Set("Content-Length", strconv.FormatInt(sendSize, 10)) | ||
1380 | 169 | } | ||
1381 | 170 | } | ||
1382 | 171 | |||
1383 | 172 | w.WriteHeader(code) | ||
1384 | 173 | |||
1385 | 174 | if r.Method != "HEAD" { | ||
1386 | 175 | if sendSize == -1 { | ||
1387 | 176 | io.Copy(w, content) | ||
1388 | 177 | } else { | ||
1389 | 178 | io.CopyN(w, content, sendSize) | ||
1390 | 179 | } | ||
1391 | 180 | } | ||
1392 | 181 | } | ||
1393 | 182 | |||
1394 | 183 | // modtime is the modification time of the resource to be served, or IsZero(). | ||
1395 | 184 | // return value is whether this request is now complete. | ||
1396 | 185 | func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool { | ||
1397 | 186 | if modtime.IsZero() { | ||
1398 | 187 | return false | ||
1399 | 188 | } | ||
1400 | 189 | |||
1401 | 190 | // The Date-Modified header truncates sub-second precision, so | ||
1402 | 191 | // use mtime < t+1s instead of mtime <= t to check for unmodified. | ||
1403 | 192 | if t, err := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && modtime.Before(t.Add(1*time.Second)) { | ||
1404 | 193 | w.WriteHeader(StatusNotModified) | ||
1405 | 194 | return true | ||
1406 | 195 | } | ||
1407 | 196 | w.Header().Set("Last-Modified", modtime.UTC().Format(TimeFormat)) | ||
1408 | 197 | return false | ||
1409 | 198 | } | ||
1410 | 199 | |||
1411 | 200 | // name is '/'-separated, not filepath.Separator. | ||
1412 | 201 | func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) { | ||
1413 | 202 | const indexPage = "/index.html" | ||
1414 | 203 | |||
1415 | 204 | // redirect .../index.html to .../ | ||
1416 | 205 | // can't use Redirect() because that would make the path absolute, | ||
1417 | 206 | // which would be a problem running under StripPrefix | ||
1418 | 207 | if strings.HasSuffix(r.URL.Path, indexPage) { | ||
1419 | 208 | localRedirect(w, r, "./") | ||
1420 | 209 | return | ||
1421 | 210 | } | ||
1422 | 211 | |||
1423 | 212 | f, err := fs.Open(name) | ||
1424 | 213 | if err != nil { | ||
1425 | 214 | // TODO expose actual error? | ||
1426 | 215 | NotFound(w, r) | ||
1427 | 216 | return | ||
1428 | 217 | } | ||
1429 | 218 | defer f.Close() | ||
1430 | 219 | |||
1431 | 220 | d, err1 := f.Stat() | ||
1432 | 221 | if err1 != nil { | ||
1433 | 222 | // TODO expose actual error? | ||
1434 | 223 | NotFound(w, r) | ||
1435 | 224 | return | ||
1436 | 225 | } | ||
1437 | 226 | |||
1438 | 227 | if redirect { | ||
1439 | 228 | // redirect to canonical path: / at end of directory url | ||
1440 | 229 | // r.URL.Path always begins with / | ||
1441 | 230 | url := r.URL.Path | ||
1442 | 231 | if d.IsDir() { | ||
1443 | 232 | if url[len(url)-1] != '/' { | ||
1444 | 233 | localRedirect(w, r, path.Base(url)+"/") | ||
1445 | 234 | return | ||
1446 | 235 | } | ||
1447 | 236 | } else { | ||
1448 | 237 | if url[len(url)-1] == '/' { | ||
1449 | 238 | localRedirect(w, r, "../"+path.Base(url)) | ||
1450 | 239 | return | ||
1451 | 240 | } | ||
1452 | 241 | } | ||
1453 | 242 | } | ||
1454 | 243 | |||
1455 | 244 | // use contents of index.html for directory, if present | ||
1456 | 245 | if d.IsDir() { | ||
1457 | 246 | if checkLastModified(w, r, d.ModTime()) { | ||
1458 | 247 | return | ||
1459 | 248 | } | ||
1460 | 249 | index := name + indexPage | ||
1461 | 250 | ff, err := fs.Open(index) | ||
1462 | 251 | if err == nil { | ||
1463 | 252 | defer ff.Close() | ||
1464 | 253 | dd, err := ff.Stat() | ||
1465 | 254 | if err == nil { | ||
1466 | 255 | name = index | ||
1467 | 256 | d = dd | ||
1468 | 257 | f = ff | ||
1469 | 258 | } | ||
1470 | 259 | } | ||
1471 | 260 | } | ||
1472 | 261 | |||
1473 | 262 | if d.IsDir() { | ||
1474 | 263 | dirList(w, f) | ||
1475 | 264 | return | ||
1476 | 265 | } | ||
1477 | 266 | |||
1478 | 267 | serveContent(w, r, d.Name(), d.ModTime(), d.Size(), f) | ||
1479 | 268 | } | ||
1480 | 269 | |||
1481 | 270 | // localRedirect gives a Moved Permanently response. | ||
1482 | 271 | // It does not convert relative paths to absolute paths like Redirect does. | ||
1483 | 272 | func localRedirect(w ResponseWriter, r *Request, newPath string) { | ||
1484 | 273 | if q := r.URL.RawQuery; q != "" { | ||
1485 | 274 | newPath += "?" + q | ||
1486 | 275 | } | ||
1487 | 276 | w.Header().Set("Location", newPath) | ||
1488 | 277 | w.WriteHeader(StatusMovedPermanently) | ||
1489 | 278 | } | ||
1490 | 279 | |||
1491 | 280 | // ServeFile replies to the request with the contents of the named file or directory. | ||
1492 | 281 | func ServeFile(w ResponseWriter, r *Request, name string) { | ||
1493 | 282 | dir, file := filepath.Split(name) | ||
1494 | 283 | serveFile(w, r, Dir(dir), file, false) | ||
1495 | 284 | } | ||
1496 | 285 | |||
1497 | 286 | type fileHandler struct { | ||
1498 | 287 | root FileSystem | ||
1499 | 288 | } | ||
1500 | 289 | |||
1501 | 290 | // FileServer returns a handler that serves HTTP requests | ||
1502 | 291 | // with the contents of the file system rooted at root. | ||
1503 | 292 | // | ||
1504 | 293 | // To use the operating system's file system implementation, | ||
1505 | 294 | // use http.Dir: | ||
1506 | 295 | // | ||
1507 | 296 | // http.Handle("/", http.FileServer(http.Dir("/tmp"))) | ||
1508 | 297 | func FileServer(root FileSystem) Handler { | ||
1509 | 298 | return &fileHandler{root} | ||
1510 | 299 | } | ||
1511 | 300 | |||
1512 | 301 | func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) { | ||
1513 | 302 | upath := r.URL.Path | ||
1514 | 303 | if !strings.HasPrefix(upath, "/") { | ||
1515 | 304 | upath = "/" + upath | ||
1516 | 305 | r.URL.Path = upath | ||
1517 | 306 | } | ||
1518 | 307 | serveFile(w, r, f.root, path.Clean(upath), true) | ||
1519 | 308 | } | ||
1520 | 309 | |||
1521 | 310 | // httpRange specifies the byte range to be sent to the client. | ||
1522 | 311 | type httpRange struct { | ||
1523 | 312 | start, length int64 | ||
1524 | 313 | } | ||
1525 | 314 | |||
1526 | 315 | // parseRange parses a Range header string as per RFC 2616. | ||
1527 | 316 | func parseRange(s string, size int64) ([]httpRange, error) { | ||
1528 | 317 | if s == "" { | ||
1529 | 318 | return nil, nil // header not present | ||
1530 | 319 | } | ||
1531 | 320 | const b = "bytes=" | ||
1532 | 321 | if !strings.HasPrefix(s, b) { | ||
1533 | 322 | return nil, errors.New("invalid range") | ||
1534 | 323 | } | ||
1535 | 324 | var ranges []httpRange | ||
1536 | 325 | for _, ra := range strings.Split(s[len(b):], ",") { | ||
1537 | 326 | i := strings.Index(ra, "-") | ||
1538 | 327 | if i < 0 { | ||
1539 | 328 | return nil, errors.New("invalid range") | ||
1540 | 329 | } | ||
1541 | 330 | start, end := ra[:i], ra[i+1:] | ||
1542 | 331 | var r httpRange | ||
1543 | 332 | if start == "" { | ||
1544 | 333 | // If no start is specified, end specifies the | ||
1545 | 334 | // range start relative to the end of the file. | ||
1546 | 335 | i, err := strconv.ParseInt(end, 10, 64) | ||
1547 | 336 | if err != nil { | ||
1548 | 337 | return nil, errors.New("invalid range") | ||
1549 | 338 | } | ||
1550 | 339 | if i > size { | ||
1551 | 340 | i = size | ||
1552 | 341 | } | ||
1553 | 342 | r.start = size - i | ||
1554 | 343 | r.length = size - r.start | ||
1555 | 344 | } else { | ||
1556 | 345 | i, err := strconv.ParseInt(start, 10, 64) | ||
1557 | 346 | if err != nil || i > size || i < 0 { | ||
1558 | 347 | return nil, errors.New("invalid range") | ||
1559 | 348 | } | ||
1560 | 349 | r.start = i | ||
1561 | 350 | if end == "" { | ||
1562 | 351 | // If no end is specified, range extends to end of the file. | ||
1563 | 352 | r.length = size - r.start | ||
1564 | 353 | } else { | ||
1565 | 354 | i, err := strconv.ParseInt(end, 10, 64) | ||
1566 | 355 | if err != nil || r.start > i { | ||
1567 | 356 | return nil, errors.New("invalid range") | ||
1568 | 357 | } | ||
1569 | 358 | if i >= size { | ||
1570 | 359 | i = size - 1 | ||
1571 | 360 | } | ||
1572 | 361 | r.length = i - r.start + 1 | ||
1573 | 362 | } | ||
1574 | 363 | } | ||
1575 | 364 | ranges = append(ranges, r) | ||
1576 | 365 | } | ||
1577 | 366 | return ranges, nil | ||
1578 | 367 | } | ||
1579 | 0 | 368 | ||
1580 | === added file 'fork/http/header.go' | |||
1581 | --- fork/http/header.go 1970-01-01 00:00:00 +0000 | |||
1582 | +++ fork/http/header.go 2013-07-22 14:27:42 +0000 | |||
1583 | @@ -0,0 +1,78 @@ | |||
1584 | 1 | // Copyright 2010 The Go Authors. All rights reserved. | ||
1585 | 2 | // Use of this source code is governed by a BSD-style | ||
1586 | 3 | // license that can be found in the LICENSE file. | ||
1587 | 4 | |||
1588 | 5 | package http | ||
1589 | 6 | |||
1590 | 7 | import ( | ||
1591 | 8 | "fmt" | ||
1592 | 9 | "io" | ||
1593 | 10 | "net/textproto" | ||
1594 | 11 | "sort" | ||
1595 | 12 | "strings" | ||
1596 | 13 | ) | ||
1597 | 14 | |||
1598 | 15 | // A Header represents the key-value pairs in an HTTP header. | ||
1599 | 16 | type Header map[string][]string | ||
1600 | 17 | |||
1601 | 18 | // Add adds the key, value pair to the header. | ||
1602 | 19 | // It appends to any existing values associated with key. | ||
1603 | 20 | func (h Header) Add(key, value string) { | ||
1604 | 21 | textproto.MIMEHeader(h).Add(key, value) | ||
1605 | 22 | } | ||
1606 | 23 | |||
1607 | 24 | // Set sets the header entries associated with key to | ||
1608 | 25 | // the single element value. It replaces any existing | ||
1609 | 26 | // values associated with key. | ||
1610 | 27 | func (h Header) Set(key, value string) { | ||
1611 | 28 | textproto.MIMEHeader(h).Set(key, value) | ||
1612 | 29 | } | ||
1613 | 30 | |||
1614 | 31 | // Get gets the first value associated with the given key. | ||
1615 | 32 | // If there are no values associated with the key, Get returns "". | ||
1616 | 33 | // To access multiple values of a key, access the map directly | ||
1617 | 34 | // with CanonicalHeaderKey. | ||
1618 | 35 | func (h Header) Get(key string) string { | ||
1619 | 36 | return textproto.MIMEHeader(h).Get(key) | ||
1620 | 37 | } | ||
1621 | 38 | |||
1622 | 39 | // Del deletes the values associated with key. | ||
1623 | 40 | func (h Header) Del(key string) { | ||
1624 | 41 | textproto.MIMEHeader(h).Del(key) | ||
1625 | 42 | } | ||
1626 | 43 | |||
1627 | 44 | // Write writes a header in wire format. | ||
1628 | 45 | func (h Header) Write(w io.Writer) error { | ||
1629 | 46 | return h.WriteSubset(w, nil) | ||
1630 | 47 | } | ||
1631 | 48 | |||
1632 | 49 | var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ") | ||
1633 | 50 | |||
1634 | 51 | // WriteSubset writes a header in wire format. | ||
1635 | 52 | // If exclude is not nil, keys where exclude[key] == true are not written. | ||
1636 | 53 | func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error { | ||
1637 | 54 | keys := make([]string, 0, len(h)) | ||
1638 | 55 | for k := range h { | ||
1639 | 56 | if exclude == nil || !exclude[k] { | ||
1640 | 57 | keys = append(keys, k) | ||
1641 | 58 | } | ||
1642 | 59 | } | ||
1643 | 60 | sort.Strings(keys) | ||
1644 | 61 | for _, k := range keys { | ||
1645 | 62 | for _, v := range h[k] { | ||
1646 | 63 | v = headerNewlineToSpace.Replace(v) | ||
1647 | 64 | v = strings.TrimSpace(v) | ||
1648 | 65 | if _, err := fmt.Fprintf(w, "%s: %s\r\n", k, v); err != nil { | ||
1649 | 66 | return err | ||
1650 | 67 | } | ||
1651 | 68 | } | ||
1652 | 69 | } | ||
1653 | 70 | return nil | ||
1654 | 71 | } | ||
1655 | 72 | |||
1656 | 73 | // CanonicalHeaderKey returns the canonical format of the | ||
1657 | 74 | // header key s. The canonicalization converts the first | ||
1658 | 75 | // letter and any letter following a hyphen to upper case; | ||
1659 | 76 | // the rest are converted to lowercase. For example, the | ||
1660 | 77 | // canonical key for "accept-encoding" is "Accept-Encoding". | ||
1661 | 78 | func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) } | ||
1662 | 0 | 79 | ||
1663 | === added file 'fork/http/jar.go' | |||
1664 | --- fork/http/jar.go 1970-01-01 00:00:00 +0000 | |||
1665 | +++ fork/http/jar.go 2013-07-22 14:27:42 +0000 | |||
1666 | @@ -0,0 +1,30 @@ | |||
1667 | 1 | // Copyright 2011 The Go Authors. All rights reserved. | ||
1668 | 2 | // Use of this source code is governed by a BSD-style | ||
1669 | 3 | // license that can be found in the LICENSE file. | ||
1670 | 4 | |||
1671 | 5 | package http | ||
1672 | 6 | |||
1673 | 7 | import ( | ||
1674 | 8 | "net/url" | ||
1675 | 9 | ) | ||
1676 | 10 | |||
1677 | 11 | // A CookieJar manages storage and use of cookies in HTTP requests. | ||
1678 | 12 | // | ||
1679 | 13 | // Implementations of CookieJar must be safe for concurrent use by multiple | ||
1680 | 14 | // goroutines. | ||
1681 | 15 | type CookieJar interface { | ||
1682 | 16 | // SetCookies handles the receipt of the cookies in a reply for the | ||
1683 | 17 | // given URL. It may or may not choose to save the cookies, depending | ||
1684 | 18 | // on the jar's policy and implementation. | ||
1685 | 19 | SetCookies(u *url.URL, cookies []*Cookie) | ||
1686 | 20 | |||
1687 | 21 | // Cookies returns the cookies to send in a request for the given URL. | ||
1688 | 22 | // It is up to the implementation to honor the standard cookie use | ||
1689 | 23 | // restrictions such as in RFC 6265. | ||
1690 | 24 | Cookies(u *url.URL) []*Cookie | ||
1691 | 25 | } | ||
1692 | 26 | |||
1693 | 27 | type blackHoleJar struct{} | ||
1694 | 28 | |||
1695 | 29 | func (blackHoleJar) SetCookies(u *url.URL, cookies []*Cookie) {} | ||
1696 | 30 | func (blackHoleJar) Cookies(u *url.URL) []*Cookie { return nil } | ||
1697 | 0 | 31 | ||
1698 | === added file 'fork/http/lex.go' | |||
1699 | --- fork/http/lex.go 1970-01-01 00:00:00 +0000 | |||
1700 | +++ fork/http/lex.go 2013-07-22 14:27:42 +0000 | |||
1701 | @@ -0,0 +1,136 @@ | |||
1702 | 1 | // Copyright 2009 The Go Authors. All rights reserved. | ||
1703 | 2 | // Use of this source code is governed by a BSD-style | ||
1704 | 3 | // license that can be found in the LICENSE file. | ||
1705 | 4 | |||
1706 | 5 | package http | ||
1707 | 6 | |||
1708 | 7 | // This file deals with lexical matters of HTTP | ||
1709 | 8 | |||
1710 | 9 | func isSeparator(c byte) bool { | ||
1711 | 10 | switch c { | ||
1712 | 11 | case '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t': | ||
1713 | 12 | return true | ||
1714 | 13 | } | ||
1715 | 14 | return false | ||
1716 | 15 | } | ||
1717 | 16 | |||
1718 | 17 | func isCtl(c byte) bool { return (0 <= c && c <= 31) || c == 127 } | ||
1719 | 18 | |||
1720 | 19 | func isChar(c byte) bool { return 0 <= c && c <= 127 } | ||
1721 | 20 | |||
1722 | 21 | func isAnyText(c byte) bool { return !isCtl(c) } | ||
1723 | 22 | |||
1724 | 23 | func isQdText(c byte) bool { return isAnyText(c) && c != '"' } | ||
1725 | 24 | |||
1726 | 25 | func isToken(c byte) bool { return isChar(c) && !isCtl(c) && !isSeparator(c) } | ||
1727 | 26 | |||
1728 | 27 | // Valid escaped sequences are not specified in RFC 2616, so for now, we assume | ||
1729 | 28 | // that they coincide with the common sense ones used by GO. Malformed | ||
1730 | 29 | // characters should probably not be treated as errors by a robust (forgiving) | ||
1731 | 30 | // parser, so we replace them with the '?' character. | ||
1732 | 31 | func httpUnquotePair(b byte) byte { | ||
1733 | 32 | // skip the first byte, which should always be '\' | ||
1734 | 33 | switch b { | ||
1735 | 34 | case 'a': | ||
1736 | 35 | return '\a' | ||
1737 | 36 | case 'b': | ||
1738 | 37 | return '\b' | ||
1739 | 38 | case 'f': | ||
1740 | 39 | return '\f' | ||
1741 | 40 | case 'n': | ||
1742 | 41 | return '\n' | ||
1743 | 42 | case 'r': | ||
1744 | 43 | return '\r' | ||
1745 | 44 | case 't': | ||
1746 | 45 | return '\t' | ||
1747 | 46 | case 'v': | ||
1748 | 47 | return '\v' | ||
1749 | 48 | case '\\': | ||
1750 | 49 | return '\\' | ||
1751 | 50 | case '\'': | ||
1752 | 51 | return '\'' | ||
1753 | 52 | case '"': | ||
1754 | 53 | return '"' | ||
1755 | 54 | } | ||
1756 | 55 | return '?' | ||
1757 | 56 | } | ||
1758 | 57 | |||
1759 | 58 | // raw must begin with a valid quoted string. Only the first quoted string is | ||
1760 | 59 | // parsed and is unquoted in result. eaten is the number of bytes parsed, or -1 | ||
1761 | 60 | // upon failure. | ||
1762 | 61 | func httpUnquote(raw []byte) (eaten int, result string) { | ||
1763 | 62 | buf := make([]byte, len(raw)) | ||
1764 | 63 | if raw[0] != '"' { | ||
1765 | 64 | return -1, "" | ||
1766 | 65 | } | ||
1767 | 66 | eaten = 1 | ||
1768 | 67 | j := 0 // # of bytes written in buf | ||
1769 | 68 | for i := 1; i < len(raw); i++ { | ||
1770 | 69 | switch b := raw[i]; b { | ||
1771 | 70 | case '"': | ||
1772 | 71 | eaten++ | ||
1773 | 72 | buf = buf[0:j] | ||
1774 | 73 | return i + 1, string(buf) | ||
1775 | 74 | case '\\': | ||
1776 | 75 | if len(raw) < i+2 { | ||
1777 | 76 | return -1, "" | ||
1778 | 77 | } | ||
1779 | 78 | buf[j] = httpUnquotePair(raw[i+1]) | ||
1780 | 79 | eaten += 2 | ||
1781 | 80 | j++ | ||
1782 | 81 | i++ | ||
1783 | 82 | default: | ||
1784 | 83 | if isQdText(b) { | ||
1785 | 84 | buf[j] = b | ||
1786 | 85 | } else { | ||
1787 | 86 | buf[j] = '?' | ||
1788 | 87 | } | ||
1789 | 88 | eaten++ | ||
1790 | 89 | j++ | ||
1791 | 90 | } | ||
1792 | 91 | } | ||
1793 | 92 | return -1, "" | ||
1794 | 93 | } | ||
1795 | 94 | |||
1796 | 95 | // This is a best effort parse, so errors are not returned, instead not all of | ||
1797 | 96 | // the input string might be parsed. result is always non-nil. | ||
1798 | 97 | func httpSplitFieldValue(fv string) (eaten int, result []string) { | ||
1799 | 98 | result = make([]string, 0, len(fv)) | ||
1800 | 99 | raw := []byte(fv) | ||
1801 | 100 | i := 0 | ||
1802 | 101 | chunk := "" | ||
1803 | 102 | for i < len(raw) { | ||
1804 | 103 | b := raw[i] | ||
1805 | 104 | switch { | ||
1806 | 105 | case b == '"': | ||
1807 | 106 | eaten, unq := httpUnquote(raw[i:]) | ||
1808 | 107 | if eaten < 0 { | ||
1809 | 108 | return i, result | ||
1810 | 109 | } else { | ||
1811 | 110 | i += eaten | ||
1812 | 111 | chunk += unq | ||
1813 | 112 | } | ||
1814 | 113 | case isSeparator(b): | ||
1815 | 114 | if chunk != "" { | ||
1816 | 115 | result = result[0 : len(result)+1] | ||
1817 | 116 | result[len(result)-1] = chunk | ||
1818 | 117 | chunk = "" | ||
1819 | 118 | } | ||
1820 | 119 | i++ | ||
1821 | 120 | case isToken(b): | ||
1822 | 121 | chunk += string(b) | ||
1823 | 122 | i++ | ||
1824 | 123 | case b == '\n' || b == '\r': | ||
1825 | 124 | i++ | ||
1826 | 125 | default: | ||
1827 | 126 | chunk += "?" | ||
1828 | 127 | i++ | ||
1829 | 128 | } | ||
1830 | 129 | } | ||
1831 | 130 | if chunk != "" { | ||
1832 | 131 | result = result[0 : len(result)+1] | ||
1833 | 132 | result[len(result)-1] = chunk | ||
1834 | 133 | chunk = "" | ||
1835 | 134 | } | ||
1836 | 135 | return i, result | ||
1837 | 136 | } | ||
1838 | 0 | 137 | ||
1839 | === added file 'fork/http/request.go' | |||
1840 | --- fork/http/request.go 1970-01-01 00:00:00 +0000 | |||
1841 | +++ fork/http/request.go 2013-07-22 14:27:42 +0000 | |||
1842 | @@ -0,0 +1,743 @@ | |||
1843 | 1 | // Copyright 2009 The Go Authors. All rights reserved. | ||
1844 | 2 | // Use of this source code is governed by a BSD-style | ||
1845 | 3 | // license that can be found in the LICENSE file. | ||
1846 | 4 | |||
1847 | 5 | // HTTP Request reading and parsing. | ||
1848 | 6 | |||
1849 | 7 | package http | ||
1850 | 8 | |||
1851 | 9 | import ( | ||
1852 | 10 | "bufio" | ||
1853 | 11 | "bytes" | ||
1854 | 12 | "crypto/tls" | ||
1855 | 13 | "encoding/base64" | ||
1856 | 14 | "errors" | ||
1857 | 15 | "fmt" | ||
1858 | 16 | "io" | ||
1859 | 17 | "io/ioutil" | ||
1860 | 18 | "mime" | ||
1861 | 19 | "mime/multipart" | ||
1862 | 20 | "net/textproto" | ||
1863 | 21 | "net/url" | ||
1864 | 22 | "strings" | ||
1865 | 23 | ) | ||
1866 | 24 | |||
1867 | 25 | const ( | ||
1868 | 26 | maxValueLength = 4096 | ||
1869 | 27 | maxHeaderLines = 1024 | ||
1870 | 28 | chunkSize = 4 << 10 // 4 KB chunks | ||
1871 | 29 | defaultMaxMemory = 32 << 20 // 32 MB | ||
1872 | 30 | ) | ||
1873 | 31 | |||
1874 | 32 | // ErrMissingFile is returned by FormFile when the provided file field name | ||
1875 | 33 | // is either not present in the request or not a file field. | ||
1876 | 34 | var ErrMissingFile = errors.New("http: no such file") | ||
1877 | 35 | |||
1878 | 36 | // HTTP request parsing errors. | ||
1879 | 37 | type ProtocolError struct { | ||
1880 | 38 | ErrorString string | ||
1881 | 39 | } | ||
1882 | 40 | |||
1883 | 41 | func (err *ProtocolError) Error() string { return err.ErrorString } | ||
1884 | 42 | |||
1885 | 43 | var ( | ||
1886 | 44 | ErrHeaderTooLong = &ProtocolError{"header too long"} | ||
1887 | 45 | ErrShortBody = &ProtocolError{"entity body too short"} | ||
1888 | 46 | ErrNotSupported = &ProtocolError{"feature not supported"} | ||
1889 | 47 | ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"} | ||
1890 | 48 | ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"} | ||
1891 | 49 | ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"} | ||
1892 | 50 | ErrMissingBoundary = &ProtocolError{"no multipart boundary param Content-Type"} | ||
1893 | 51 | ) | ||
1894 | 52 | |||
1895 | 53 | type badStringError struct { | ||
1896 | 54 | what string | ||
1897 | 55 | str string | ||
1898 | 56 | } | ||
1899 | 57 | |||
1900 | 58 | func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) } | ||
1901 | 59 | |||
1902 | 60 | // Headers that Request.Write handles itself and should be skipped. | ||
1903 | 61 | var reqWriteExcludeHeader = map[string]bool{ | ||
1904 | 62 | "Host": true, // not in Header map anyway | ||
1905 | 63 | "User-Agent": true, | ||
1906 | 64 | "Content-Length": true, | ||
1907 | 65 | "Transfer-Encoding": true, | ||
1908 | 66 | "Trailer": true, | ||
1909 | 67 | } | ||
1910 | 68 | |||
1911 | 69 | // A Request represents an HTTP request received by a server | ||
1912 | 70 | // or to be sent by a client. | ||
1913 | 71 | type Request struct { | ||
1914 | 72 | Method string // GET, POST, PUT, etc. | ||
1915 | 73 | URL *url.URL | ||
1916 | 74 | |||
1917 | 75 | // The protocol version for incoming requests. | ||
1918 | 76 | // Outgoing requests always use HTTP/1.1. | ||
1919 | 77 | Proto string // "HTTP/1.0" | ||
1920 | 78 | ProtoMajor int // 1 | ||
1921 | 79 | ProtoMinor int // 0 | ||
1922 | 80 | |||
1923 | 81 | // A header maps request lines to their values. | ||
1924 | 82 | // If the header says | ||
1925 | 83 | // | ||
1926 | 84 | // accept-encoding: gzip, deflate | ||
1927 | 85 | // Accept-Language: en-us | ||
1928 | 86 | // Connection: keep-alive | ||
1929 | 87 | // | ||
1930 | 88 | // then | ||
1931 | 89 | // | ||
1932 | 90 | // Header = map[string][]string{ | ||
1933 | 91 | // "Accept-Encoding": {"gzip, deflate"}, | ||
1934 | 92 | // "Accept-Language": {"en-us"}, | ||
1935 | 93 | // "Connection": {"keep-alive"}, | ||
1936 | 94 | // } | ||
1937 | 95 | // | ||
1938 | 96 | // HTTP defines that header names are case-insensitive. | ||
1939 | 97 | // The request parser implements this by canonicalizing the | ||
1940 | 98 | // name, making the first character and any characters | ||
1941 | 99 | // following a hyphen uppercase and the rest lowercase. | ||
1942 | 100 | Header Header | ||
1943 | 101 | |||
1944 | 102 | // The message body. | ||
1945 | 103 | Body io.ReadCloser | ||
1946 | 104 | |||
1947 | 105 | // ContentLength records the length of the associated content. | ||
1948 | 106 | // The value -1 indicates that the length is unknown. | ||
1949 | 107 | // Values >= 0 indicate that the given number of bytes may | ||
1950 | 108 | // be read from Body. | ||
1951 | 109 | // For outgoing requests, a value of 0 means unknown if Body is not nil. | ||
1952 | 110 | ContentLength int64 | ||
1953 | 111 | |||
1954 | 112 | // TransferEncoding lists the transfer encodings from outermost to | ||
1955 | 113 | // innermost. An empty list denotes the "identity" encoding. | ||
1956 | 114 | // TransferEncoding can usually be ignored; chunked encoding is | ||
1957 | 115 | // automatically added and removed as necessary when sending and | ||
1958 | 116 | // receiving requests. | ||
1959 | 117 | TransferEncoding []string | ||
1960 | 118 | |||
1961 | 119 | // Close indicates whether to close the connection after | ||
1962 | 120 | // replying to this request. | ||
1963 | 121 | Close bool | ||
1964 | 122 | |||
1965 | 123 | // The host on which the URL is sought. | ||
1966 | 124 | // Per RFC 2616, this is either the value of the Host: header | ||
1967 | 125 | // or the host name given in the URL itself. | ||
1968 | 126 | Host string | ||
1969 | 127 | |||
1970 | 128 | // Form contains the parsed form data, including both the URL | ||
1971 | 129 | // field's query parameters and the POST or PUT form data. | ||
1972 | 130 | // This field is only available after ParseForm is called. | ||
1973 | 131 | // The HTTP client ignores Form and uses Body instead. | ||
1974 | 132 | Form url.Values | ||
1975 | 133 | |||
1976 | 134 | // MultipartForm is the parsed multipart form, including file uploads. | ||
1977 | 135 | // This field is only available after ParseMultipartForm is called. | ||
1978 | 136 | // The HTTP client ignores MultipartForm and uses Body instead. | ||
1979 | 137 | MultipartForm *multipart.Form | ||
1980 | 138 | |||
1981 | 139 | // Trailer maps trailer keys to values. Like for Header, if the | ||
1982 | 140 | // response has multiple trailer lines with the same key, they will be | ||
1983 | 141 | // concatenated, delimited by commas. | ||
1984 | 142 | // For server requests, Trailer is only populated after Body has been | ||
1985 | 143 | // closed or fully consumed. | ||
1986 | 144 | // Trailer support is only partially complete. | ||
1987 | 145 | Trailer Header | ||
1988 | 146 | |||
1989 | 147 | // RemoteAddr allows HTTP servers and other software to record | ||
1990 | 148 | // the network address that sent the request, usually for | ||
1991 | 149 | // logging. This field is not filled in by ReadRequest and | ||
1992 | 150 | // has no defined format. The HTTP server in this package | ||
1993 | 151 | // sets RemoteAddr to an "IP:port" address before invoking a | ||
1994 | 152 | // handler. | ||
1995 | 153 | // This field is ignored by the HTTP client. | ||
1996 | 154 | RemoteAddr string | ||
1997 | 155 | |||
1998 | 156 | // RequestURI is the unmodified Request-URI of the | ||
1999 | 157 | // Request-Line (RFC 2616, Section 5.1) as sent by the client | ||
2000 | 158 | // to a server. Usually the URL field should be used instead. | ||
2001 | 159 | // It is an error to set this field in an HTTP client request. | ||
2002 | 160 | RequestURI string | ||
2003 | 161 | |||
2004 | 162 | // TLS allows HTTP servers and other software to record | ||
2005 | 163 | // information about the TLS connection on which the request | ||
2006 | 164 | // was received. This field is not filled in by ReadRequest. | ||
2007 | 165 | // The HTTP server in this package sets the field for | ||
2008 | 166 | // TLS-enabled connections before invoking a handler; | ||
2009 | 167 | // otherwise it leaves the field nil. | ||
2010 | 168 | // This field is ignored by the HTTP client. | ||
2011 | 169 | TLS *tls.ConnectionState | ||
2012 | 170 | } | ||
2013 | 171 | |||
2014 | 172 | // ProtoAtLeast returns whether the HTTP protocol used | ||
2015 | 173 | // in the request is at least major.minor. | ||
2016 | 174 | func (r *Request) ProtoAtLeast(major, minor int) bool { | ||
2017 | 175 | return r.ProtoMajor > major || | ||
2018 | 176 | r.ProtoMajor == major && r.ProtoMinor >= minor | ||
2019 | 177 | } | ||
2020 | 178 | |||
2021 | 179 | // UserAgent returns the client's User-Agent, if sent in the request. | ||
2022 | 180 | func (r *Request) UserAgent() string { | ||
2023 | 181 | return r.Header.Get("User-Agent") | ||
2024 | 182 | } | ||
2025 | 183 | |||
2026 | 184 | // Cookies parses and returns the HTTP cookies sent with the request. | ||
2027 | 185 | func (r *Request) Cookies() []*Cookie { | ||
2028 | 186 | return readCookies(r.Header, "") | ||
2029 | 187 | } | ||
2030 | 188 | |||
2031 | 189 | var ErrNoCookie = errors.New("http: named cookie not present") | ||
2032 | 190 | |||
2033 | 191 | // Cookie returns the named cookie provided in the request or | ||
2034 | 192 | // ErrNoCookie if not found. | ||
2035 | 193 | func (r *Request) Cookie(name string) (*Cookie, error) { | ||
2036 | 194 | for _, c := range readCookies(r.Header, name) { | ||
2037 | 195 | return c, nil | ||
2038 | 196 | } | ||
2039 | 197 | return nil, ErrNoCookie | ||
2040 | 198 | } | ||
2041 | 199 | |||
2042 | 200 | // AddCookie adds a cookie to the request. Per RFC 6265 section 5.4, | ||
2043 | 201 | // AddCookie does not attach more than one Cookie header field. That | ||
2044 | 202 | // means all cookies, if any, are written into the same line, | ||
2045 | 203 | // separated by semicolon. | ||
2046 | 204 | func (r *Request) AddCookie(c *Cookie) { | ||
2047 | 205 | s := fmt.Sprintf("%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value)) | ||
2048 | 206 | if c := r.Header.Get("Cookie"); c != "" { | ||
2049 | 207 | r.Header.Set("Cookie", c+"; "+s) | ||
2050 | 208 | } else { | ||
2051 | 209 | r.Header.Set("Cookie", s) | ||
2052 | 210 | } | ||
2053 | 211 | } | ||
2054 | 212 | |||
2055 | 213 | // Referer returns the referring URL, if sent in the request. | ||
2056 | 214 | // | ||
2057 | 215 | // Referer is misspelled as in the request itself, a mistake from the | ||
2058 | 216 | // earliest days of HTTP. This value can also be fetched from the | ||
2059 | 217 | // Header map as Header["Referer"]; the benefit of making it available | ||
2060 | 218 | // as a method is that the compiler can diagnose programs that use the | ||
2061 | 219 | // alternate (correct English) spelling req.Referrer() but cannot | ||
2062 | 220 | // diagnose programs that use Header["Referrer"]. | ||
2063 | 221 | func (r *Request) Referer() string { | ||
2064 | 222 | return r.Header.Get("Referer") | ||
2065 | 223 | } | ||
2066 | 224 | |||
2067 | 225 | // multipartByReader is a sentinel value. | ||
2068 | 226 | // Its presence in Request.MultipartForm indicates that parsing of the request | ||
2069 | 227 | // body has been handed off to a MultipartReader instead of ParseMultipartFrom. | ||
2070 | 228 | var multipartByReader = &multipart.Form{ | ||
2071 | 229 | Value: make(map[string][]string), | ||
2072 | 230 | File: make(map[string][]*multipart.FileHeader), | ||
2073 | 231 | } | ||
2074 | 232 | |||
2075 | 233 | // MultipartReader returns a MIME multipart reader if this is a | ||
2076 | 234 | // multipart/form-data POST request, else returns nil and an error. | ||
2077 | 235 | // Use this function instead of ParseMultipartForm to | ||
2078 | 236 | // process the request body as a stream. | ||
2079 | 237 | func (r *Request) MultipartReader() (*multipart.Reader, error) { | ||
2080 | 238 | if r.MultipartForm == multipartByReader { | ||
2081 | 239 | return nil, errors.New("http: MultipartReader called twice") | ||
2082 | 240 | } | ||
2083 | 241 | if r.MultipartForm != nil { | ||
2084 | 242 | return nil, errors.New("http: multipart handled by ParseMultipartForm") | ||
2085 | 243 | } | ||
2086 | 244 | r.MultipartForm = multipartByReader | ||
2087 | 245 | return r.multipartReader() | ||
2088 | 246 | } | ||
2089 | 247 | |||
2090 | 248 | func (r *Request) multipartReader() (*multipart.Reader, error) { | ||
2091 | 249 | v := r.Header.Get("Content-Type") | ||
2092 | 250 | if v == "" { | ||
2093 | 251 | return nil, ErrNotMultipart | ||
2094 | 252 | } | ||
2095 | 253 | d, params, err := mime.ParseMediaType(v) | ||
2096 | 254 | if err != nil || d != "multipart/form-data" { | ||
2097 | 255 | return nil, ErrNotMultipart | ||
2098 | 256 | } | ||
2099 | 257 | boundary, ok := params["boundary"] | ||
2100 | 258 | if !ok { | ||
2101 | 259 | return nil, ErrMissingBoundary | ||
2102 | 260 | } | ||
2103 | 261 | return multipart.NewReader(r.Body, boundary), nil | ||
2104 | 262 | } | ||
2105 | 263 | |||
2106 | 264 | // Return value if nonempty, def otherwise. | ||
2107 | 265 | func valueOrDefault(value, def string) string { | ||
2108 | 266 | if value != "" { | ||
2109 | 267 | return value | ||
2110 | 268 | } | ||
2111 | 269 | return def | ||
2112 | 270 | } | ||
2113 | 271 | |||
2114 | 272 | const defaultUserAgent = "Go http package" | ||
2115 | 273 | |||
2116 | 274 | // Write writes an HTTP/1.1 request -- header and body -- in wire format. | ||
2117 | 275 | // This method consults the following fields of the request: | ||
2118 | 276 | // Host | ||
2119 | 277 | // URL | ||
2120 | 278 | // Method (defaults to "GET") | ||
2121 | 279 | // Header | ||
2122 | 280 | // ContentLength | ||
2123 | 281 | // TransferEncoding | ||
2124 | 282 | // Body | ||
2125 | 283 | // | ||
2126 | 284 | // If Body is present, Content-Length is <= 0 and TransferEncoding | ||
2127 | 285 | // hasn't been set to "identity", Write adds "Transfer-Encoding: | ||
2128 | 286 | // chunked" to the header. Body is closed after it is sent. | ||
2129 | 287 | func (r *Request) Write(w io.Writer) error { | ||
2130 | 288 | return r.write(w, false, nil) | ||
2131 | 289 | } | ||
2132 | 290 | |||
2133 | 291 | // WriteProxy is like Write but writes the request in the form | ||
2134 | 292 | // expected by an HTTP proxy. In particular, WriteProxy writes the | ||
2135 | 293 | // initial Request-URI line of the request with an absolute URI, per | ||
2136 | 294 | // section 5.1.2 of RFC 2616, including the scheme and host. | ||
2137 | 295 | // In either case, WriteProxy also writes a Host header, using | ||
2138 | 296 | // either r.Host or r.URL.Host. | ||
2139 | 297 | func (r *Request) WriteProxy(w io.Writer) error { | ||
2140 | 298 | return r.write(w, true, nil) | ||
2141 | 299 | } | ||
2142 | 300 | |||
2143 | 301 | // extraHeaders may be nil | ||
2144 | 302 | func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) error { | ||
2145 | 303 | host := req.Host | ||
2146 | 304 | if host == "" { | ||
2147 | 305 | if req.URL == nil { | ||
2148 | 306 | return errors.New("http: Request.Write on Request with no Host or URL set") | ||
2149 | 307 | } | ||
2150 | 308 | host = req.URL.Host | ||
2151 | 309 | } | ||
2152 | 310 | |||
2153 | 311 | ruri := req.URL.RequestURI() | ||
2154 | 312 | if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" { | ||
2155 | 313 | ruri = req.URL.Scheme + "://" + host + ruri | ||
2156 | 314 | } else if req.Method == "CONNECT" && req.URL.Path == "" { | ||
2157 | 315 | // CONNECT requests normally give just the host and port, not a full URL. | ||
2158 | 316 | ruri = host | ||
2159 | 317 | } | ||
2160 | 318 | // TODO(bradfitz): escape at least newlines in ruri? | ||
2161 | 319 | |||
2162 | 320 | bw := bufio.NewWriter(w) | ||
2163 | 321 | fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri) | ||
2164 | 322 | |||
2165 | 323 | // Header lines | ||
2166 | 324 | fmt.Fprintf(bw, "Host: %s\r\n", host) | ||
2167 | 325 | |||
2168 | 326 | // Use the defaultUserAgent unless the Header contains one, which | ||
2169 | 327 | // may be blank to not send the header. | ||
2170 | 328 | userAgent := defaultUserAgent | ||
2171 | 329 | if req.Header != nil { | ||
2172 | 330 | if ua := req.Header["User-Agent"]; len(ua) > 0 { | ||
2173 | 331 | userAgent = ua[0] | ||
2174 | 332 | } | ||
2175 | 333 | } | ||
2176 | 334 | if userAgent != "" { | ||
2177 | 335 | fmt.Fprintf(bw, "User-Agent: %s\r\n", userAgent) | ||
2178 | 336 | } | ||
2179 | 337 | |||
2180 | 338 | // Process Body,ContentLength,Close,Trailer | ||
2181 | 339 | tw, err := newTransferWriter(req) | ||
2182 | 340 | if err != nil { | ||
2183 | 341 | return err | ||
2184 | 342 | } | ||
2185 | 343 | err = tw.WriteHeader(bw) | ||
2186 | 344 | if err != nil { | ||
2187 | 345 | return err | ||
2188 | 346 | } | ||
2189 | 347 | |||
2190 | 348 | // TODO: split long values? (If so, should share code with Conn.Write) | ||
2191 | 349 | err = req.Header.WriteSubset(bw, reqWriteExcludeHeader) | ||
2192 | 350 | if err != nil { | ||
2193 | 351 | return err | ||
2194 | 352 | } | ||
2195 | 353 | |||
2196 | 354 | if extraHeaders != nil { | ||
2197 | 355 | err = extraHeaders.Write(bw) | ||
2198 | 356 | if err != nil { | ||
2199 | 357 | return err | ||
2200 | 358 | } | ||
2201 | 359 | } | ||
2202 | 360 | |||
2203 | 361 | io.WriteString(bw, "\r\n") | ||
2204 | 362 | |||
2205 | 363 | // Write body and trailer | ||
2206 | 364 | err = tw.WriteBody(bw) | ||
2207 | 365 | if err != nil { | ||
2208 | 366 | return err | ||
2209 | 367 | } | ||
2210 | 368 | |||
2211 | 369 | return bw.Flush() | ||
2212 | 370 | } | ||
2213 | 371 | |||
2214 | 372 | // Convert decimal at s[i:len(s)] to integer, | ||
2215 | 373 | // returning value, string position where the digits stopped, | ||
2216 | 374 | // and whether there was a valid number (digits, not too big). | ||
2217 | 375 | func atoi(s string, i int) (n, i1 int, ok bool) { | ||
2218 | 376 | const Big = 1000000 | ||
2219 | 377 | if i >= len(s) || s[i] < '0' || s[i] > '9' { | ||
2220 | 378 | return 0, 0, false | ||
2221 | 379 | } | ||
2222 | 380 | n = 0 | ||
2223 | 381 | for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { | ||
2224 | 382 | n = n*10 + int(s[i]-'0') | ||
2225 | 383 | if n > Big { | ||
2226 | 384 | return 0, 0, false | ||
2227 | 385 | } | ||
2228 | 386 | } | ||
2229 | 387 | return n, i, true | ||
2230 | 388 | } | ||
2231 | 389 | |||
2232 | 390 | // ParseHTTPVersion parses a HTTP version string. | ||
2233 | 391 | // "HTTP/1.0" returns (1, 0, true). | ||
2234 | 392 | func ParseHTTPVersion(vers string) (major, minor int, ok bool) { | ||
2235 | 393 | if len(vers) < 5 || vers[0:5] != "HTTP/" { | ||
2236 | 394 | return 0, 0, false | ||
2237 | 395 | } | ||
2238 | 396 | major, i, ok := atoi(vers, 5) | ||
2239 | 397 | if !ok || i >= len(vers) || vers[i] != '.' { | ||
2240 | 398 | return 0, 0, false | ||
2241 | 399 | } | ||
2242 | 400 | minor, i, ok = atoi(vers, i+1) | ||
2243 | 401 | if !ok || i != len(vers) { | ||
2244 | 402 | return 0, 0, false | ||
2245 | 403 | } | ||
2246 | 404 | return major, minor, true | ||
2247 | 405 | } | ||
2248 | 406 | |||
2249 | 407 | // NewRequest returns a new Request given a method, URL, and optional body. | ||
2250 | 408 | func NewRequest(method, urlStr string, body io.Reader) (*Request, error) { | ||
2251 | 409 | u, err := url.Parse(urlStr) | ||
2252 | 410 | if err != nil { | ||
2253 | 411 | return nil, err | ||
2254 | 412 | } | ||
2255 | 413 | rc, ok := body.(io.ReadCloser) | ||
2256 | 414 | if !ok && body != nil { | ||
2257 | 415 | rc = ioutil.NopCloser(body) | ||
2258 | 416 | } | ||
2259 | 417 | req := &Request{ | ||
2260 | 418 | Method: method, | ||
2261 | 419 | URL: u, | ||
2262 | 420 | Proto: "HTTP/1.1", | ||
2263 | 421 | ProtoMajor: 1, | ||
2264 | 422 | ProtoMinor: 1, | ||
2265 | 423 | Header: make(Header), | ||
2266 | 424 | Body: rc, | ||
2267 | 425 | Host: u.Host, | ||
2268 | 426 | } | ||
2269 | 427 | if body != nil { | ||
2270 | 428 | switch v := body.(type) { | ||
2271 | 429 | case *strings.Reader: | ||
2272 | 430 | req.ContentLength = int64(v.Len()) | ||
2273 | 431 | case *bytes.Buffer: | ||
2274 | 432 | req.ContentLength = int64(v.Len()) | ||
2275 | 433 | } | ||
2276 | 434 | } | ||
2277 | 435 | |||
2278 | 436 | return req, nil | ||
2279 | 437 | } | ||
2280 | 438 | |||
2281 | 439 | // SetBasicAuth sets the request's Authorization header to use HTTP | ||
2282 | 440 | // Basic Authentication with the provided username and password. | ||
2283 | 441 | // | ||
2284 | 442 | // With HTTP Basic Authentication the provided username and password | ||
2285 | 443 | // are not encrypted. | ||
2286 | 444 | func (r *Request) SetBasicAuth(username, password string) { | ||
2287 | 445 | s := username + ":" + password | ||
2288 | 446 | r.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(s))) | ||
2289 | 447 | } | ||
2290 | 448 | |||
2291 | 449 | // ReadRequest reads and parses a request from b. | ||
2292 | 450 | func ReadRequest(b *bufio.Reader) (req *Request, err error) { | ||
2293 | 451 | |||
2294 | 452 | tp := textproto.NewReader(b) | ||
2295 | 453 | req = new(Request) | ||
2296 | 454 | |||
2297 | 455 | // First line: GET /index.html HTTP/1.0 | ||
2298 | 456 | var s string | ||
2299 | 457 | if s, err = tp.ReadLine(); err != nil { | ||
2300 | 458 | return nil, err | ||
2301 | 459 | } | ||
2302 | 460 | defer func() { | ||
2303 | 461 | if err == io.EOF { | ||
2304 | 462 | err = io.ErrUnexpectedEOF | ||
2305 | 463 | } | ||
2306 | 464 | }() | ||
2307 | 465 | |||
2308 | 466 | var f []string | ||
2309 | 467 | if f = strings.SplitN(s, " ", 3); len(f) < 3 { | ||
2310 | 468 | return nil, &badStringError{"malformed HTTP request", s} | ||
2311 | 469 | } | ||
2312 | 470 | req.Method, req.RequestURI, req.Proto = f[0], f[1], f[2] | ||
2313 | 471 | rawurl := req.RequestURI | ||
2314 | 472 | var ok bool | ||
2315 | 473 | if req.ProtoMajor, req.ProtoMinor, ok = ParseHTTPVersion(req.Proto); !ok { | ||
2316 | 474 | return nil, &badStringError{"malformed HTTP version", req.Proto} | ||
2317 | 475 | } | ||
2318 | 476 | |||
2319 | 477 | // CONNECT requests are used two different ways, and neither uses a full URL: | ||
2320 | 478 | // The standard use is to tunnel HTTPS through an HTTP proxy. | ||
2321 | 479 | // It looks like "CONNECT www.google.com:443 HTTP/1.1", and the parameter is | ||
2322 | 480 | // just the authority section of a URL. This information should go in req.URL.Host. | ||
2323 | 481 | // | ||
2324 | 482 | // The net/rpc package also uses CONNECT, but there the parameter is a path | ||
2325 | 483 | // that starts with a slash. It can be parsed with the regular URL parser, | ||
2326 | 484 | // and the path will end up in req.URL.Path, where it needs to be in order for | ||
2327 | 485 | // RPC to work. | ||
2328 | 486 | justAuthority := req.Method == "CONNECT" && !strings.HasPrefix(rawurl, "/") | ||
2329 | 487 | if justAuthority { | ||
2330 | 488 | rawurl = "http://" + rawurl | ||
2331 | 489 | } | ||
2332 | 490 | |||
2333 | 491 | if req.URL, err = url.ParseRequestURI(rawurl); err != nil { | ||
2334 | 492 | return nil, err | ||
2335 | 493 | } | ||
2336 | 494 | |||
2337 | 495 | if justAuthority { | ||
2338 | 496 | // Strip the bogus "http://" back off. | ||
2339 | 497 | req.URL.Scheme = "" | ||
2340 | 498 | } | ||
2341 | 499 | |||
2342 | 500 | // Subsequent lines: Key: value. | ||
2343 | 501 | mimeHeader, err := tp.ReadMIMEHeader() | ||
2344 | 502 | if err != nil { | ||
2345 | 503 | return nil, err | ||
2346 | 504 | } | ||
2347 | 505 | req.Header = Header(mimeHeader) | ||
2348 | 506 | |||
2349 | 507 | // RFC2616: Must treat | ||
2350 | 508 | // GET /index.html HTTP/1.1 | ||
2351 | 509 | // Host: www.google.com | ||
2352 | 510 | // and | ||
2353 | 511 | // GET http://www.google.com/index.html HTTP/1.1 | ||
2354 | 512 | // Host: doesntmatter | ||
2355 | 513 | // the same. In the second case, any Host line is ignored. | ||
2356 | 514 | req.Host = req.URL.Host | ||
2357 | 515 | if req.Host == "" { | ||
2358 | 516 | req.Host = req.Header.Get("Host") | ||
2359 | 517 | } | ||
2360 | 518 | req.Header.Del("Host") | ||
2361 | 519 | |||
2362 | 520 | fixPragmaCacheControl(req.Header) | ||
2363 | 521 | |||
2364 | 522 | // TODO: Parse specific header values: | ||
2365 | 523 | // Accept | ||
2366 | 524 | // Accept-Encoding | ||
2367 | 525 | // Accept-Language | ||
2368 | 526 | // Authorization | ||
2369 | 527 | // Cache-Control | ||
2370 | 528 | // Connection | ||
2371 | 529 | // Date | ||
2372 | 530 | // Expect | ||
2373 | 531 | // From | ||
2374 | 532 | // If-Match | ||
2375 | 533 | // If-Modified-Since | ||
2376 | 534 | // If-None-Match | ||
2377 | 535 | // If-Range | ||
2378 | 536 | // If-Unmodified-Since | ||
2379 | 537 | // Max-Forwards | ||
2380 | 538 | // Proxy-Authorization | ||
2381 | 539 | // Referer [sic] | ||
2382 | 540 | // TE (transfer-codings) | ||
2383 | 541 | // Trailer | ||
2384 | 542 | // Transfer-Encoding | ||
2385 | 543 | // Upgrade | ||
2386 | 544 | // User-Agent | ||
2387 | 545 | // Via | ||
2388 | 546 | // Warning | ||
2389 | 547 | |||
2390 | 548 | err = readTransfer(req, b) | ||
2391 | 549 | if err != nil { | ||
2392 | 550 | return nil, err | ||
2393 | 551 | } | ||
2394 | 552 | |||
2395 | 553 | return req, nil | ||
2396 | 554 | } | ||
2397 | 555 | |||
2398 | 556 | // MaxBytesReader is similar to io.LimitReader but is intended for | ||
2399 | 557 | // limiting the size of incoming request bodies. In contrast to | ||
2400 | 558 | // io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a | ||
2401 | 559 | // non-EOF error for a Read beyond the limit, and Closes the | ||
2402 | 560 | // underlying reader when its Close method is called. | ||
2403 | 561 | // | ||
2404 | 562 | // MaxBytesReader prevents clients from accidentally or maliciously | ||
2405 | 563 | // sending a large request and wasting server resources. | ||
2406 | 564 | func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser { | ||
2407 | 565 | return &maxBytesReader{w: w, r: r, n: n} | ||
2408 | 566 | } | ||
2409 | 567 | |||
2410 | 568 | type maxBytesReader struct { | ||
2411 | 569 | w ResponseWriter | ||
2412 | 570 | r io.ReadCloser // underlying reader | ||
2413 | 571 | n int64 // max bytes remaining | ||
2414 | 572 | stopped bool | ||
2415 | 573 | } | ||
2416 | 574 | |||
2417 | 575 | func (l *maxBytesReader) Read(p []byte) (n int, err error) { | ||
2418 | 576 | if l.n <= 0 { | ||
2419 | 577 | if !l.stopped { | ||
2420 | 578 | l.stopped = true | ||
2421 | 579 | if res, ok := l.w.(*response); ok { | ||
2422 | 580 | res.requestTooLarge() | ||
2423 | 581 | } | ||
2424 | 582 | } | ||
2425 | 583 | return 0, errors.New("http: request body too large") | ||
2426 | 584 | } | ||
2427 | 585 | if int64(len(p)) > l.n { | ||
2428 | 586 | p = p[:l.n] | ||
2429 | 587 | } | ||
2430 | 588 | n, err = l.r.Read(p) | ||
2431 | 589 | l.n -= int64(n) | ||
2432 | 590 | return | ||
2433 | 591 | } | ||
2434 | 592 | |||
2435 | 593 | func (l *maxBytesReader) Close() error { | ||
2436 | 594 | return l.r.Close() | ||
2437 | 595 | } | ||
2438 | 596 | |||
2439 | 597 | // ParseForm parses the raw query from the URL. | ||
2440 | 598 | // | ||
2441 | 599 | // For POST or PUT requests, it also parses the request body as a form. | ||
2442 | 600 | // If the request Body's size has not already been limited by MaxBytesReader, | ||
2443 | 601 | // the size is capped at 10MB. | ||
2444 | 602 | // | ||
2445 | 603 | // ParseMultipartForm calls ParseForm automatically. | ||
2446 | 604 | // It is idempotent. | ||
2447 | 605 | func (r *Request) ParseForm() (err error) { | ||
2448 | 606 | if r.Form != nil { | ||
2449 | 607 | return | ||
2450 | 608 | } | ||
2451 | 609 | if r.URL != nil { | ||
2452 | 610 | r.Form, err = url.ParseQuery(r.URL.RawQuery) | ||
2453 | 611 | } | ||
2454 | 612 | if r.Method == "POST" || r.Method == "PUT" { | ||
2455 | 613 | if r.Body == nil { | ||
2456 | 614 | return errors.New("missing form body") | ||
2457 | 615 | } | ||
2458 | 616 | ct := r.Header.Get("Content-Type") | ||
2459 | 617 | ct, _, err = mime.ParseMediaType(ct) | ||
2460 | 618 | switch { | ||
2461 | 619 | case ct == "application/x-www-form-urlencoded": | ||
2462 | 620 | var reader io.Reader = r.Body | ||
2463 | 621 | maxFormSize := int64(1<<63 - 1) | ||
2464 | 622 | if _, ok := r.Body.(*maxBytesReader); !ok { | ||
2465 | 623 | maxFormSize = int64(10 << 20) // 10 MB is a lot of text. | ||
2466 | 624 | reader = io.LimitReader(r.Body, maxFormSize+1) | ||
2467 | 625 | } | ||
2468 | 626 | b, e := ioutil.ReadAll(reader) | ||
2469 | 627 | if e != nil { | ||
2470 | 628 | if err == nil { | ||
2471 | 629 | err = e | ||
2472 | 630 | } | ||
2473 | 631 | break | ||
2474 | 632 | } | ||
2475 | 633 | if int64(len(b)) > maxFormSize { | ||
2476 | 634 | return errors.New("http: POST too large") | ||
2477 | 635 | } | ||
2478 | 636 | var newValues url.Values | ||
2479 | 637 | newValues, e = url.ParseQuery(string(b)) | ||
2480 | 638 | if err == nil { | ||
2481 | 639 | err = e | ||
2482 | 640 | } | ||
2483 | 641 | if r.Form == nil { | ||
2484 | 642 | r.Form = make(url.Values) | ||
2485 | 643 | } | ||
2486 | 644 | // Copy values into r.Form. TODO: make this smoother. | ||
2487 | 645 | for k, vs := range newValues { | ||
2488 | 646 | for _, value := range vs { | ||
2489 | 647 | r.Form.Add(k, value) | ||
2490 | 648 | } | ||
2491 | 649 | } | ||
2492 | 650 | case ct == "multipart/form-data": | ||
2493 | 651 | // handled by ParseMultipartForm (which is calling us, or should be) | ||
2494 | 652 | // TODO(bradfitz): there are too many possible | ||
2495 | 653 | // orders to call too many functions here. | ||
2496 | 654 | // Clean this up and write more tests. | ||
2497 | 655 | // request_test.go contains the start of this, | ||
2498 | 656 | // in TestRequestMultipartCallOrder. | ||
2499 | 657 | } | ||
2500 | 658 | } | ||
2501 | 659 | return err | ||
2502 | 660 | } | ||
2503 | 661 | |||
2504 | 662 | // ParseMultipartForm parses a request body as multipart/form-data. | ||
2505 | 663 | // The whole request body is parsed and up to a total of maxMemory bytes of | ||
2506 | 664 | // its file parts are stored in memory, with the remainder stored on | ||
2507 | 665 | // disk in temporary files. | ||
2508 | 666 | // ParseMultipartForm calls ParseForm if necessary. | ||
2509 | 667 | // After one call to ParseMultipartForm, subsequent calls have no effect. | ||
2510 | 668 | func (r *Request) ParseMultipartForm(maxMemory int64) error { | ||
2511 | 669 | if r.MultipartForm == multipartByReader { | ||
2512 | 670 | return errors.New("http: multipart handled by MultipartReader") | ||
2513 | 671 | } | ||
2514 | 672 | if r.Form == nil { | ||
2515 | 673 | err := r.ParseForm() | ||
2516 | 674 | if err != nil { | ||
2517 | 675 | return err | ||
2518 | 676 | } | ||
2519 | 677 | } | ||
2520 | 678 | if r.MultipartForm != nil { | ||
2521 | 679 | return nil | ||
2522 | 680 | } | ||
2523 | 681 | |||
2524 | 682 | mr, err := r.multipartReader() | ||
2525 | 683 | if err == ErrNotMultipart { | ||
2526 | 684 | return nil | ||
2527 | 685 | } else if err != nil { | ||
2528 | 686 | return err | ||
2529 | 687 | } | ||
2530 | 688 | |||
2531 | 689 | f, err := mr.ReadForm(maxMemory) | ||
2532 | 690 | if err != nil { | ||
2533 | 691 | return err | ||
2534 | 692 | } | ||
2535 | 693 | for k, v := range f.Value { | ||
2536 | 694 | r.Form[k] = append(r.Form[k], v...) | ||
2537 | 695 | } | ||
2538 | 696 | r.MultipartForm = f | ||
2539 | 697 | |||
2540 | 698 | return nil | ||
2541 | 699 | } | ||
2542 | 700 | |||
2543 | 701 | // FormValue returns the first value for the named component of the query. | ||
2544 | 702 | // FormValue calls ParseMultipartForm and ParseForm if necessary. | ||
2545 | 703 | func (r *Request) FormValue(key string) string { | ||
2546 | 704 | if r.Form == nil { | ||
2547 | 705 | r.ParseMultipartForm(defaultMaxMemory) | ||
2548 | 706 | } | ||
2549 | 707 | if vs := r.Form[key]; len(vs) > 0 { | ||
2550 | 708 | return vs[0] | ||
2551 | 709 | } | ||
2552 | 710 | return "" | ||
2553 | 711 | } | ||
2554 | 712 | |||
2555 | 713 | // FormFile returns the first file for the provided form key. | ||
2556 | 714 | // FormFile calls ParseMultipartForm and ParseForm if necessary. | ||
2557 | 715 | func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) { | ||
2558 | 716 | if r.MultipartForm == multipartByReader { | ||
2559 | 717 | return nil, nil, errors.New("http: multipart handled by MultipartReader") | ||
2560 | 718 | } | ||
2561 | 719 | if r.MultipartForm == nil { | ||
2562 | 720 | err := r.ParseMultipartForm(defaultMaxMemory) | ||
2563 | 721 | if err != nil { | ||
2564 | 722 | return nil, nil, err | ||
2565 | 723 | } | ||
2566 | 724 | } | ||
2567 | 725 | if r.MultipartForm != nil && r.MultipartForm.File != nil { | ||
2568 | 726 | if fhs := r.MultipartForm.File[key]; len(fhs) > 0 { | ||
2569 | 727 | f, err := fhs[0].Open() | ||
2570 | 728 | return f, fhs[0], err | ||
2571 | 729 | } | ||
2572 | 730 | } | ||
2573 | 731 | return nil, nil, ErrMissingFile | ||
2574 | 732 | } | ||
2575 | 733 | |||
2576 | 734 | func (r *Request) expectsContinue() bool { | ||
2577 | 735 | return strings.ToLower(r.Header.Get("Expect")) == "100-continue" | ||
2578 | 736 | } | ||
2579 | 737 | |||
2580 | 738 | func (r *Request) wantsHttp10KeepAlive() bool { | ||
2581 | 739 | if r.ProtoMajor != 1 || r.ProtoMinor != 0 { | ||
2582 | 740 | return false | ||
2583 | 741 | } | ||
2584 | 742 | return strings.Contains(strings.ToLower(r.Header.Get("Connection")), "keep-alive") | ||
2585 | 743 | } | ||
2586 | 0 | 744 | ||
2587 | === added file 'fork/http/response.go' | |||
2588 | --- fork/http/response.go 1970-01-01 00:00:00 +0000 | |||
2589 | +++ fork/http/response.go 2013-07-22 14:27:42 +0000 | |||
2590 | @@ -0,0 +1,239 @@ | |||
2591 | 1 | // Copyright 2009 The Go Authors. All rights reserved. | ||
2592 | 2 | // Use of this source code is governed by a BSD-style | ||
2593 | 3 | // license that can be found in the LICENSE file. | ||
2594 | 4 | |||
2595 | 5 | // HTTP Response reading and parsing. | ||
2596 | 6 | |||
2597 | 7 | package http | ||
2598 | 8 | |||
2599 | 9 | import ( | ||
2600 | 10 | "bufio" | ||
2601 | 11 | "errors" | ||
2602 | 12 | "io" | ||
2603 | 13 | "net/textproto" | ||
2604 | 14 | "net/url" | ||
2605 | 15 | "strconv" | ||
2606 | 16 | "strings" | ||
2607 | 17 | ) | ||
2608 | 18 | |||
2609 | 19 | var respExcludeHeader = map[string]bool{ | ||
2610 | 20 | "Content-Length": true, | ||
2611 | 21 | "Transfer-Encoding": true, | ||
2612 | 22 | "Trailer": true, | ||
2613 | 23 | } | ||
2614 | 24 | |||
2615 | 25 | // Response represents the response from an HTTP request. | ||
2616 | 26 | // | ||
2617 | 27 | type Response struct { | ||
2618 | 28 | Status string // e.g. "200 OK" | ||
2619 | 29 | StatusCode int // e.g. 200 | ||
2620 | 30 | Proto string // e.g. "HTTP/1.0" | ||
2621 | 31 | ProtoMajor int // e.g. 1 | ||
2622 | 32 | ProtoMinor int // e.g. 0 | ||
2623 | 33 | |||
2624 | 34 | // Header maps header keys to values. If the response had multiple | ||
2625 | 35 | // headers with the same key, they will be concatenated, with comma | ||
2626 | 36 | // delimiters. (Section 4.2 of RFC 2616 requires that multiple headers | ||
2627 | 37 | // be semantically equivalent to a comma-delimited sequence.) Values | ||
2628 | 38 | // duplicated by other fields in this struct (e.g., ContentLength) are | ||
2629 | 39 | // omitted from Header. | ||
2630 | 40 | // | ||
2631 | 41 | // Keys in the map are canonicalized (see CanonicalHeaderKey). | ||
2632 | 42 | Header Header | ||
2633 | 43 | |||
2634 | 44 | // Body represents the response body. | ||
2635 | 45 | // | ||
2636 | 46 | // The http Client and Transport guarantee that Body is always | ||
2637 | 47 | // non-nil, even on responses without a body or responses with | ||
2638 | 48 | // a zero-lengthed body. | ||
2639 | 49 | Body io.ReadCloser | ||
2640 | 50 | |||
2641 | 51 | // ContentLength records the length of the associated content. The | ||
2642 | 52 | // value -1 indicates that the length is unknown. Unless RequestMethod | ||
2643 | 53 | // is "HEAD", values >= 0 indicate that the given number of bytes may | ||
2644 | 54 | // be read from Body. | ||
2645 | 55 | ContentLength int64 | ||
2646 | 56 | |||
2647 | 57 | // Contains transfer encodings from outer-most to inner-most. Value is | ||
2648 | 58 | // nil, means that "identity" encoding is used. | ||
2649 | 59 | TransferEncoding []string | ||
2650 | 60 | |||
2651 | 61 | // Close records whether the header directed that the connection be | ||
2652 | 62 | // closed after reading Body. The value is advice for clients: neither | ||
2653 | 63 | // ReadResponse nor Response.Write ever closes a connection. | ||
2654 | 64 | Close bool | ||
2655 | 65 | |||
2656 | 66 | // Trailer maps trailer keys to values, in the same | ||
2657 | 67 | // format as the header. | ||
2658 | 68 | Trailer Header | ||
2659 | 69 | |||
2660 | 70 | // The Request that was sent to obtain this Response. | ||
2661 | 71 | // Request's Body is nil (having already been consumed). | ||
2662 | 72 | // This is only populated for Client requests. | ||
2663 | 73 | Request *Request | ||
2664 | 74 | } | ||
2665 | 75 | |||
2666 | 76 | // Cookies parses and returns the cookies set in the Set-Cookie headers. | ||
2667 | 77 | func (r *Response) Cookies() []*Cookie { | ||
2668 | 78 | return readSetCookies(r.Header) | ||
2669 | 79 | } | ||
2670 | 80 | |||
2671 | 81 | var ErrNoLocation = errors.New("http: no Location header in response") | ||
2672 | 82 | |||
2673 | 83 | // Location returns the URL of the response's "Location" header, | ||
2674 | 84 | // if present. Relative redirects are resolved relative to | ||
2675 | 85 | // the Response's Request. ErrNoLocation is returned if no | ||
2676 | 86 | // Location header is present. | ||
2677 | 87 | func (r *Response) Location() (*url.URL, error) { | ||
2678 | 88 | lv := r.Header.Get("Location") | ||
2679 | 89 | if lv == "" { | ||
2680 | 90 | return nil, ErrNoLocation | ||
2681 | 91 | } | ||
2682 | 92 | if r.Request != nil && r.Request.URL != nil { | ||
2683 | 93 | return r.Request.URL.Parse(lv) | ||
2684 | 94 | } | ||
2685 | 95 | return url.Parse(lv) | ||
2686 | 96 | } | ||
2687 | 97 | |||
2688 | 98 | // ReadResponse reads and returns an HTTP response from r. The | ||
2689 | 99 | // req parameter specifies the Request that corresponds to | ||
2690 | 100 | // this Response. Clients must call resp.Body.Close when finished | ||
2691 | 101 | // reading resp.Body. After that call, clients can inspect | ||
2692 | 102 | // resp.Trailer to find key/value pairs included in the response | ||
2693 | 103 | // trailer. | ||
2694 | 104 | func ReadResponse(r *bufio.Reader, req *Request) (resp *Response, err error) { | ||
2695 | 105 | |||
2696 | 106 | tp := textproto.NewReader(r) | ||
2697 | 107 | resp = new(Response) | ||
2698 | 108 | |||
2699 | 109 | resp.Request = req | ||
2700 | 110 | resp.Request.Method = strings.ToUpper(resp.Request.Method) | ||
2701 | 111 | |||
2702 | 112 | // Parse the first line of the response. | ||
2703 | 113 | line, err := tp.ReadLine() | ||
2704 | 114 | if err != nil { | ||
2705 | 115 | if err == io.EOF { | ||
2706 | 116 | err = io.ErrUnexpectedEOF | ||
2707 | 117 | } | ||
2708 | 118 | return nil, err | ||
2709 | 119 | } | ||
2710 | 120 | f := strings.SplitN(line, " ", 3) | ||
2711 | 121 | if len(f) < 2 { | ||
2712 | 122 | return nil, &badStringError{"malformed HTTP response", line} | ||
2713 | 123 | } | ||
2714 | 124 | reasonPhrase := "" | ||
2715 | 125 | if len(f) > 2 { | ||
2716 | 126 | reasonPhrase = f[2] | ||
2717 | 127 | } | ||
2718 | 128 | resp.Status = f[1] + " " + reasonPhrase | ||
2719 | 129 | resp.StatusCode, err = strconv.Atoi(f[1]) | ||
2720 | 130 | if err != nil { | ||
2721 | 131 | return nil, &badStringError{"malformed HTTP status code", f[1]} | ||
2722 | 132 | } | ||
2723 | 133 | |||
2724 | 134 | resp.Proto = f[0] | ||
2725 | 135 | var ok bool | ||
2726 | 136 | if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok { | ||
2727 | 137 | return nil, &badStringError{"malformed HTTP version", resp.Proto} | ||
2728 | 138 | } | ||
2729 | 139 | |||
2730 | 140 | // Parse the response headers. | ||
2731 | 141 | mimeHeader, err := tp.ReadMIMEHeader() | ||
2732 | 142 | if err != nil { | ||
2733 | 143 | return nil, err | ||
2734 | 144 | } | ||
2735 | 145 | resp.Header = Header(mimeHeader) | ||
2736 | 146 | |||
2737 | 147 | fixPragmaCacheControl(resp.Header) | ||
2738 | 148 | |||
2739 | 149 | err = readTransfer(resp, r) | ||
2740 | 150 | if err != nil { | ||
2741 | 151 | return nil, err | ||
2742 | 152 | } | ||
2743 | 153 | |||
2744 | 154 | return resp, nil | ||
2745 | 155 | } | ||
2746 | 156 | |||
2747 | 157 | // RFC2616: Should treat | ||
2748 | 158 | // Pragma: no-cache | ||
2749 | 159 | // like | ||
2750 | 160 | // Cache-Control: no-cache | ||
2751 | 161 | func fixPragmaCacheControl(header Header) { | ||
2752 | 162 | if hp, ok := header["Pragma"]; ok && len(hp) > 0 && hp[0] == "no-cache" { | ||
2753 | 163 | if _, presentcc := header["Cache-Control"]; !presentcc { | ||
2754 | 164 | header["Cache-Control"] = []string{"no-cache"} | ||
2755 | 165 | } | ||
2756 | 166 | } | ||
2757 | 167 | } | ||
2758 | 168 | |||
2759 | 169 | // ProtoAtLeast returns whether the HTTP protocol used | ||
2760 | 170 | // in the response is at least major.minor. | ||
2761 | 171 | func (r *Response) ProtoAtLeast(major, minor int) bool { | ||
2762 | 172 | return r.ProtoMajor > major || | ||
2763 | 173 | r.ProtoMajor == major && r.ProtoMinor >= minor | ||
2764 | 174 | } | ||
2765 | 175 | |||
2766 | 176 | // Writes the response (header, body and trailer) in wire format. This method | ||
2767 | 177 | // consults the following fields of the response: | ||
2768 | 178 | // | ||
2769 | 179 | // StatusCode | ||
2770 | 180 | // ProtoMajor | ||
2771 | 181 | // ProtoMinor | ||
2772 | 182 | // RequestMethod | ||
2773 | 183 | // TransferEncoding | ||
2774 | 184 | // Trailer | ||
2775 | 185 | // Body | ||
2776 | 186 | // ContentLength | ||
2777 | 187 | // Header, values for non-canonical keys will have unpredictable behavior | ||
2778 | 188 | // | ||
2779 | 189 | func (r *Response) Write(w io.Writer) error { | ||
2780 | 190 | |||
2781 | 191 | // RequestMethod should be upper-case | ||
2782 | 192 | if r.Request != nil { | ||
2783 | 193 | r.Request.Method = strings.ToUpper(r.Request.Method) | ||
2784 | 194 | } | ||
2785 | 195 | |||
2786 | 196 | // Status line | ||
2787 | 197 | text := r.Status | ||
2788 | 198 | if text == "" { | ||
2789 | 199 | var ok bool | ||
2790 | 200 | text, ok = statusText[r.StatusCode] | ||
2791 | 201 | if !ok { | ||
2792 | 202 | text = "status code " + strconv.Itoa(r.StatusCode) | ||
2793 | 203 | } | ||
2794 | 204 | } | ||
2795 | 205 | protoMajor, protoMinor := strconv.Itoa(r.ProtoMajor), strconv.Itoa(r.ProtoMinor) | ||
2796 | 206 | statusCode := strconv.Itoa(r.StatusCode) + " " | ||
2797 | 207 | if strings.HasPrefix(text, statusCode) { | ||
2798 | 208 | text = text[len(statusCode):] | ||
2799 | 209 | } | ||
2800 | 210 | io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n") | ||
2801 | 211 | |||
2802 | 212 | // Process Body,ContentLength,Close,Trailer | ||
2803 | 213 | tw, err := newTransferWriter(r) | ||
2804 | 214 | if err != nil { | ||
2805 | 215 | return err | ||
2806 | 216 | } | ||
2807 | 217 | err = tw.WriteHeader(w) | ||
2808 | 218 | if err != nil { | ||
2809 | 219 | return err | ||
2810 | 220 | } | ||
2811 | 221 | |||
2812 | 222 | // Rest of header | ||
2813 | 223 | err = r.Header.WriteSubset(w, respExcludeHeader) | ||
2814 | 224 | if err != nil { | ||
2815 | 225 | return err | ||
2816 | 226 | } | ||
2817 | 227 | |||
2818 | 228 | // End-of-header | ||
2819 | 229 | io.WriteString(w, "\r\n") | ||
2820 | 230 | |||
2821 | 231 | // Write body and trailer | ||
2822 | 232 | err = tw.WriteBody(w) | ||
2823 | 233 | if err != nil { | ||
2824 | 234 | return err | ||
2825 | 235 | } | ||
2826 | 236 | |||
2827 | 237 | // Success | ||
2828 | 238 | return nil | ||
2829 | 239 | } | ||
2830 | 0 | 240 | ||
2831 | === added file 'fork/http/server.go' | |||
2832 | --- fork/http/server.go 1970-01-01 00:00:00 +0000 | |||
2833 | +++ fork/http/server.go 2013-07-22 14:27:42 +0000 | |||
2834 | @@ -0,0 +1,1234 @@ | |||
2835 | 1 | // Copyright 2009 The Go Authors. All rights reserved. | ||
2836 | 2 | // Use of this source code is governed by a BSD-style | ||
2837 | 3 | // license that can be found in the LICENSE file. | ||
2838 | 4 | |||
2839 | 5 | // HTTP server. See RFC 2616. | ||
2840 | 6 | |||
2841 | 7 | // TODO(rsc): | ||
2842 | 8 | // logging | ||
2843 | 9 | |||
2844 | 10 | package http | ||
2845 | 11 | |||
2846 | 12 | import ( | ||
2847 | 13 | "bufio" | ||
2848 | 14 | "bytes" | ||
2849 | 15 | "crypto/tls" | ||
2850 | 16 | "errors" | ||
2851 | 17 | "fmt" | ||
2852 | 18 | "io" | ||
2853 | 19 | "io/ioutil" | ||
2854 | 20 | "log" | ||
2855 | 21 | "net" | ||
2856 | 22 | "net/url" | ||
2857 | 23 | "path" | ||
2858 | 24 | "runtime/debug" | ||
2859 | 25 | "strconv" | ||
2860 | 26 | "strings" | ||
2861 | 27 | "sync" | ||
2862 | 28 | "time" | ||
2863 | 29 | ) | ||
2864 | 30 | |||
2865 | 31 | // Errors introduced by the HTTP server. | ||
2866 | 32 | var ( | ||
2867 | 33 | ErrWriteAfterFlush = errors.New("Conn.Write called after Flush") | ||
2868 | 34 | ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body") | ||
2869 | 35 | ErrHijacked = errors.New("Conn has been hijacked") | ||
2870 | 36 | ErrContentLength = errors.New("Conn.Write wrote more than the declared Content-Length") | ||
2871 | 37 | ) | ||
2872 | 38 | |||
2873 | 39 | // Objects implementing the Handler interface can be | ||
2874 | 40 | // registered to serve a particular path or subtree | ||
2875 | 41 | // in the HTTP server. | ||
2876 | 42 | // | ||
2877 | 43 | // ServeHTTP should write reply headers and data to the ResponseWriter | ||
2878 | 44 | // and then return. Returning signals that the request is finished | ||
2879 | 45 | // and that the HTTP server can move on to the next request on | ||
2880 | 46 | // the connection. | ||
2881 | 47 | type Handler interface { | ||
2882 | 48 | ServeHTTP(ResponseWriter, *Request) | ||
2883 | 49 | } | ||
2884 | 50 | |||
2885 | 51 | // A ResponseWriter interface is used by an HTTP handler to | ||
2886 | 52 | // construct an HTTP response. | ||
2887 | 53 | type ResponseWriter interface { | ||
2888 | 54 | // Header returns the header map that will be sent by WriteHeader. | ||
2889 | 55 | // Changing the header after a call to WriteHeader (or Write) has | ||
2890 | 56 | // no effect. | ||
2891 | 57 | Header() Header | ||
2892 | 58 | |||
2893 | 59 | // Write writes the data to the connection as part of an HTTP reply. | ||
2894 | 60 | // If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK) | ||
2895 | 61 | // before writing the data. If the Header does not contain a | ||
2896 | 62 | // Content-Type line, Write adds a Content-Type set to the result of passing | ||
2897 | 63 | // the initial 512 bytes of written data to DetectContentType. | ||
2898 | 64 | Write([]byte) (int, error) | ||
2899 | 65 | |||
2900 | 66 | // WriteHeader sends an HTTP response header with status code. | ||
2901 | 67 | // If WriteHeader is not called explicitly, the first call to Write | ||
2902 | 68 | // will trigger an implicit WriteHeader(http.StatusOK). | ||
2903 | 69 | // Thus explicit calls to WriteHeader are mainly used to | ||
2904 | 70 | // send error codes. | ||
2905 | 71 | WriteHeader(int) | ||
2906 | 72 | } | ||
2907 | 73 | |||
2908 | 74 | // The Flusher interface is implemented by ResponseWriters that allow | ||
2909 | 75 | // an HTTP handler to flush buffered data to the client. | ||
2910 | 76 | // | ||
2911 | 77 | // Note that even for ResponseWriters that support Flush, | ||
2912 | 78 | // if the client is connected through an HTTP proxy, | ||
2913 | 79 | // the buffered data may not reach the client until the response | ||
2914 | 80 | // completes. | ||
2915 | 81 | type Flusher interface { | ||
2916 | 82 | // Flush sends any buffered data to the client. | ||
2917 | 83 | Flush() | ||
2918 | 84 | } | ||
2919 | 85 | |||
2920 | 86 | // The Hijacker interface is implemented by ResponseWriters that allow | ||
2921 | 87 | // an HTTP handler to take over the connection. | ||
2922 | 88 | type Hijacker interface { | ||
2923 | 89 | // Hijack lets the caller take over the connection. | ||
2924 | 90 | // After a call to Hijack(), the HTTP server library | ||
2925 | 91 | // will not do anything else with the connection. | ||
2926 | 92 | // It becomes the caller's responsibility to manage | ||
2927 | 93 | // and close the connection. | ||
2928 | 94 | Hijack() (net.Conn, *bufio.ReadWriter, error) | ||
2929 | 95 | } | ||
2930 | 96 | |||
2931 | 97 | // A conn represents the server side of an HTTP connection. | ||
2932 | 98 | type conn struct { | ||
2933 | 99 | remoteAddr string // network address of remote side | ||
2934 | 100 | server *Server // the Server on which the connection arrived | ||
2935 | 101 | rwc net.Conn // i/o connection | ||
2936 | 102 | lr *io.LimitedReader // io.LimitReader(rwc) | ||
2937 | 103 | buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->rwc | ||
2938 | 104 | hijacked bool // connection has been hijacked by handler | ||
2939 | 105 | tlsState *tls.ConnectionState // or nil when not using TLS | ||
2940 | 106 | body []byte | ||
2941 | 107 | } | ||
2942 | 108 | |||
2943 | 109 | // A response represents the server side of an HTTP response. | ||
2944 | 110 | type response struct { | ||
2945 | 111 | conn *conn | ||
2946 | 112 | req *Request // request for this response | ||
2947 | 113 | chunking bool // using chunked transfer encoding for reply body | ||
2948 | 114 | wroteHeader bool // reply header has been written | ||
2949 | 115 | wroteContinue bool // 100 Continue response was written | ||
2950 | 116 | header Header // reply header parameters | ||
2951 | 117 | written int64 // number of bytes written in body | ||
2952 | 118 | contentLength int64 // explicitly-declared Content-Length; or -1 | ||
2953 | 119 | status int // status code passed to WriteHeader | ||
2954 | 120 | needSniff bool // need to sniff to find Content-Type | ||
2955 | 121 | |||
2956 | 122 | // close connection after this reply. set on request and | ||
2957 | 123 | // updated after response from handler if there's a | ||
2958 | 124 | // "Connection: keep-alive" response header and a | ||
2959 | 125 | // Content-Length. | ||
2960 | 126 | closeAfterReply bool | ||
2961 | 127 | |||
2962 | 128 | // requestBodyLimitHit is set by requestTooLarge when | ||
2963 | 129 | // maxBytesReader hits its max size. It is checked in | ||
2964 | 130 | // WriteHeader, to make sure we don't consume the the | ||
2965 | 131 | // remaining request body to try to advance to the next HTTP | ||
2966 | 132 | // request. Instead, when this is set, we stop doing | ||
2967 | 133 | // subsequent requests on this connection and stop reading | ||
2968 | 134 | // input from it. | ||
2969 | 135 | requestBodyLimitHit bool | ||
2970 | 136 | } | ||
2971 | 137 | |||
2972 | 138 | // requestTooLarge is called by maxBytesReader when too much input has | ||
2973 | 139 | // been read from the client. | ||
2974 | 140 | func (w *response) requestTooLarge() { | ||
2975 | 141 | w.closeAfterReply = true | ||
2976 | 142 | w.requestBodyLimitHit = true | ||
2977 | 143 | if !w.wroteHeader { | ||
2978 | 144 | w.Header().Set("Connection", "close") | ||
2979 | 145 | } | ||
2980 | 146 | } | ||
2981 | 147 | |||
2982 | 148 | type writerOnly struct { | ||
2983 | 149 | io.Writer | ||
2984 | 150 | } | ||
2985 | 151 | |||
2986 | 152 | func (w *response) ReadFrom(src io.Reader) (n int64, err error) { | ||
2987 | 153 | // Call WriteHeader before checking w.chunking if it hasn't | ||
2988 | 154 | // been called yet, since WriteHeader is what sets w.chunking. | ||
2989 | 155 | if !w.wroteHeader { | ||
2990 | 156 | w.WriteHeader(StatusOK) | ||
2991 | 157 | } | ||
2992 | 158 | if !w.chunking && w.bodyAllowed() && !w.needSniff { | ||
2993 | 159 | w.Flush() | ||
2994 | 160 | if rf, ok := w.conn.rwc.(io.ReaderFrom); ok { | ||
2995 | 161 | n, err = rf.ReadFrom(src) | ||
2996 | 162 | w.written += n | ||
2997 | 163 | return | ||
2998 | 164 | } | ||
2999 | 165 | } | ||
3000 | 166 | // Fall back to default io.Copy implementation. | ||
3001 | 167 | // Use wrapper to hide w.ReadFrom from io.Copy. | ||
3002 | 168 | return io.Copy(writerOnly{w}, src) | ||
3003 | 169 | } | ||
3004 | 170 | |||
3005 | 171 | // noLimit is an effective infinite upper bound for io.LimitedReader | ||
3006 | 172 | const noLimit int64 = (1 << 63) - 1 | ||
3007 | 173 | |||
3008 | 174 | // Create new connection from rwc. | ||
3009 | 175 | func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) { | ||
3010 | 176 | c = new(conn) | ||
3011 | 177 | c.remoteAddr = rwc.RemoteAddr().String() | ||
3012 | 178 | c.server = srv | ||
3013 | 179 | c.rwc = rwc | ||
3014 | 180 | c.body = make([]byte, sniffLen) | ||
3015 | 181 | c.lr = io.LimitReader(rwc, noLimit).(*io.LimitedReader) | ||
3016 | 182 | br := bufio.NewReader(c.lr) | ||
3017 | 183 | bw := bufio.NewWriter(rwc) | ||
3018 | 184 | c.buf = bufio.NewReadWriter(br, bw) | ||
3019 | 185 | return c, nil | ||
3020 | 186 | } | ||
3021 | 187 | |||
3022 | 188 | // DefaultMaxHeaderBytes is the maximum permitted size of the headers | ||
3023 | 189 | // in an HTTP request. | ||
3024 | 190 | // This can be overridden by setting Server.MaxHeaderBytes. | ||
3025 | 191 | const DefaultMaxHeaderBytes = 1 << 20 // 1 MB | ||
3026 | 192 | |||
3027 | 193 | func (srv *Server) maxHeaderBytes() int { | ||
3028 | 194 | if srv.MaxHeaderBytes > 0 { | ||
3029 | 195 | return srv.MaxHeaderBytes | ||
3030 | 196 | } | ||
3031 | 197 | return DefaultMaxHeaderBytes | ||
3032 | 198 | } | ||
3033 | 199 | |||
3034 | 200 | // wrapper around io.ReaderCloser which on first read, sends an | ||
3035 | 201 | // HTTP/1.1 100 Continue header | ||
3036 | 202 | type expectContinueReader struct { | ||
3037 | 203 | resp *response | ||
3038 | 204 | readCloser io.ReadCloser | ||
3039 | 205 | closed bool | ||
3040 | 206 | } | ||
3041 | 207 | |||
3042 | 208 | func (ecr *expectContinueReader) Read(p []byte) (n int, err error) { | ||
3043 | 209 | if ecr.closed { | ||
3044 | 210 | return 0, errors.New("http: Read after Close on request Body") | ||
3045 | 211 | } | ||
3046 | 212 | if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked { | ||
3047 | 213 | ecr.resp.wroteContinue = true | ||
3048 | 214 | io.WriteString(ecr.resp.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n") | ||
3049 | 215 | ecr.resp.conn.buf.Flush() | ||
3050 | 216 | } | ||
3051 | 217 | return ecr.readCloser.Read(p) | ||
3052 | 218 | } | ||
3053 | 219 | |||
3054 | 220 | func (ecr *expectContinueReader) Close() error { | ||
3055 | 221 | ecr.closed = true | ||
3056 | 222 | return ecr.readCloser.Close() | ||
3057 | 223 | } | ||
3058 | 224 | |||
3059 | 225 | // TimeFormat is the time format to use with | ||
3060 | 226 | // time.Parse and time.Time.Format when parsing | ||
3061 | 227 | // or generating times in HTTP headers. | ||
3062 | 228 | // It is like time.RFC1123 but hard codes GMT as the time zone. | ||
3063 | 229 | const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" | ||
3064 | 230 | |||
3065 | 231 | var errTooLarge = errors.New("http: request too large") | ||
3066 | 232 | |||
3067 | 233 | // Read next request from connection. | ||
3068 | 234 | func (c *conn) readRequest() (w *response, err error) { | ||
3069 | 235 | if c.hijacked { | ||
3070 | 236 | return nil, ErrHijacked | ||
3071 | 237 | } | ||
3072 | 238 | c.lr.N = int64(c.server.maxHeaderBytes()) + 4096 /* bufio slop */ | ||
3073 | 239 | var req *Request | ||
3074 | 240 | if req, err = ReadRequest(c.buf.Reader); err != nil { | ||
3075 | 241 | if c.lr.N == 0 { | ||
3076 | 242 | return nil, errTooLarge | ||
3077 | 243 | } | ||
3078 | 244 | return nil, err | ||
3079 | 245 | } | ||
3080 | 246 | c.lr.N = noLimit | ||
3081 | 247 | |||
3082 | 248 | req.RemoteAddr = c.remoteAddr | ||
3083 | 249 | req.TLS = c.tlsState | ||
3084 | 250 | |||
3085 | 251 | w = new(response) | ||
3086 | 252 | w.conn = c | ||
3087 | 253 | w.req = req | ||
3088 | 254 | w.header = make(Header) | ||
3089 | 255 | w.contentLength = -1 | ||
3090 | 256 | c.body = c.body[:0] | ||
3091 | 257 | return w, nil | ||
3092 | 258 | } | ||
3093 | 259 | |||
3094 | 260 | func (w *response) Header() Header { | ||
3095 | 261 | return w.header | ||
3096 | 262 | } | ||
3097 | 263 | |||
3098 | 264 | // maxPostHandlerReadBytes is the max number of Request.Body bytes not | ||
3099 | 265 | // consumed by a handler that the server will read from the client | ||
3100 | 266 | // in order to keep a connection alive. If there are more bytes than | ||
3101 | 267 | // this then the server to be paranoid instead sends a "Connection: | ||
3102 | 268 | // close" response. | ||
3103 | 269 | // | ||
3104 | 270 | // This number is approximately what a typical machine's TCP buffer | ||
3105 | 271 | // size is anyway. (if we have the bytes on the machine, we might as | ||
3106 | 272 | // well read them) | ||
3107 | 273 | const maxPostHandlerReadBytes = 256 << 10 | ||
3108 | 274 | |||
3109 | 275 | func (w *response) WriteHeader(code int) { | ||
3110 | 276 | if w.conn.hijacked { | ||
3111 | 277 | log.Print("http: response.WriteHeader on hijacked connection") | ||
3112 | 278 | return | ||
3113 | 279 | } | ||
3114 | 280 | if w.wroteHeader { | ||
3115 | 281 | log.Print("http: multiple response.WriteHeader calls") | ||
3116 | 282 | return | ||
3117 | 283 | } | ||
3118 | 284 | w.wroteHeader = true | ||
3119 | 285 | w.status = code | ||
3120 | 286 | |||
3121 | 287 | // Check for a explicit (and valid) Content-Length header. | ||
3122 | 288 | var hasCL bool | ||
3123 | 289 | var contentLength int64 | ||
3124 | 290 | if clenStr := w.header.Get("Content-Length"); clenStr != "" { | ||
3125 | 291 | var err error | ||
3126 | 292 | contentLength, err = strconv.ParseInt(clenStr, 10, 64) | ||
3127 | 293 | if err == nil { | ||
3128 | 294 | hasCL = true | ||
3129 | 295 | } else { | ||
3130 | 296 | log.Printf("http: invalid Content-Length of %q sent", clenStr) | ||
3131 | 297 | w.header.Del("Content-Length") | ||
3132 | 298 | } | ||
3133 | 299 | } | ||
3134 | 300 | |||
3135 | 301 | if w.req.wantsHttp10KeepAlive() && (w.req.Method == "HEAD" || hasCL) { | ||
3136 | 302 | _, connectionHeaderSet := w.header["Connection"] | ||
3137 | 303 | if !connectionHeaderSet { | ||
3138 | 304 | w.header.Set("Connection", "keep-alive") | ||
3139 | 305 | } | ||
3140 | 306 | } else if !w.req.ProtoAtLeast(1, 1) { | ||
3141 | 307 | // Client did not ask to keep connection alive. | ||
3142 | 308 | w.closeAfterReply = true | ||
3143 | 309 | } | ||
3144 | 310 | |||
3145 | 311 | if w.header.Get("Connection") == "close" { | ||
3146 | 312 | w.closeAfterReply = true | ||
3147 | 313 | } | ||
3148 | 314 | |||
3149 | 315 | // Per RFC 2616, we should consume the request body before | ||
3150 | 316 | // replying, if the handler hasn't already done so. But we | ||
3151 | 317 | // don't want to do an unbounded amount of reading here for | ||
3152 | 318 | // DoS reasons, so we only try up to a threshold. | ||
3153 | 319 | if w.req.ContentLength != 0 && !w.closeAfterReply { | ||
3154 | 320 | ecr, isExpecter := w.req.Body.(*expectContinueReader) | ||
3155 | 321 | if !isExpecter || ecr.resp.wroteContinue { | ||
3156 | 322 | n, _ := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1) | ||
3157 | 323 | if n >= maxPostHandlerReadBytes { | ||
3158 | 324 | w.requestTooLarge() | ||
3159 | 325 | w.header.Set("Connection", "close") | ||
3160 | 326 | } else { | ||
3161 | 327 | w.req.Body.Close() | ||
3162 | 328 | } | ||
3163 | 329 | } | ||
3164 | 330 | } | ||
3165 | 331 | |||
3166 | 332 | if code == StatusNotModified { | ||
3167 | 333 | // Must not have body. | ||
3168 | 334 | for _, header := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} { | ||
3169 | 335 | if w.header.Get(header) != "" { | ||
3170 | 336 | // TODO: return an error if WriteHeader gets a return parameter | ||
3171 | 337 | // or set a flag on w to make future Writes() write an error page? | ||
3172 | 338 | // for now just log and drop the header. | ||
3173 | 339 | log.Printf("http: StatusNotModified response with header %q defined", header) | ||
3174 | 340 | w.header.Del(header) | ||
3175 | 341 | } | ||
3176 | 342 | } | ||
3177 | 343 | } else { | ||
3178 | 344 | // If no content type, apply sniffing algorithm to body. | ||
3179 | 345 | if w.header.Get("Content-Type") == "" && w.req.Method != "HEAD" { | ||
3180 | 346 | w.needSniff = true | ||
3181 | 347 | } | ||
3182 | 348 | } | ||
3183 | 349 | |||
3184 | 350 | if _, ok := w.header["Date"]; !ok { | ||
3185 | 351 | w.Header().Set("Date", time.Now().UTC().Format(TimeFormat)) | ||
3186 | 352 | } | ||
3187 | 353 | |||
3188 | 354 | te := w.header.Get("Transfer-Encoding") | ||
3189 | 355 | hasTE := te != "" | ||
3190 | 356 | if hasCL && hasTE && te != "identity" { | ||
3191 | 357 | // TODO: return an error if WriteHeader gets a return parameter | ||
3192 | 358 | // For now just ignore the Content-Length. | ||
3193 | 359 | log.Printf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d", | ||
3194 | 360 | te, contentLength) | ||
3195 | 361 | w.header.Del("Content-Length") | ||
3196 | 362 | hasCL = false | ||
3197 | 363 | } | ||
3198 | 364 | |||
3199 | 365 | if w.req.Method == "HEAD" || code == StatusNotModified { | ||
3200 | 366 | // do nothing | ||
3201 | 367 | } else if hasCL { | ||
3202 | 368 | w.contentLength = contentLength | ||
3203 | 369 | w.header.Del("Transfer-Encoding") | ||
3204 | 370 | } else if w.req.ProtoAtLeast(1, 1) { | ||
3205 | 371 | // HTTP/1.1 or greater: use chunked transfer encoding | ||
3206 | 372 | // to avoid closing the connection at EOF. | ||
3207 | 373 | // TODO: this blows away any custom or stacked Transfer-Encoding they | ||
3208 | 374 | // might have set. Deal with that as need arises once we have a valid | ||
3209 | 375 | // use case. | ||
3210 | 376 | w.chunking = true | ||
3211 | 377 | w.header.Set("Transfer-Encoding", "chunked") | ||
3212 | 378 | } else { | ||
3213 | 379 | // HTTP version < 1.1: cannot do chunked transfer | ||
3214 | 380 | // encoding and we don't know the Content-Length so | ||
3215 | 381 | // signal EOF by closing connection. | ||
3216 | 382 | w.closeAfterReply = true | ||
3217 | 383 | w.header.Del("Transfer-Encoding") // in case already set | ||
3218 | 384 | } | ||
3219 | 385 | |||
3220 | 386 | // Cannot use Content-Length with non-identity Transfer-Encoding. | ||
3221 | 387 | if w.chunking { | ||
3222 | 388 | w.header.Del("Content-Length") | ||
3223 | 389 | } | ||
3224 | 390 | if !w.req.ProtoAtLeast(1, 0) { | ||
3225 | 391 | return | ||
3226 | 392 | } | ||
3227 | 393 | proto := "HTTP/1.0" | ||
3228 | 394 | if w.req.ProtoAtLeast(1, 1) { | ||
3229 | 395 | proto = "HTTP/1.1" | ||
3230 | 396 | } | ||
3231 | 397 | codestring := strconv.Itoa(code) | ||
3232 | 398 | text, ok := statusText[code] | ||
3233 | 399 | if !ok { | ||
3234 | 400 | text = "status code " + codestring | ||
3235 | 401 | } | ||
3236 | 402 | io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n") | ||
3237 | 403 | w.header.Write(w.conn.buf) | ||
3238 | 404 | |||
3239 | 405 | // If we need to sniff the body, leave the header open. | ||
3240 | 406 | // Otherwise, end it here. | ||
3241 | 407 | if !w.needSniff { | ||
3242 | 408 | io.WriteString(w.conn.buf, "\r\n") | ||
3243 | 409 | } | ||
3244 | 410 | } | ||
3245 | 411 | |||
3246 | 412 | // sniff uses the first block of written data, | ||
3247 | 413 | // stored in w.conn.body, to decide the Content-Type | ||
3248 | 414 | // for the HTTP body. | ||
3249 | 415 | func (w *response) sniff() { | ||
3250 | 416 | if !w.needSniff { | ||
3251 | 417 | return | ||
3252 | 418 | } | ||
3253 | 419 | w.needSniff = false | ||
3254 | 420 | |||
3255 | 421 | data := w.conn.body | ||
3256 | 422 | fmt.Fprintf(w.conn.buf, "Content-Type: %s\r\n\r\n", DetectContentType(data)) | ||
3257 | 423 | |||
3258 | 424 | if len(data) == 0 { | ||
3259 | 425 | return | ||
3260 | 426 | } | ||
3261 | 427 | if w.chunking { | ||
3262 | 428 | fmt.Fprintf(w.conn.buf, "%x\r\n", len(data)) | ||
3263 | 429 | } | ||
3264 | 430 | _, err := w.conn.buf.Write(data) | ||
3265 | 431 | if w.chunking && err == nil { | ||
3266 | 432 | io.WriteString(w.conn.buf, "\r\n") | ||
3267 | 433 | } | ||
3268 | 434 | } | ||
3269 | 435 | |||
3270 | 436 | // bodyAllowed returns true if a Write is allowed for this response type. | ||
3271 | 437 | // It's illegal to call this before the header has been flushed. | ||
3272 | 438 | func (w *response) bodyAllowed() bool { | ||
3273 | 439 | if !w.wroteHeader { | ||
3274 | 440 | panic("") | ||
3275 | 441 | } | ||
3276 | 442 | return w.status != StatusNotModified && w.req.Method != "HEAD" | ||
3277 | 443 | } | ||
3278 | 444 | |||
3279 | 445 | func (w *response) Write(data []byte) (n int, err error) { | ||
3280 | 446 | if w.conn.hijacked { | ||
3281 | 447 | log.Print("http: response.Write on hijacked connection") | ||
3282 | 448 | return 0, ErrHijacked | ||
3283 | 449 | } | ||
3284 | 450 | if !w.wroteHeader { | ||
3285 | 451 | w.WriteHeader(StatusOK) | ||
3286 | 452 | } | ||
3287 | 453 | if len(data) == 0 { | ||
3288 | 454 | return 0, nil | ||
3289 | 455 | } | ||
3290 | 456 | if !w.bodyAllowed() { | ||
3291 | 457 | return 0, ErrBodyNotAllowed | ||
3292 | 458 | } | ||
3293 | 459 | |||
3294 | 460 | w.written += int64(len(data)) // ignoring errors, for errorKludge | ||
3295 | 461 | if w.contentLength != -1 && w.written > w.contentLength { | ||
3296 | 462 | return 0, ErrContentLength | ||
3297 | 463 | } | ||
3298 | 464 | |||
3299 | 465 | var m int | ||
3300 | 466 | if w.needSniff { | ||
3301 | 467 | // We need to sniff the beginning of the output to | ||
3302 | 468 | // determine the content type. Accumulate the | ||
3303 | 469 | // initial writes in w.conn.body. | ||
3304 | 470 | // Cap m so that append won't allocate. | ||
3305 | 471 | m = cap(w.conn.body) - len(w.conn.body) | ||
3306 | 472 | if m > len(data) { | ||
3307 | 473 | m = len(data) | ||
3308 | 474 | } | ||
3309 | 475 | w.conn.body = append(w.conn.body, data[:m]...) | ||
3310 | 476 | data = data[m:] | ||
3311 | 477 | if len(data) == 0 { | ||
3312 | 478 | // Copied everything into the buffer. | ||
3313 | 479 | // Wait for next write. | ||
3314 | 480 | return m, nil | ||
3315 | 481 | } | ||
3316 | 482 | |||
3317 | 483 | // Filled the buffer; more data remains. | ||
3318 | 484 | // Sniff the content (flushes the buffer) | ||
3319 | 485 | // and then proceed with the remainder | ||
3320 | 486 | // of the data as a normal Write. | ||
3321 | 487 | // Calling sniff clears needSniff. | ||
3322 | 488 | w.sniff() | ||
3323 | 489 | } | ||
3324 | 490 | |||
3325 | 491 | // TODO(rsc): if chunking happened after the buffering, | ||
3326 | 492 | // then there would be fewer chunk headers. | ||
3327 | 493 | // On the other hand, it would make hijacking more difficult. | ||
3328 | 494 | if w.chunking { | ||
3329 | 495 | fmt.Fprintf(w.conn.buf, "%x\r\n", len(data)) // TODO(rsc): use strconv not fmt | ||
3330 | 496 | } | ||
3331 | 497 | n, err = w.conn.buf.Write(data) | ||
3332 | 498 | if err == nil && w.chunking { | ||
3333 | 499 | if n != len(data) { | ||
3334 | 500 | err = io.ErrShortWrite | ||
3335 | 501 | } | ||
3336 | 502 | if err == nil { | ||
3337 | 503 | io.WriteString(w.conn.buf, "\r\n") | ||
3338 | 504 | } | ||
3339 | 505 | } | ||
3340 | 506 | |||
3341 | 507 | return m + n, err | ||
3342 | 508 | } | ||
3343 | 509 | |||
3344 | 510 | func (w *response) finishRequest() { | ||
3345 | 511 | // If this was an HTTP/1.0 request with keep-alive and we sent a Content-Length | ||
3346 | 512 | // back, we can make this a keep-alive response ... | ||
3347 | 513 | if w.req.wantsHttp10KeepAlive() { | ||
3348 | 514 | sentLength := w.header.Get("Content-Length") != "" | ||
3349 | 515 | if sentLength && w.header.Get("Connection") == "keep-alive" { | ||
3350 | 516 | w.closeAfterReply = false | ||
3351 | 517 | } | ||
3352 | 518 | } | ||
3353 | 519 | if !w.wroteHeader { | ||
3354 | 520 | w.WriteHeader(StatusOK) | ||
3355 | 521 | } | ||
3356 | 522 | if w.needSniff { | ||
3357 | 523 | w.sniff() | ||
3358 | 524 | } | ||
3359 | 525 | if w.chunking { | ||
3360 | 526 | io.WriteString(w.conn.buf, "0\r\n") | ||
3361 | 527 | // trailer key/value pairs, followed by blank line | ||
3362 | 528 | io.WriteString(w.conn.buf, "\r\n") | ||
3363 | 529 | } | ||
3364 | 530 | w.conn.buf.Flush() | ||
3365 | 531 | // Close the body, unless we're about to close the whole TCP connection | ||
3366 | 532 | // anyway. | ||
3367 | 533 | if !w.closeAfterReply { | ||
3368 | 534 | w.req.Body.Close() | ||
3369 | 535 | } | ||
3370 | 536 | if w.req.MultipartForm != nil { | ||
3371 | 537 | w.req.MultipartForm.RemoveAll() | ||
3372 | 538 | } | ||
3373 | 539 | |||
3374 | 540 | if w.contentLength != -1 && w.contentLength != w.written { | ||
3375 | 541 | // Did not write enough. Avoid getting out of sync. | ||
3376 | 542 | w.closeAfterReply = true | ||
3377 | 543 | } | ||
3378 | 544 | } | ||
3379 | 545 | |||
3380 | 546 | func (w *response) Flush() { | ||
3381 | 547 | if !w.wroteHeader { | ||
3382 | 548 | w.WriteHeader(StatusOK) | ||
3383 | 549 | } | ||
3384 | 550 | w.sniff() | ||
3385 | 551 | w.conn.buf.Flush() | ||
3386 | 552 | } | ||
3387 | 553 | |||
3388 | 554 | // Close the connection. | ||
3389 | 555 | func (c *conn) close() { | ||
3390 | 556 | if c.buf != nil { | ||
3391 | 557 | c.buf.Flush() | ||
3392 | 558 | c.buf = nil | ||
3393 | 559 | } | ||
3394 | 560 | if c.rwc != nil { | ||
3395 | 561 | c.rwc.Close() | ||
3396 | 562 | c.rwc = nil | ||
3397 | 563 | } | ||
3398 | 564 | } | ||
3399 | 565 | |||
3400 | 566 | // Serve a new connection. | ||
3401 | 567 | func (c *conn) serve() { | ||
3402 | 568 | defer func() { | ||
3403 | 569 | err := recover() | ||
3404 | 570 | if err == nil { | ||
3405 | 571 | return | ||
3406 | 572 | } | ||
3407 | 573 | |||
3408 | 574 | var buf bytes.Buffer | ||
3409 | 575 | fmt.Fprintf(&buf, "http: panic serving %v: %v\n", c.remoteAddr, err) | ||
3410 | 576 | buf.Write(debug.Stack()) | ||
3411 | 577 | log.Print(buf.String()) | ||
3412 | 578 | |||
3413 | 579 | if c.rwc != nil { // may be nil if connection hijacked | ||
3414 | 580 | c.rwc.Close() | ||
3415 | 581 | } | ||
3416 | 582 | }() | ||
3417 | 583 | |||
3418 | 584 | if tlsConn, ok := c.rwc.(*tls.Conn); ok { | ||
3419 | 585 | if err := tlsConn.Handshake(); err != nil { | ||
3420 | 586 | c.close() | ||
3421 | 587 | return | ||
3422 | 588 | } | ||
3423 | 589 | c.tlsState = new(tls.ConnectionState) | ||
3424 | 590 | *c.tlsState = tlsConn.ConnectionState() | ||
3425 | 591 | } | ||
3426 | 592 | |||
3427 | 593 | for { | ||
3428 | 594 | w, err := c.readRequest() | ||
3429 | 595 | if err != nil { | ||
3430 | 596 | msg := "400 Bad Request" | ||
3431 | 597 | if err == errTooLarge { | ||
3432 | 598 | // Their HTTP client may or may not be | ||
3433 | 599 | // able to read this if we're | ||
3434 | 600 | // responding to them and hanging up | ||
3435 | 601 | // while they're still writing their | ||
3436 | 602 | // request. Undefined behavior. | ||
3437 | 603 | msg = "413 Request Entity Too Large" | ||
3438 | 604 | } else if err == io.EOF { | ||
3439 | 605 | break // Don't reply | ||
3440 | 606 | } else if neterr, ok := err.(net.Error); ok && neterr.Timeout() { | ||
3441 | 607 | break // Don't reply | ||
3442 | 608 | } | ||
3443 | 609 | fmt.Fprintf(c.rwc, "HTTP/1.1 %s\r\n\r\n", msg) | ||
3444 | 610 | break | ||
3445 | 611 | } | ||
3446 | 612 | |||
3447 | 613 | // Expect 100 Continue support | ||
3448 | 614 | req := w.req | ||
3449 | 615 | if req.expectsContinue() { | ||
3450 | 616 | if req.ProtoAtLeast(1, 1) { | ||
3451 | 617 | // Wrap the Body reader with one that replies on the connection | ||
3452 | 618 | req.Body = &expectContinueReader{readCloser: req.Body, resp: w} | ||
3453 | 619 | } | ||
3454 | 620 | if req.ContentLength == 0 { | ||
3455 | 621 | w.Header().Set("Connection", "close") | ||
3456 | 622 | w.WriteHeader(StatusBadRequest) | ||
3457 | 623 | w.finishRequest() | ||
3458 | 624 | break | ||
3459 | 625 | } | ||
3460 | 626 | req.Header.Del("Expect") | ||
3461 | 627 | } else if req.Header.Get("Expect") != "" { | ||
3462 | 628 | // TODO(bradfitz): let ServeHTTP handlers handle | ||
3463 | 629 | // requests with non-standard expectation[s]? Seems | ||
3464 | 630 | // theoretical at best, and doesn't fit into the | ||
3465 | 631 | // current ServeHTTP model anyway. We'd need to | ||
3466 | 632 | // make the ResponseWriter an optional | ||
3467 | 633 | // "ExpectReplier" interface or something. | ||
3468 | 634 | // | ||
3469 | 635 | // For now we'll just obey RFC 2616 14.20 which says | ||
3470 | 636 | // "If a server receives a request containing an | ||
3471 | 637 | // Expect field that includes an expectation- | ||
3472 | 638 | // extension that it does not support, it MUST | ||
3473 | 639 | // respond with a 417 (Expectation Failed) status." | ||
3474 | 640 | w.Header().Set("Connection", "close") | ||
3475 | 641 | w.WriteHeader(StatusExpectationFailed) | ||
3476 | 642 | w.finishRequest() | ||
3477 | 643 | break | ||
3478 | 644 | } | ||
3479 | 645 | |||
3480 | 646 | handler := c.server.Handler | ||
3481 | 647 | if handler == nil { | ||
3482 | 648 | handler = DefaultServeMux | ||
3483 | 649 | } | ||
3484 | 650 | |||
3485 | 651 | // HTTP cannot have multiple simultaneous active requests.[*] | ||
3486 | 652 | // Until the server replies to this request, it can't read another, | ||
3487 | 653 | // so we might as well run the handler in this goroutine. | ||
3488 | 654 | // [*] Not strictly true: HTTP pipelining. We could let them all process | ||
3489 | 655 | // in parallel even if their responses need to be serialized. | ||
3490 | 656 | handler.ServeHTTP(w, w.req) | ||
3491 | 657 | if c.hijacked { | ||
3492 | 658 | return | ||
3493 | 659 | } | ||
3494 | 660 | w.finishRequest() | ||
3495 | 661 | if w.closeAfterReply { | ||
3496 | 662 | break | ||
3497 | 663 | } | ||
3498 | 664 | } | ||
3499 | 665 | c.close() | ||
3500 | 666 | } | ||
3501 | 667 | |||
3502 | 668 | // Hijack implements the Hijacker.Hijack method. Our response is both a ResponseWriter | ||
3503 | 669 | // and a Hijacker. | ||
3504 | 670 | func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) { | ||
3505 | 671 | if w.conn.hijacked { | ||
3506 | 672 | return nil, nil, ErrHijacked | ||
3507 | 673 | } | ||
3508 | 674 | w.conn.hijacked = true | ||
3509 | 675 | rwc = w.conn.rwc | ||
3510 | 676 | buf = w.conn.buf | ||
3511 | 677 | w.conn.rwc = nil | ||
3512 | 678 | w.conn.buf = nil | ||
3513 | 679 | return | ||
3514 | 680 | } | ||
3515 | 681 | |||
3516 | 682 | // The HandlerFunc type is an adapter to allow the use of | ||
3517 | 683 | // ordinary functions as HTTP handlers. If f is a function | ||
3518 | 684 | // with the appropriate signature, HandlerFunc(f) is a | ||
3519 | 685 | // Handler object that calls f. | ||
3520 | 686 | type HandlerFunc func(ResponseWriter, *Request) | ||
3521 | 687 | |||
3522 | 688 | // ServeHTTP calls f(w, r). | ||
3523 | 689 | func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { | ||
3524 | 690 | f(w, r) | ||
3525 | 691 | } | ||
3526 | 692 | |||
3527 | 693 | // Helper handlers | ||
3528 | 694 | |||
3529 | 695 | // Error replies to the request with the specified error message and HTTP code. | ||
3530 | 696 | func Error(w ResponseWriter, error string, code int) { | ||
3531 | 697 | w.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||
3532 | 698 | w.WriteHeader(code) | ||
3533 | 699 | fmt.Fprintln(w, error) | ||
3534 | 700 | } | ||
3535 | 701 | |||
3536 | 702 | // NotFound replies to the request with an HTTP 404 not found error. | ||
3537 | 703 | func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) } | ||
3538 | 704 | |||
3539 | 705 | // NotFoundHandler returns a simple request handler | ||
3540 | 706 | // that replies to each request with a ``404 page not found'' reply. | ||
3541 | 707 | func NotFoundHandler() Handler { return HandlerFunc(NotFound) } | ||
3542 | 708 | |||
3543 | 709 | // StripPrefix returns a handler that serves HTTP requests | ||
3544 | 710 | // by removing the given prefix from the request URL's Path | ||
3545 | 711 | // and invoking the handler h. StripPrefix handles a | ||
3546 | 712 | // request for a path that doesn't begin with prefix by | ||
3547 | 713 | // replying with an HTTP 404 not found error. | ||
3548 | 714 | func StripPrefix(prefix string, h Handler) Handler { | ||
3549 | 715 | return HandlerFunc(func(w ResponseWriter, r *Request) { | ||
3550 | 716 | if !strings.HasPrefix(r.URL.Path, prefix) { | ||
3551 | 717 | NotFound(w, r) | ||
3552 | 718 | return | ||
3553 | 719 | } | ||
3554 | 720 | r.URL.Path = r.URL.Path[len(prefix):] | ||
3555 | 721 | h.ServeHTTP(w, r) | ||
3556 | 722 | }) | ||
3557 | 723 | } | ||
3558 | 724 | |||
3559 | 725 | // Redirect replies to the request with a redirect to url, | ||
3560 | 726 | // which may be a path relative to the request path. | ||
3561 | 727 | func Redirect(w ResponseWriter, r *Request, urlStr string, code int) { | ||
3562 | 728 | if u, err := url.Parse(urlStr); err == nil { | ||
3563 | 729 | // If url was relative, make absolute by | ||
3564 | 730 | // combining with request path. | ||
3565 | 731 | // The browser would probably do this for us, | ||
3566 | 732 | // but doing it ourselves is more reliable. | ||
3567 | 733 | |||
3568 | 734 | // NOTE(rsc): RFC 2616 says that the Location | ||
3569 | 735 | // line must be an absolute URI, like | ||
3570 | 736 | // "http://www.google.com/redirect/", | ||
3571 | 737 | // not a path like "/redirect/". | ||
3572 | 738 | // Unfortunately, we don't know what to | ||
3573 | 739 | // put in the host name section to get the | ||
3574 | 740 | // client to connect to us again, so we can't | ||
3575 | 741 | // know the right absolute URI to send back. | ||
3576 | 742 | // Because of this problem, no one pays attention | ||
3577 | 743 | // to the RFC; they all send back just a new path. | ||
3578 | 744 | // So do we. | ||
3579 | 745 | oldpath := r.URL.Path | ||
3580 | 746 | if oldpath == "" { // should not happen, but avoid a crash if it does | ||
3581 | 747 | oldpath = "/" | ||
3582 | 748 | } | ||
3583 | 749 | if u.Scheme == "" { | ||
3584 | 750 | // no leading http://server | ||
3585 | 751 | if urlStr == "" || urlStr[0] != '/' { | ||
3586 | 752 | // make relative path absolute | ||
3587 | 753 | olddir, _ := path.Split(oldpath) | ||
3588 | 754 | urlStr = olddir + urlStr | ||
3589 | 755 | } | ||
3590 | 756 | |||
3591 | 757 | var query string | ||
3592 | 758 | if i := strings.Index(urlStr, "?"); i != -1 { | ||
3593 | 759 | urlStr, query = urlStr[:i], urlStr[i:] | ||
3594 | 760 | } | ||
3595 | 761 | |||
3596 | 762 | // clean up but preserve trailing slash | ||
3597 | 763 | trailing := urlStr[len(urlStr)-1] == '/' | ||
3598 | 764 | urlStr = path.Clean(urlStr) | ||
3599 | 765 | if trailing && urlStr[len(urlStr)-1] != '/' { | ||
3600 | 766 | urlStr += "/" | ||
3601 | 767 | } | ||
3602 | 768 | urlStr += query | ||
3603 | 769 | } | ||
3604 | 770 | } | ||
3605 | 771 | |||
3606 | 772 | w.Header().Set("Location", urlStr) | ||
3607 | 773 | w.WriteHeader(code) | ||
3608 | 774 | |||
3609 | 775 | // RFC2616 recommends that a short note "SHOULD" be included in the | ||
3610 | 776 | // response because older user agents may not understand 301/307. | ||
3611 | 777 | // Shouldn't send the response for POST or HEAD; that leaves GET. | ||
3612 | 778 | if r.Method == "GET" { | ||
3613 | 779 | note := "<a href=\"" + htmlEscape(urlStr) + "\">" + statusText[code] + "</a>.\n" | ||
3614 | 780 | fmt.Fprintln(w, note) | ||
3615 | 781 | } | ||
3616 | 782 | } | ||
3617 | 783 | |||
3618 | 784 | var htmlReplacer = strings.NewReplacer( | ||
3619 | 785 | "&", "&", | ||
3620 | 786 | "<", "<", | ||
3621 | 787 | ">", ">", | ||
3622 | 788 | // """ is shorter than """. | ||
3623 | 789 | `"`, """, | ||
3624 | 790 | // "'" is shorter than "'" and apos was not in HTML until HTML5. | ||
3625 | 791 | "'", "'", | ||
3626 | 792 | ) | ||
3627 | 793 | |||
3628 | 794 | func htmlEscape(s string) string { | ||
3629 | 795 | return htmlReplacer.Replace(s) | ||
3630 | 796 | } | ||
3631 | 797 | |||
3632 | 798 | // Redirect to a fixed URL | ||
3633 | 799 | type redirectHandler struct { | ||
3634 | 800 | url string | ||
3635 | 801 | code int | ||
3636 | 802 | } | ||
3637 | 803 | |||
3638 | 804 | func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) { | ||
3639 | 805 | Redirect(w, r, rh.url, rh.code) | ||
3640 | 806 | } | ||
3641 | 807 | |||
3642 | 808 | // RedirectHandler returns a request handler that redirects | ||
3643 | 809 | // each request it receives to the given url using the given | ||
3644 | 810 | // status code. | ||
3645 | 811 | func RedirectHandler(url string, code int) Handler { | ||
3646 | 812 | return &redirectHandler{url, code} | ||
3647 | 813 | } | ||
3648 | 814 | |||
3649 | 815 | // ServeMux is an HTTP request multiplexer. | ||
3650 | 816 | // It matches the URL of each incoming request against a list of registered | ||
3651 | 817 | // patterns and calls the handler for the pattern that | ||
3652 | 818 | // most closely matches the URL. | ||
3653 | 819 | // | ||
3654 | 820 | // Patterns named fixed, rooted paths, like "/favicon.ico", | ||
3655 | 821 | // or rooted subtrees, like "/images/" (note the trailing slash). | ||
3656 | 822 | // Longer patterns take precedence over shorter ones, so that | ||
3657 | 823 | // if there are handlers registered for both "/images/" | ||
3658 | 824 | // and "/images/thumbnails/", the latter handler will be | ||
3659 | 825 | // called for paths beginning "/images/thumbnails/" and the | ||
3660 | 826 | // former will receiver requests for any other paths in the | ||
3661 | 827 | // "/images/" subtree. | ||
3662 | 828 | // | ||
3663 | 829 | // Patterns may optionally begin with a host name, restricting matches to | ||
3664 | 830 | // URLs on that host only. Host-specific patterns take precedence over | ||
3665 | 831 | // general patterns, so that a handler might register for the two patterns | ||
3666 | 832 | // "/codesearch" and "codesearch.google.com/" without also taking over | ||
3667 | 833 | // requests for "http://www.google.com/". | ||
3668 | 834 | // | ||
3669 | 835 | // ServeMux also takes care of sanitizing the URL request path, | ||
3670 | 836 | // redirecting any request containing . or .. elements to an | ||
3671 | 837 | // equivalent .- and ..-free URL. | ||
3672 | 838 | type ServeMux struct { | ||
3673 | 839 | mu sync.RWMutex | ||
3674 | 840 | m map[string]muxEntry | ||
3675 | 841 | } | ||
3676 | 842 | |||
3677 | 843 | type muxEntry struct { | ||
3678 | 844 | explicit bool | ||
3679 | 845 | h Handler | ||
3680 | 846 | } | ||
3681 | 847 | |||
3682 | 848 | // NewServeMux allocates and returns a new ServeMux. | ||
3683 | 849 | func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} } | ||
3684 | 850 | |||
3685 | 851 | // DefaultServeMux is the default ServeMux used by Serve. | ||
3686 | 852 | var DefaultServeMux = NewServeMux() | ||
3687 | 853 | |||
3688 | 854 | // Does path match pattern? | ||
3689 | 855 | func pathMatch(pattern, path string) bool { | ||
3690 | 856 | if len(pattern) == 0 { | ||
3691 | 857 | // should not happen | ||
3692 | 858 | return false | ||
3693 | 859 | } | ||
3694 | 860 | n := len(pattern) | ||
3695 | 861 | if pattern[n-1] != '/' { | ||
3696 | 862 | return pattern == path | ||
3697 | 863 | } | ||
3698 | 864 | return len(path) >= n && path[0:n] == pattern | ||
3699 | 865 | } | ||
3700 | 866 | |||
3701 | 867 | // Return the canonical path for p, eliminating . and .. elements. | ||
3702 | 868 | func cleanPath(p string) string { | ||
3703 | 869 | if p == "" { | ||
3704 | 870 | return "/" | ||
3705 | 871 | } | ||
3706 | 872 | if p[0] != '/' { | ||
3707 | 873 | p = "/" + p | ||
3708 | 874 | } | ||
3709 | 875 | np := path.Clean(p) | ||
3710 | 876 | // path.Clean removes trailing slash except for root; | ||
3711 | 877 | // put the trailing slash back if necessary. | ||
3712 | 878 | if p[len(p)-1] == '/' && np != "/" { | ||
3713 | 879 | np += "/" | ||
3714 | 880 | } | ||
3715 | 881 | return np | ||
3716 | 882 | } | ||
3717 | 883 | |||
3718 | 884 | // Find a handler on a handler map given a path string | ||
3719 | 885 | // Most-specific (longest) pattern wins | ||
3720 | 886 | func (mux *ServeMux) match(path string) Handler { | ||
3721 | 887 | var h Handler | ||
3722 | 888 | var n = 0 | ||
3723 | 889 | for k, v := range mux.m { | ||
3724 | 890 | if !pathMatch(k, path) { | ||
3725 | 891 | continue | ||
3726 | 892 | } | ||
3727 | 893 | if h == nil || len(k) > n { | ||
3728 | 894 | n = len(k) | ||
3729 | 895 | h = v.h | ||
3730 | 896 | } | ||
3731 | 897 | } | ||
3732 | 898 | return h | ||
3733 | 899 | } | ||
3734 | 900 | |||
3735 | 901 | // handler returns the handler to use for the request r. | ||
3736 | 902 | func (mux *ServeMux) handler(r *Request) Handler { | ||
3737 | 903 | mux.mu.RLock() | ||
3738 | 904 | defer mux.mu.RUnlock() | ||
3739 | 905 | |||
3740 | 906 | // Host-specific pattern takes precedence over generic ones | ||
3741 | 907 | h := mux.match(r.Host + r.URL.Path) | ||
3742 | 908 | if h == nil { | ||
3743 | 909 | h = mux.match(r.URL.Path) | ||
3744 | 910 | } | ||
3745 | 911 | if h == nil { | ||
3746 | 912 | h = NotFoundHandler() | ||
3747 | 913 | } | ||
3748 | 914 | return h | ||
3749 | 915 | } | ||
3750 | 916 | |||
3751 | 917 | // ServeHTTP dispatches the request to the handler whose | ||
3752 | 918 | // pattern most closely matches the request URL. | ||
3753 | 919 | func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { | ||
3754 | 920 | // Clean path to canonical form and redirect. | ||
3755 | 921 | if p := cleanPath(r.URL.Path); p != r.URL.Path { | ||
3756 | 922 | w.Header().Set("Location", p) | ||
3757 | 923 | w.WriteHeader(StatusMovedPermanently) | ||
3758 | 924 | return | ||
3759 | 925 | } | ||
3760 | 926 | mux.handler(r).ServeHTTP(w, r) | ||
3761 | 927 | } | ||
3762 | 928 | |||
3763 | 929 | // Handle registers the handler for the given pattern. | ||
3764 | 930 | // If a handler already exists for pattern, Handle panics. | ||
3765 | 931 | func (mux *ServeMux) Handle(pattern string, handler Handler) { | ||
3766 | 932 | mux.mu.Lock() | ||
3767 | 933 | defer mux.mu.Unlock() | ||
3768 | 934 | |||
3769 | 935 | if pattern == "" { | ||
3770 | 936 | panic("http: invalid pattern " + pattern) | ||
3771 | 937 | } | ||
3772 | 938 | if handler == nil { | ||
3773 | 939 | panic("http: nil handler") | ||
3774 | 940 | } | ||
3775 | 941 | if mux.m[pattern].explicit { | ||
3776 | 942 | panic("http: multiple registrations for " + pattern) | ||
3777 | 943 | } | ||
3778 | 944 | |||
3779 | 945 | mux.m[pattern] = muxEntry{explicit: true, h: handler} | ||
3780 | 946 | |||
3781 | 947 | // Helpful behavior: | ||
3782 | 948 | // If pattern is /tree/, insert an implicit permanent redirect for /tree. | ||
3783 | 949 | // It can be overridden by an explicit registration. | ||
3784 | 950 | n := len(pattern) | ||
3785 | 951 | if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit { | ||
3786 | 952 | mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(pattern, StatusMovedPermanently)} | ||
3787 | 953 | } | ||
3788 | 954 | } | ||
3789 | 955 | |||
3790 | 956 | // HandleFunc registers the handler function for the given pattern. | ||
3791 | 957 | func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { | ||
3792 | 958 | mux.Handle(pattern, HandlerFunc(handler)) | ||
3793 | 959 | } | ||
3794 | 960 | |||
3795 | 961 | // Handle registers the handler for the given pattern | ||
3796 | 962 | // in the DefaultServeMux. | ||
3797 | 963 | // The documentation for ServeMux explains how patterns are matched. | ||
3798 | 964 | func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) } | ||
3799 | 965 | |||
3800 | 966 | // HandleFunc registers the handler function for the given pattern | ||
3801 | 967 | // in the DefaultServeMux. | ||
3802 | 968 | // The documentation for ServeMux explains how patterns are matched. | ||
3803 | 969 | func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { | ||
3804 | 970 | DefaultServeMux.HandleFunc(pattern, handler) | ||
3805 | 971 | } | ||
3806 | 972 | |||
3807 | 973 | // Serve accepts incoming HTTP connections on the listener l, | ||
3808 | 974 | // creating a new service thread for each. The service threads | ||
3809 | 975 | // read requests and then call handler to reply to them. | ||
3810 | 976 | // Handler is typically nil, in which case the DefaultServeMux is used. | ||
3811 | 977 | func Serve(l net.Listener, handler Handler) error { | ||
3812 | 978 | srv := &Server{Handler: handler} | ||
3813 | 979 | return srv.Serve(l) | ||
3814 | 980 | } | ||
3815 | 981 | |||
3816 | 982 | // A Server defines parameters for running an HTTP server. | ||
3817 | 983 | type Server struct { | ||
3818 | 984 | Addr string // TCP address to listen on, ":http" if empty | ||
3819 | 985 | Handler Handler // handler to invoke, http.DefaultServeMux if nil | ||
3820 | 986 | ReadTimeout time.Duration // maximum duration before timing out read of the request | ||
3821 | 987 | WriteTimeout time.Duration // maximum duration before timing out write of the response | ||
3822 | 988 | MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0 | ||
3823 | 989 | TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS | ||
3824 | 990 | } | ||
3825 | 991 | |||
3826 | 992 | // ListenAndServe listens on the TCP network address srv.Addr and then | ||
3827 | 993 | // calls Serve to handle requests on incoming connections. If | ||
3828 | 994 | // srv.Addr is blank, ":http" is used. | ||
3829 | 995 | func (srv *Server) ListenAndServe() error { | ||
3830 | 996 | addr := srv.Addr | ||
3831 | 997 | if addr == "" { | ||
3832 | 998 | addr = ":http" | ||
3833 | 999 | } | ||
3834 | 1000 | l, e := net.Listen("tcp", addr) | ||
3835 | 1001 | if e != nil { | ||
3836 | 1002 | return e | ||
3837 | 1003 | } | ||
3838 | 1004 | return srv.Serve(l) | ||
3839 | 1005 | } | ||
3840 | 1006 | |||
3841 | 1007 | // Serve accepts incoming connections on the Listener l, creating a | ||
3842 | 1008 | // new service thread for each. The service threads read requests and | ||
3843 | 1009 | // then call srv.Handler to reply to them. | ||
3844 | 1010 | func (srv *Server) Serve(l net.Listener) error { | ||
3845 | 1011 | defer l.Close() | ||
3846 | 1012 | var tempDelay time.Duration // how long to sleep on accept failure | ||
3847 | 1013 | for { | ||
3848 | 1014 | rw, e := l.Accept() | ||
3849 | 1015 | if e != nil { | ||
3850 | 1016 | if ne, ok := e.(net.Error); ok && ne.Temporary() { | ||
3851 | 1017 | if tempDelay == 0 { | ||
3852 | 1018 | tempDelay = 5 * time.Millisecond | ||
3853 | 1019 | } else { | ||
3854 | 1020 | tempDelay *= 2 | ||
3855 | 1021 | } | ||
3856 | 1022 | if max := 1 * time.Second; tempDelay > max { | ||
3857 | 1023 | tempDelay = max | ||
3858 | 1024 | } | ||
3859 | 1025 | log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay) | ||
3860 | 1026 | time.Sleep(tempDelay) | ||
3861 | 1027 | continue | ||
3862 | 1028 | } | ||
3863 | 1029 | return e | ||
3864 | 1030 | } | ||
3865 | 1031 | tempDelay = 0 | ||
3866 | 1032 | if srv.ReadTimeout != 0 { | ||
3867 | 1033 | rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout)) | ||
3868 | 1034 | } | ||
3869 | 1035 | if srv.WriteTimeout != 0 { | ||
3870 | 1036 | rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout)) | ||
3871 | 1037 | } | ||
3872 | 1038 | c, err := srv.newConn(rw) | ||
3873 | 1039 | if err != nil { | ||
3874 | 1040 | continue | ||
3875 | 1041 | } | ||
3876 | 1042 | go c.serve() | ||
3877 | 1043 | } | ||
3878 | 1044 | panic("not reached") | ||
3879 | 1045 | } | ||
3880 | 1046 | |||
3881 | 1047 | // ListenAndServe listens on the TCP network address addr | ||
3882 | 1048 | // and then calls Serve with handler to handle requests | ||
3883 | 1049 | // on incoming connections. Handler is typically nil, | ||
3884 | 1050 | // in which case the DefaultServeMux is used. | ||
3885 | 1051 | // | ||
3886 | 1052 | // A trivial example server is: | ||
3887 | 1053 | // | ||
3888 | 1054 | // package main | ||
3889 | 1055 | // | ||
3890 | 1056 | // import ( | ||
3891 | 1057 | // "io" | ||
3892 | 1058 | // "net/http" | ||
3893 | 1059 | // "log" | ||
3894 | 1060 | // ) | ||
3895 | 1061 | // | ||
3896 | 1062 | // // hello world, the web server | ||
3897 | 1063 | // func HelloServer(w http.ResponseWriter, req *http.Request) { | ||
3898 | 1064 | // io.WriteString(w, "hello, world!\n") | ||
3899 | 1065 | // } | ||
3900 | 1066 | // | ||
3901 | 1067 | // func main() { | ||
3902 | 1068 | // http.HandleFunc("/hello", HelloServer) | ||
3903 | 1069 | // err := http.ListenAndServe(":12345", nil) | ||
3904 | 1070 | // if err != nil { | ||
3905 | 1071 | // log.Fatal("ListenAndServe: ", err) | ||
3906 | 1072 | // } | ||
3907 | 1073 | // } | ||
3908 | 1074 | func ListenAndServe(addr string, handler Handler) error { | ||
3909 | 1075 | server := &Server{Addr: addr, Handler: handler} | ||
3910 | 1076 | return server.ListenAndServe() | ||
3911 | 1077 | } | ||
3912 | 1078 | |||
3913 | 1079 | // ListenAndServeTLS acts identically to ListenAndServe, except that it | ||
3914 | 1080 | // expects HTTPS connections. Additionally, files containing a certificate and | ||
3915 | 1081 | // matching private key for the server must be provided. If the certificate | ||
3916 | 1082 | // is signed by a certificate authority, the certFile should be the concatenation | ||
3917 | 1083 | // of the server's certificate followed by the CA's certificate. | ||
3918 | 1084 | // | ||
3919 | 1085 | // A trivial example server is: | ||
3920 | 1086 | // | ||
3921 | 1087 | // import ( | ||
3922 | 1088 | // "log" | ||
3923 | 1089 | // "net/http" | ||
3924 | 1090 | // ) | ||
3925 | 1091 | // | ||
3926 | 1092 | // func handler(w http.ResponseWriter, req *http.Request) { | ||
3927 | 1093 | // w.Header().Set("Content-Type", "text/plain") | ||
3928 | 1094 | // w.Write([]byte("This is an example server.\n")) | ||
3929 | 1095 | // } | ||
3930 | 1096 | // | ||
3931 | 1097 | // func main() { | ||
3932 | 1098 | // http.HandleFunc("/", handler) | ||
3933 | 1099 | // log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/") | ||
3934 | 1100 | // err := http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil) | ||
3935 | 1101 | // if err != nil { | ||
3936 | 1102 | // log.Fatal(err) | ||
3937 | 1103 | // } | ||
3938 | 1104 | // } | ||
3939 | 1105 | // | ||
3940 | 1106 | // One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem. | ||
3941 | 1107 | func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error { | ||
3942 | 1108 | server := &Server{Addr: addr, Handler: handler} | ||
3943 | 1109 | return server.ListenAndServeTLS(certFile, keyFile) | ||
3944 | 1110 | } | ||
3945 | 1111 | |||
3946 | 1112 | // ListenAndServeTLS listens on the TCP network address srv.Addr and | ||
3947 | 1113 | // then calls Serve to handle requests on incoming TLS connections. | ||
3948 | 1114 | // | ||
3949 | 1115 | // Filenames containing a certificate and matching private key for | ||
3950 | 1116 | // the server must be provided. If the certificate is signed by a | ||
3951 | 1117 | // certificate authority, the certFile should be the concatenation | ||
3952 | 1118 | // of the server's certificate followed by the CA's certificate. | ||
3953 | 1119 | // | ||
3954 | 1120 | // If srv.Addr is blank, ":https" is used. | ||
3955 | 1121 | func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { | ||
3956 | 1122 | addr := srv.Addr | ||
3957 | 1123 | if addr == "" { | ||
3958 | 1124 | addr = ":https" | ||
3959 | 1125 | } | ||
3960 | 1126 | config := &tls.Config{} | ||
3961 | 1127 | if srv.TLSConfig != nil { | ||
3962 | 1128 | *config = *srv.TLSConfig | ||
3963 | 1129 | } | ||
3964 | 1130 | if config.NextProtos == nil { | ||
3965 | 1131 | config.NextProtos = []string{"http/1.1"} | ||
3966 | 1132 | } | ||
3967 | 1133 | |||
3968 | 1134 | var err error | ||
3969 | 1135 | config.Certificates = make([]tls.Certificate, 1) | ||
3970 | 1136 | config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) | ||
3971 | 1137 | if err != nil { | ||
3972 | 1138 | return err | ||
3973 | 1139 | } | ||
3974 | 1140 | |||
3975 | 1141 | conn, err := net.Listen("tcp", addr) | ||
3976 | 1142 | if err != nil { | ||
3977 | 1143 | return err | ||
3978 | 1144 | } | ||
3979 | 1145 | |||
3980 | 1146 | tlsListener := tls.NewListener(conn, config) | ||
3981 | 1147 | return srv.Serve(tlsListener) | ||
3982 | 1148 | } | ||
3983 | 1149 | |||
3984 | 1150 | // TimeoutHandler returns a Handler that runs h with the given time limit. | ||
3985 | 1151 | // | ||
3986 | 1152 | // The new Handler calls h.ServeHTTP to handle each request, but if a | ||
3987 | 1153 | // call runs for more than ns nanoseconds, the handler responds with | ||
3988 | 1154 | // a 503 Service Unavailable error and the given message in its body. | ||
3989 | 1155 | // (If msg is empty, a suitable default message will be sent.) | ||
3990 | 1156 | // After such a timeout, writes by h to its ResponseWriter will return | ||
3991 | 1157 | // ErrHandlerTimeout. | ||
3992 | 1158 | func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler { | ||
3993 | 1159 | f := func() <-chan time.Time { | ||
3994 | 1160 | return time.After(dt) | ||
3995 | 1161 | } | ||
3996 | 1162 | return &timeoutHandler{h, f, msg} | ||
3997 | 1163 | } | ||
3998 | 1164 | |||
3999 | 1165 | // ErrHandlerTimeout is returned on ResponseWriter Write calls | ||
4000 | 1166 | // in handlers which have timed out. | ||
4001 | 1167 | var ErrHandlerTimeout = errors.New("http: Handler timeout") | ||
4002 | 1168 | |||
4003 | 1169 | type timeoutHandler struct { | ||
4004 | 1170 | handler Handler | ||
4005 | 1171 | timeout func() <-chan time.Time // returns channel producing a timeout | ||
4006 | 1172 | body string | ||
4007 | 1173 | } | ||
4008 | 1174 | |||
4009 | 1175 | func (h *timeoutHandler) errorBody() string { | ||
4010 | 1176 | if h.body != "" { | ||
4011 | 1177 | return h.body | ||
4012 | 1178 | } | ||
4013 | 1179 | return "<html><head><title>Timeout</title></head><body><h1>Timeout</h1></body></html>" | ||
4014 | 1180 | } | ||
4015 | 1181 | |||
4016 | 1182 | func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { | ||
4017 | 1183 | done := make(chan bool) | ||
4018 | 1184 | tw := &timeoutWriter{w: w} | ||
4019 | 1185 | go func() { | ||
4020 | 1186 | h.handler.ServeHTTP(tw, r) | ||
4021 | 1187 | done <- true | ||
4022 | 1188 | }() | ||
4023 | 1189 | select { | ||
4024 | 1190 | case <-done: | ||
4025 | 1191 | return | ||
4026 | 1192 | case <-h.timeout(): | ||
4027 | 1193 | tw.mu.Lock() | ||
4028 | 1194 | defer tw.mu.Unlock() | ||
4029 | 1195 | if !tw.wroteHeader { | ||
4030 | 1196 | tw.w.WriteHeader(StatusServiceUnavailable) | ||
4031 | 1197 | tw.w.Write([]byte(h.errorBody())) | ||
4032 | 1198 | } | ||
4033 | 1199 | tw.timedOut = true | ||
4034 | 1200 | } | ||
4035 | 1201 | } | ||
4036 | 1202 | |||
4037 | 1203 | type timeoutWriter struct { | ||
4038 | 1204 | w ResponseWriter | ||
4039 | 1205 | |||
4040 | 1206 | mu sync.Mutex | ||
4041 | 1207 | timedOut bool | ||
4042 | 1208 | wroteHeader bool | ||
4043 | 1209 | } | ||
4044 | 1210 | |||
4045 | 1211 | func (tw *timeoutWriter) Header() Header { | ||
4046 | 1212 | return tw.w.Header() | ||
4047 | 1213 | } | ||
4048 | 1214 | |||
4049 | 1215 | func (tw *timeoutWriter) Write(p []byte) (int, error) { | ||
4050 | 1216 | tw.mu.Lock() | ||
4051 | 1217 | timedOut := tw.timedOut | ||
4052 | 1218 | tw.mu.Unlock() | ||
4053 | 1219 | if timedOut { | ||
4054 | 1220 | return 0, ErrHandlerTimeout | ||
4055 | 1221 | } | ||
4056 | 1222 | return tw.w.Write(p) | ||
4057 | 1223 | } | ||
4058 | 1224 | |||
4059 | 1225 | func (tw *timeoutWriter) WriteHeader(code int) { | ||
4060 | 1226 | tw.mu.Lock() | ||
4061 | 1227 | if tw.timedOut || tw.wroteHeader { | ||
4062 | 1228 | tw.mu.Unlock() | ||
4063 | 1229 | return | ||
4064 | 1230 | } | ||
4065 | 1231 | tw.wroteHeader = true | ||
4066 | 1232 | tw.mu.Unlock() | ||
4067 | 1233 | tw.w.WriteHeader(code) | ||
4068 | 1234 | } | ||
4069 | 0 | 1235 | ||
4070 | === added file 'fork/http/sniff.go' | |||
4071 | --- fork/http/sniff.go 1970-01-01 00:00:00 +0000 | |||
4072 | +++ fork/http/sniff.go 2013-07-22 14:27:42 +0000 | |||
4073 | @@ -0,0 +1,214 @@ | |||
4074 | 1 | // Copyright 2011 The Go Authors. All rights reserved. | ||
4075 | 2 | // Use of this source code is governed by a BSD-style | ||
4076 | 3 | // license that can be found in the LICENSE file. | ||
4077 | 4 | |||
4078 | 5 | package http | ||
4079 | 6 | |||
4080 | 7 | import ( | ||
4081 | 8 | "bytes" | ||
4082 | 9 | "encoding/binary" | ||
4083 | 10 | ) | ||
4084 | 11 | |||
4085 | 12 | // The algorithm uses at most sniffLen bytes to make its decision. | ||
4086 | 13 | const sniffLen = 512 | ||
4087 | 14 | |||
4088 | 15 | // DetectContentType implements the algorithm described | ||
4089 | 16 | // at http://mimesniff.spec.whatwg.org/ to determine the | ||
4090 | 17 | // Content-Type of the given data. It considers at most the | ||
4091 | 18 | // first 512 bytes of data. DetectContentType always returns | ||
4092 | 19 | // a valid MIME type: if it cannot determine a more specific one, it | ||
4093 | 20 | // returns "application/octet-stream". | ||
4094 | 21 | func DetectContentType(data []byte) string { | ||
4095 | 22 | if len(data) > sniffLen { | ||
4096 | 23 | data = data[:sniffLen] | ||
4097 | 24 | } | ||
4098 | 25 | |||
4099 | 26 | // Index of the first non-whitespace byte in data. | ||
4100 | 27 | firstNonWS := 0 | ||
4101 | 28 | for ; firstNonWS < len(data) && isWS(data[firstNonWS]); firstNonWS++ { | ||
4102 | 29 | } | ||
4103 | 30 | |||
4104 | 31 | for _, sig := range sniffSignatures { | ||
4105 | 32 | if ct := sig.match(data, firstNonWS); ct != "" { | ||
4106 | 33 | return ct | ||
4107 | 34 | } | ||
4108 | 35 | } | ||
4109 | 36 | |||
4110 | 37 | return "application/octet-stream" // fallback | ||
4111 | 38 | } | ||
4112 | 39 | |||
4113 | 40 | func isWS(b byte) bool { | ||
4114 | 41 | return bytes.IndexByte([]byte("\t\n\x0C\r "), b) != -1 | ||
4115 | 42 | } | ||
4116 | 43 | |||
4117 | 44 | type sniffSig interface { | ||
4118 | 45 | // match returns the MIME type of the data, or "" if unknown. | ||
4119 | 46 | match(data []byte, firstNonWS int) string | ||
4120 | 47 | } | ||
4121 | 48 | |||
4122 | 49 | // Data matching the table in section 6. | ||
4123 | 50 | var sniffSignatures = []sniffSig{ | ||
4124 | 51 | htmlSig("<!DOCTYPE HTML"), | ||
4125 | 52 | htmlSig("<HTML"), | ||
4126 | 53 | htmlSig("<HEAD"), | ||
4127 | 54 | htmlSig("<SCRIPT"), | ||
4128 | 55 | htmlSig("<IFRAME"), | ||
4129 | 56 | htmlSig("<H1"), | ||
4130 | 57 | htmlSig("<DIV"), | ||
4131 | 58 | htmlSig("<FONT"), | ||
4132 | 59 | htmlSig("<TABLE"), | ||
4133 | 60 | htmlSig("<A"), | ||
4134 | 61 | htmlSig("<STYLE"), | ||
4135 | 62 | htmlSig("<TITLE"), | ||
4136 | 63 | htmlSig("<B"), | ||
4137 | 64 | htmlSig("<BODY"), | ||
4138 | 65 | htmlSig("<BR"), | ||
4139 | 66 | htmlSig("<P"), | ||
4140 | 67 | htmlSig("<!--"), | ||
4141 | 68 | |||
4142 | 69 | &maskedSig{mask: []byte("\xFF\xFF\xFF\xFF\xFF"), pat: []byte("<?xml"), skipWS: true, ct: "text/xml; charset=utf-8"}, | ||
4143 | 70 | |||
4144 | 71 | &exactSig{[]byte("%PDF-"), "application/pdf"}, | ||
4145 | 72 | &exactSig{[]byte("%!PS-Adobe-"), "application/postscript"}, | ||
4146 | 73 | |||
4147 | 74 | // UTF BOMs. | ||
4148 | 75 | &maskedSig{mask: []byte("\xFF\xFF\x00\x00"), pat: []byte("\xFE\xFF\x00\x00"), ct: "text/plain; charset=utf-16be"}, | ||
4149 | 76 | &maskedSig{mask: []byte("\xFF\xFF\x00\x00"), pat: []byte("\xFF\xFE\x00\x00"), ct: "text/plain; charset=utf-16le"}, | ||
4150 | 77 | &maskedSig{mask: []byte("\xFF\xFF\xFF\x00"), pat: []byte("\xEF\xBB\xBF\x00"), ct: "text/plain; charset=utf-8"}, | ||
4151 | 78 | |||
4152 | 79 | &exactSig{[]byte("GIF87a"), "image/gif"}, | ||
4153 | 80 | &exactSig{[]byte("GIF89a"), "image/gif"}, | ||
4154 | 81 | &exactSig{[]byte("\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"), "image/png"}, | ||
4155 | 82 | &exactSig{[]byte("\xFF\xD8\xFF"), "image/jpeg"}, | ||
4156 | 83 | &exactSig{[]byte("BM"), "image/bmp"}, | ||
4157 | 84 | &maskedSig{ | ||
4158 | 85 | mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"), | ||
4159 | 86 | pat: []byte("RIFF\x00\x00\x00\x00WEBPVP"), | ||
4160 | 87 | ct: "image/webp", | ||
4161 | 88 | }, | ||
4162 | 89 | &exactSig{[]byte("\x00\x00\x01\x00"), "image/vnd.microsoft.icon"}, | ||
4163 | 90 | &exactSig{[]byte("\x4F\x67\x67\x53\x00"), "application/ogg"}, | ||
4164 | 91 | &maskedSig{ | ||
4165 | 92 | mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"), | ||
4166 | 93 | pat: []byte("RIFF\x00\x00\x00\x00WAVE"), | ||
4167 | 94 | ct: "audio/wave", | ||
4168 | 95 | }, | ||
4169 | 96 | &exactSig{[]byte("\x1A\x45\xDF\xA3"), "video/webm"}, | ||
4170 | 97 | &exactSig{[]byte("\x52\x61\x72\x20\x1A\x07\x00"), "application/x-rar-compressed"}, | ||
4171 | 98 | &exactSig{[]byte("\x50\x4B\x03\x04"), "application/zip"}, | ||
4172 | 99 | &exactSig{[]byte("\x1F\x8B\x08"), "application/x-gzip"}, | ||
4173 | 100 | |||
4174 | 101 | // TODO(dsymonds): Re-enable this when the spec is sorted w.r.t. MP4. | ||
4175 | 102 | //mp4Sig(0), | ||
4176 | 103 | |||
4177 | 104 | textSig(0), // should be last | ||
4178 | 105 | } | ||
4179 | 106 | |||
4180 | 107 | type exactSig struct { | ||
4181 | 108 | sig []byte | ||
4182 | 109 | ct string | ||
4183 | 110 | } | ||
4184 | 111 | |||
4185 | 112 | func (e *exactSig) match(data []byte, firstNonWS int) string { | ||
4186 | 113 | if bytes.HasPrefix(data, e.sig) { | ||
4187 | 114 | return e.ct | ||
4188 | 115 | } | ||
4189 | 116 | return "" | ||
4190 | 117 | } | ||
4191 | 118 | |||
4192 | 119 | type maskedSig struct { | ||
4193 | 120 | mask, pat []byte | ||
4194 | 121 | skipWS bool | ||
4195 | 122 | ct string | ||
4196 | 123 | } | ||
4197 | 124 | |||
4198 | 125 | func (m *maskedSig) match(data []byte, firstNonWS int) string { | ||
4199 | 126 | if m.skipWS { | ||
4200 | 127 | data = data[firstNonWS:] | ||
4201 | 128 | } | ||
4202 | 129 | if len(data) < len(m.mask) { | ||
4203 | 130 | return "" | ||
4204 | 131 | } | ||
4205 | 132 | for i, mask := range m.mask { | ||
4206 | 133 | db := data[i] & mask | ||
4207 | 134 | if db != m.pat[i] { | ||
4208 | 135 | return "" | ||
4209 | 136 | } | ||
4210 | 137 | } | ||
4211 | 138 | return m.ct | ||
4212 | 139 | } | ||
4213 | 140 | |||
4214 | 141 | type htmlSig []byte | ||
4215 | 142 | |||
4216 | 143 | func (h htmlSig) match(data []byte, firstNonWS int) string { | ||
4217 | 144 | data = data[firstNonWS:] | ||
4218 | 145 | if len(data) < len(h)+1 { | ||
4219 | 146 | return "" | ||
4220 | 147 | } | ||
4221 | 148 | for i, b := range h { | ||
4222 | 149 | db := data[i] | ||
4223 | 150 | if 'A' <= b && b <= 'Z' { | ||
4224 | 151 | db &= 0xDF | ||
4225 | 152 | } | ||
4226 | 153 | if b != db { | ||
4227 | 154 | return "" | ||
4228 | 155 | } | ||
4229 | 156 | } | ||
4230 | 157 | // Next byte must be space or right angle bracket. | ||
4231 | 158 | if db := data[len(h)]; db != ' ' && db != '>' { | ||
4232 | 159 | return "" | ||
4233 | 160 | } | ||
4234 | 161 | return "text/html; charset=utf-8" | ||
4235 | 162 | } | ||
4236 | 163 | |||
4237 | 164 | type mp4Sig int | ||
4238 | 165 | |||
4239 | 166 | func (mp4Sig) match(data []byte, firstNonWS int) string { | ||
4240 | 167 | // c.f. section 6.1. | ||
4241 | 168 | if len(data) < 8 { | ||
4242 | 169 | return "" | ||
4243 | 170 | } | ||
4244 | 171 | boxSize := int(binary.BigEndian.Uint32(data[:4])) | ||
4245 | 172 | if boxSize%4 != 0 || len(data) < boxSize { | ||
4246 | 173 | return "" | ||
4247 | 174 | } | ||
4248 | 175 | if !bytes.Equal(data[4:8], []byte("ftyp")) { | ||
4249 | 176 | return "" | ||
4250 | 177 | } | ||
4251 | 178 | for st := 8; st < boxSize; st += 4 { | ||
4252 | 179 | if st == 12 { | ||
4253 | 180 | // minor version number | ||
4254 | 181 | continue | ||
4255 | 182 | } | ||
4256 | 183 | seg := string(data[st : st+3]) | ||
4257 | 184 | switch seg { | ||
4258 | 185 | case "mp4", "iso", "M4V", "M4P", "M4B": | ||
4259 | 186 | return "video/mp4" | ||
4260 | 187 | /* The remainder are not in the spec. | ||
4261 | 188 | case "M4A": | ||
4262 | 189 | return "audio/mp4" | ||
4263 | 190 | case "3gp": | ||
4264 | 191 | return "video/3gpp" | ||
4265 | 192 | case "jp2": | ||
4266 | 193 | return "image/jp2" // JPEG 2000 | ||
4267 | 194 | */ | ||
4268 | 195 | } | ||
4269 | 196 | } | ||
4270 | 197 | return "" | ||
4271 | 198 | } | ||
4272 | 199 | |||
4273 | 200 | type textSig int | ||
4274 | 201 | |||
4275 | 202 | func (textSig) match(data []byte, firstNonWS int) string { | ||
4276 | 203 | // c.f. section 5, step 4. | ||
4277 | 204 | for _, b := range data[firstNonWS:] { | ||
4278 | 205 | switch { | ||
4279 | 206 | case 0x00 <= b && b <= 0x08, | ||
4280 | 207 | b == 0x0B, | ||
4281 | 208 | 0x0E <= b && b <= 0x1A, | ||
4282 | 209 | 0x1C <= b && b <= 0x1F: | ||
4283 | 210 | return "" | ||
4284 | 211 | } | ||
4285 | 212 | } | ||
4286 | 213 | return "text/plain; charset=utf-8" | ||
4287 | 214 | } | ||
4288 | 0 | 215 | ||
4289 | === added file 'fork/http/status.go' | |||
4290 | --- fork/http/status.go 1970-01-01 00:00:00 +0000 | |||
4291 | +++ fork/http/status.go 2013-07-22 14:27:42 +0000 | |||
4292 | @@ -0,0 +1,108 @@ | |||
4293 | 1 | // Copyright 2009 The Go Authors. All rights reserved. | ||
4294 | 2 | // Use of this source code is governed by a BSD-style | ||
4295 | 3 | // license that can be found in the LICENSE file. | ||
4296 | 4 | |||
4297 | 5 | package http | ||
4298 | 6 | |||
4299 | 7 | // HTTP status codes, defined in RFC 2616. | ||
4300 | 8 | const ( | ||
4301 | 9 | StatusContinue = 100 | ||
4302 | 10 | StatusSwitchingProtocols = 101 | ||
4303 | 11 | |||
4304 | 12 | StatusOK = 200 | ||
4305 | 13 | StatusCreated = 201 | ||
4306 | 14 | StatusAccepted = 202 | ||
4307 | 15 | StatusNonAuthoritativeInfo = 203 | ||
4308 | 16 | StatusNoContent = 204 | ||
4309 | 17 | StatusResetContent = 205 | ||
4310 | 18 | StatusPartialContent = 206 | ||
4311 | 19 | |||
4312 | 20 | StatusMultipleChoices = 300 | ||
4313 | 21 | StatusMovedPermanently = 301 | ||
4314 | 22 | StatusFound = 302 | ||
4315 | 23 | StatusSeeOther = 303 | ||
4316 | 24 | StatusNotModified = 304 | ||
4317 | 25 | StatusUseProxy = 305 | ||
4318 | 26 | StatusTemporaryRedirect = 307 | ||
4319 | 27 | |||
4320 | 28 | StatusBadRequest = 400 | ||
4321 | 29 | StatusUnauthorized = 401 | ||
4322 | 30 | StatusPaymentRequired = 402 | ||
4323 | 31 | StatusForbidden = 403 | ||
4324 | 32 | StatusNotFound = 404 | ||
4325 | 33 | StatusMethodNotAllowed = 405 | ||
4326 | 34 | StatusNotAcceptable = 406 | ||
4327 | 35 | StatusProxyAuthRequired = 407 | ||
4328 | 36 | StatusRequestTimeout = 408 | ||
4329 | 37 | StatusConflict = 409 | ||
4330 | 38 | StatusGone = 410 | ||
4331 | 39 | StatusLengthRequired = 411 | ||
4332 | 40 | StatusPreconditionFailed = 412 | ||
4333 | 41 | StatusRequestEntityTooLarge = 413 | ||
4334 | 42 | StatusRequestURITooLong = 414 | ||
4335 | 43 | StatusUnsupportedMediaType = 415 | ||
4336 | 44 | StatusRequestedRangeNotSatisfiable = 416 | ||
4337 | 45 | StatusExpectationFailed = 417 | ||
4338 | 46 | StatusTeapot = 418 | ||
4339 | 47 | |||
4340 | 48 | StatusInternalServerError = 500 | ||
4341 | 49 | StatusNotImplemented = 501 | ||
4342 | 50 | StatusBadGateway = 502 | ||
4343 | 51 | StatusServiceUnavailable = 503 | ||
4344 | 52 | StatusGatewayTimeout = 504 | ||
4345 | 53 | StatusHTTPVersionNotSupported = 505 | ||
4346 | 54 | ) | ||
4347 | 55 | |||
4348 | 56 | var statusText = map[int]string{ | ||
4349 | 57 | StatusContinue: "Continue", | ||
4350 | 58 | StatusSwitchingProtocols: "Switching Protocols", | ||
4351 | 59 | |||
4352 | 60 | StatusOK: "OK", | ||
4353 | 61 | StatusCreated: "Created", | ||
4354 | 62 | StatusAccepted: "Accepted", | ||
4355 | 63 | StatusNonAuthoritativeInfo: "Non-Authoritative Information", | ||
4356 | 64 | StatusNoContent: "No Content", | ||
4357 | 65 | StatusResetContent: "Reset Content", | ||
4358 | 66 | StatusPartialContent: "Partial Content", | ||
4359 | 67 | |||
4360 | 68 | StatusMultipleChoices: "Multiple Choices", | ||
4361 | 69 | StatusMovedPermanently: "Moved Permanently", | ||
4362 | 70 | StatusFound: "Found", | ||
4363 | 71 | StatusSeeOther: "See Other", | ||
4364 | 72 | StatusNotModified: "Not Modified", | ||
4365 | 73 | StatusUseProxy: "Use Proxy", | ||
4366 | 74 | StatusTemporaryRedirect: "Temporary Redirect", | ||
4367 | 75 | |||
4368 | 76 | StatusBadRequest: "Bad Request", | ||
4369 | 77 | StatusUnauthorized: "Unauthorized", | ||
4370 | 78 | StatusPaymentRequired: "Payment Required", | ||
4371 | 79 | StatusForbidden: "Forbidden", | ||
4372 | 80 | StatusNotFound: "Not Found", | ||
4373 | 81 | StatusMethodNotAllowed: "Method Not Allowed", | ||
4374 | 82 | StatusNotAcceptable: "Not Acceptable", | ||
4375 | 83 | StatusProxyAuthRequired: "Proxy Authentication Required", | ||
4376 | 84 | StatusRequestTimeout: "Request Timeout", | ||
4377 | 85 | StatusConflict: "Conflict", | ||
4378 | 86 | StatusGone: "Gone", | ||
4379 | 87 | StatusLengthRequired: "Length Required", | ||
4380 | 88 | StatusPreconditionFailed: "Precondition Failed", | ||
4381 | 89 | StatusRequestEntityTooLarge: "Request Entity Too Large", | ||
4382 | 90 | StatusRequestURITooLong: "Request URI Too Long", | ||
4383 | 91 | StatusUnsupportedMediaType: "Unsupported Media Type", | ||
4384 | 92 | StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable", | ||
4385 | 93 | StatusExpectationFailed: "Expectation Failed", | ||
4386 | 94 | StatusTeapot: "I'm a teapot", | ||
4387 | 95 | |||
4388 | 96 | StatusInternalServerError: "Internal Server Error", | ||
4389 | 97 | StatusNotImplemented: "Not Implemented", | ||
4390 | 98 | StatusBadGateway: "Bad Gateway", | ||
4391 | 99 | StatusServiceUnavailable: "Service Unavailable", | ||
4392 | 100 | StatusGatewayTimeout: "Gateway Timeout", | ||
4393 | 101 | StatusHTTPVersionNotSupported: "HTTP Version Not Supported", | ||
4394 | 102 | } | ||
4395 | 103 | |||
4396 | 104 | // StatusText returns a text for the HTTP status code. It returns the empty | ||
4397 | 105 | // string if the code is unknown. | ||
4398 | 106 | func StatusText(code int) string { | ||
4399 | 107 | return statusText[code] | ||
4400 | 108 | } | ||
4401 | 0 | 109 | ||
4402 | === added file 'fork/http/transfer.go' | |||
4403 | --- fork/http/transfer.go 1970-01-01 00:00:00 +0000 | |||
4404 | +++ fork/http/transfer.go 2013-07-22 14:27:42 +0000 | |||
4405 | @@ -0,0 +1,632 @@ | |||
4406 | 1 | // Copyright 2009 The Go Authors. All rights reserved. | ||
4407 | 2 | // Use of this source code is governed by a BSD-style | ||
4408 | 3 | // license that can be found in the LICENSE file. | ||
4409 | 4 | |||
4410 | 5 | package http | ||
4411 | 6 | |||
4412 | 7 | import ( | ||
4413 | 8 | "bufio" | ||
4414 | 9 | "bytes" | ||
4415 | 10 | "errors" | ||
4416 | 11 | "fmt" | ||
4417 | 12 | "io" | ||
4418 | 13 | "io/ioutil" | ||
4419 | 14 | "net/textproto" | ||
4420 | 15 | "strconv" | ||
4421 | 16 | "strings" | ||
4422 | 17 | ) | ||
4423 | 18 | |||
4424 | 19 | // transferWriter inspects the fields of a user-supplied Request or Response, | ||
4425 | 20 | // sanitizes them without changing the user object and provides methods for | ||
4426 | 21 | // writing the respective header, body and trailer in wire format. | ||
4427 | 22 | type transferWriter struct { | ||
4428 | 23 | Method string | ||
4429 | 24 | Body io.Reader | ||
4430 | 25 | BodyCloser io.Closer | ||
4431 | 26 | ResponseToHEAD bool | ||
4432 | 27 | ContentLength int64 // -1 means unknown, 0 means exactly none | ||
4433 | 28 | Close bool | ||
4434 | 29 | TransferEncoding []string | ||
4435 | 30 | Trailer Header | ||
4436 | 31 | } | ||
4437 | 32 | |||
4438 | 33 | func newTransferWriter(r interface{}) (t *transferWriter, err error) { | ||
4439 | 34 | t = &transferWriter{} | ||
4440 | 35 | |||
4441 | 36 | // Extract relevant fields | ||
4442 | 37 | atLeastHTTP11 := false | ||
4443 | 38 | switch rr := r.(type) { | ||
4444 | 39 | case *Request: | ||
4445 | 40 | if rr.ContentLength != 0 && rr.Body == nil { | ||
4446 | 41 | return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength) | ||
4447 | 42 | } | ||
4448 | 43 | t.Method = rr.Method | ||
4449 | 44 | t.Body = rr.Body | ||
4450 | 45 | t.BodyCloser = rr.Body | ||
4451 | 46 | t.ContentLength = rr.ContentLength | ||
4452 | 47 | t.Close = rr.Close | ||
4453 | 48 | t.TransferEncoding = rr.TransferEncoding | ||
4454 | 49 | t.Trailer = rr.Trailer | ||
4455 | 50 | atLeastHTTP11 = rr.ProtoAtLeast(1, 1) | ||
4456 | 51 | if t.Body != nil && len(t.TransferEncoding) == 0 && atLeastHTTP11 { | ||
4457 | 52 | if t.ContentLength == 0 { | ||
4458 | 53 | // Test to see if it's actually zero or just unset. | ||
4459 | 54 | var buf [1]byte | ||
4460 | 55 | n, _ := io.ReadFull(t.Body, buf[:]) | ||
4461 | 56 | if n == 1 { | ||
4462 | 57 | // Oh, guess there is data in this Body Reader after all. | ||
4463 | 58 | // The ContentLength field just wasn't set. | ||
4464 | 59 | // Stich the Body back together again, re-attaching our | ||
4465 | 60 | // consumed byte. | ||
4466 | 61 | t.ContentLength = -1 | ||
4467 | 62 | t.Body = io.MultiReader(bytes.NewBuffer(buf[:]), t.Body) | ||
4468 | 63 | } else { | ||
4469 | 64 | // Body is actually empty. | ||
4470 | 65 | t.Body = nil | ||
4471 | 66 | t.BodyCloser = nil | ||
4472 | 67 | } | ||
4473 | 68 | } | ||
4474 | 69 | if t.ContentLength < 0 { | ||
4475 | 70 | t.TransferEncoding = []string{"chunked"} | ||
4476 | 71 | } | ||
4477 | 72 | } | ||
4478 | 73 | case *Response: | ||
4479 | 74 | if rr.Request != nil { | ||
4480 | 75 | t.Method = rr.Request.Method | ||
4481 | 76 | } | ||
4482 | 77 | t.Body = rr.Body | ||
4483 | 78 | t.BodyCloser = rr.Body | ||
4484 | 79 | t.ContentLength = rr.ContentLength | ||
4485 | 80 | t.Close = rr.Close | ||
4486 | 81 | t.TransferEncoding = rr.TransferEncoding | ||
4487 | 82 | t.Trailer = rr.Trailer | ||
4488 | 83 | atLeastHTTP11 = rr.ProtoAtLeast(1, 1) | ||
4489 | 84 | t.ResponseToHEAD = noBodyExpected(t.Method) | ||
4490 | 85 | } | ||
4491 | 86 | |||
4492 | 87 | // Sanitize Body,ContentLength,TransferEncoding | ||
4493 | 88 | if t.ResponseToHEAD { | ||
4494 | 89 | t.Body = nil | ||
4495 | 90 | t.TransferEncoding = nil | ||
4496 | 91 | // ContentLength is expected to hold Content-Length | ||
4497 | 92 | if t.ContentLength < 0 { | ||
4498 | 93 | return nil, ErrMissingContentLength | ||
4499 | 94 | } | ||
4500 | 95 | } else { | ||
4501 | 96 | if !atLeastHTTP11 || t.Body == nil { | ||
4502 | 97 | t.TransferEncoding = nil | ||
4503 | 98 | } | ||
4504 | 99 | if chunked(t.TransferEncoding) { | ||
4505 | 100 | t.ContentLength = -1 | ||
4506 | 101 | } else if t.Body == nil { // no chunking, no body | ||
4507 | 102 | t.ContentLength = 0 | ||
4508 | 103 | } | ||
4509 | 104 | } | ||
4510 | 105 | |||
4511 | 106 | // Sanitize Trailer | ||
4512 | 107 | if !chunked(t.TransferEncoding) { | ||
4513 | 108 | t.Trailer = nil | ||
4514 | 109 | } | ||
4515 | 110 | |||
4516 | 111 | return t, nil | ||
4517 | 112 | } | ||
4518 | 113 | |||
4519 | 114 | func noBodyExpected(requestMethod string) bool { | ||
4520 | 115 | return requestMethod == "HEAD" | ||
4521 | 116 | } | ||
4522 | 117 | |||
4523 | 118 | func (t *transferWriter) shouldSendContentLength() bool { | ||
4524 | 119 | if chunked(t.TransferEncoding) { | ||
4525 | 120 | return false | ||
4526 | 121 | } | ||
4527 | 122 | if t.ContentLength > 0 { | ||
4528 | 123 | return true | ||
4529 | 124 | } | ||
4530 | 125 | if t.ResponseToHEAD { | ||
4531 | 126 | return true | ||
4532 | 127 | } | ||
4533 | 128 | // Many servers expect a Content-Length for these methods | ||
4534 | 129 | if t.Method == "POST" || t.Method == "PUT" { | ||
4535 | 130 | return true | ||
4536 | 131 | } | ||
4537 | 132 | if t.ContentLength == 0 && isIdentity(t.TransferEncoding) { | ||
4538 | 133 | return true | ||
4539 | 134 | } | ||
4540 | 135 | |||
4541 | 136 | return false | ||
4542 | 137 | } | ||
4543 | 138 | |||
4544 | 139 | func (t *transferWriter) WriteHeader(w io.Writer) (err error) { | ||
4545 | 140 | if t.Close { | ||
4546 | 141 | _, err = io.WriteString(w, "Connection: close\r\n") | ||
4547 | 142 | if err != nil { | ||
4548 | 143 | return | ||
4549 | 144 | } | ||
4550 | 145 | } | ||
4551 | 146 | |||
4552 | 147 | // Write Content-Length and/or Transfer-Encoding whose values are a | ||
4553 | 148 | // function of the sanitized field triple (Body, ContentLength, | ||
4554 | 149 | // TransferEncoding) | ||
4555 | 150 | if t.shouldSendContentLength() { | ||
4556 | 151 | io.WriteString(w, "Content-Length: ") | ||
4557 | 152 | _, err = io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n") | ||
4558 | 153 | if err != nil { | ||
4559 | 154 | return | ||
4560 | 155 | } | ||
4561 | 156 | } else if chunked(t.TransferEncoding) { | ||
4562 | 157 | _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n") | ||
4563 | 158 | if err != nil { | ||
4564 | 159 | return | ||
4565 | 160 | } | ||
4566 | 161 | } | ||
4567 | 162 | |||
4568 | 163 | // Write Trailer header | ||
4569 | 164 | if t.Trailer != nil { | ||
4570 | 165 | // TODO: At some point, there should be a generic mechanism for | ||
4571 | 166 | // writing long headers, using HTTP line splitting | ||
4572 | 167 | io.WriteString(w, "Trailer: ") | ||
4573 | 168 | needComma := false | ||
4574 | 169 | for k := range t.Trailer { | ||
4575 | 170 | k = CanonicalHeaderKey(k) | ||
4576 | 171 | switch k { | ||
4577 | 172 | case "Transfer-Encoding", "Trailer", "Content-Length": | ||
4578 | 173 | return &badStringError{"invalid Trailer key", k} | ||
4579 | 174 | } | ||
4580 | 175 | if needComma { | ||
4581 | 176 | io.WriteString(w, ",") | ||
4582 | 177 | } | ||
4583 | 178 | io.WriteString(w, k) | ||
4584 | 179 | needComma = true | ||
4585 | 180 | } | ||
4586 | 181 | _, err = io.WriteString(w, "\r\n") | ||
4587 | 182 | } | ||
4588 | 183 | |||
4589 | 184 | return | ||
4590 | 185 | } | ||
4591 | 186 | |||
4592 | 187 | func (t *transferWriter) WriteBody(w io.Writer) (err error) { | ||
4593 | 188 | var ncopy int64 | ||
4594 | 189 | |||
4595 | 190 | // Write body | ||
4596 | 191 | if t.Body != nil { | ||
4597 | 192 | if chunked(t.TransferEncoding) { | ||
4598 | 193 | cw := newChunkedWriter(w) | ||
4599 | 194 | _, err = io.Copy(cw, t.Body) | ||
4600 | 195 | if err == nil { | ||
4601 | 196 | err = cw.Close() | ||
4602 | 197 | } | ||
4603 | 198 | } else if t.ContentLength == -1 { | ||
4604 | 199 | ncopy, err = io.Copy(w, t.Body) | ||
4605 | 200 | } else { | ||
4606 | 201 | ncopy, err = io.Copy(w, io.LimitReader(t.Body, t.ContentLength)) | ||
4607 | 202 | nextra, err := io.Copy(ioutil.Discard, t.Body) | ||
4608 | 203 | if err != nil { | ||
4609 | 204 | return err | ||
4610 | 205 | } | ||
4611 | 206 | ncopy += nextra | ||
4612 | 207 | } | ||
4613 | 208 | if err != nil { | ||
4614 | 209 | return err | ||
4615 | 210 | } | ||
4616 | 211 | if err = t.BodyCloser.Close(); err != nil { | ||
4617 | 212 | return err | ||
4618 | 213 | } | ||
4619 | 214 | } | ||
4620 | 215 | |||
4621 | 216 | if t.ContentLength != -1 && t.ContentLength != ncopy { | ||
4622 | 217 | return fmt.Errorf("http: Request.ContentLength=%d with Body length %d", | ||
4623 | 218 | t.ContentLength, ncopy) | ||
4624 | 219 | } | ||
4625 | 220 | |||
4626 | 221 | // TODO(petar): Place trailer writer code here. | ||
4627 | 222 | if chunked(t.TransferEncoding) { | ||
4628 | 223 | // Last chunk, empty trailer | ||
4629 | 224 | _, err = io.WriteString(w, "\r\n") | ||
4630 | 225 | } | ||
4631 | 226 | |||
4632 | 227 | return | ||
4633 | 228 | } | ||
4634 | 229 | |||
4635 | 230 | type transferReader struct { | ||
4636 | 231 | // Input | ||
4637 | 232 | Header Header | ||
4638 | 233 | StatusCode int | ||
4639 | 234 | RequestMethod string | ||
4640 | 235 | ProtoMajor int | ||
4641 | 236 | ProtoMinor int | ||
4642 | 237 | // Output | ||
4643 | 238 | Body io.ReadCloser | ||
4644 | 239 | ContentLength int64 | ||
4645 | 240 | TransferEncoding []string | ||
4646 | 241 | Close bool | ||
4647 | 242 | Trailer Header | ||
4648 | 243 | } | ||
4649 | 244 | |||
4650 | 245 | // bodyAllowedForStatus returns whether a given response status code | ||
4651 | 246 | // permits a body. See RFC2616, section 4.4. | ||
4652 | 247 | func bodyAllowedForStatus(status int) bool { | ||
4653 | 248 | switch { | ||
4654 | 249 | case status >= 100 && status <= 199: | ||
4655 | 250 | return false | ||
4656 | 251 | case status == 204: | ||
4657 | 252 | return false | ||
4658 | 253 | case status == 304: | ||
4659 | 254 | return false | ||
4660 | 255 | } | ||
4661 | 256 | return true | ||
4662 | 257 | } | ||
4663 | 258 | |||
4664 | 259 | // msg is *Request or *Response. | ||
4665 | 260 | func readTransfer(msg interface{}, r *bufio.Reader) (err error) { | ||
4666 | 261 | t := &transferReader{} | ||
4667 | 262 | |||
4668 | 263 | // Unify input | ||
4669 | 264 | isResponse := false | ||
4670 | 265 | switch rr := msg.(type) { | ||
4671 | 266 | case *Response: | ||
4672 | 267 | t.Header = rr.Header | ||
4673 | 268 | t.StatusCode = rr.StatusCode | ||
4674 | 269 | t.RequestMethod = rr.Request.Method | ||
4675 | 270 | t.ProtoMajor = rr.ProtoMajor | ||
4676 | 271 | t.ProtoMinor = rr.ProtoMinor | ||
4677 | 272 | t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header) | ||
4678 | 273 | isResponse = true | ||
4679 | 274 | case *Request: | ||
4680 | 275 | t.Header = rr.Header | ||
4681 | 276 | t.ProtoMajor = rr.ProtoMajor | ||
4682 | 277 | t.ProtoMinor = rr.ProtoMinor | ||
4683 | 278 | // Transfer semantics for Requests are exactly like those for | ||
4684 | 279 | // Responses with status code 200, responding to a GET method | ||
4685 | 280 | t.StatusCode = 200 | ||
4686 | 281 | t.RequestMethod = "GET" | ||
4687 | 282 | default: | ||
4688 | 283 | panic("unexpected type") | ||
4689 | 284 | } | ||
4690 | 285 | |||
4691 | 286 | // Default to HTTP/1.1 | ||
4692 | 287 | if t.ProtoMajor == 0 && t.ProtoMinor == 0 { | ||
4693 | 288 | t.ProtoMajor, t.ProtoMinor = 1, 1 | ||
4694 | 289 | } | ||
4695 | 290 | |||
4696 | 291 | // Transfer encoding, content length | ||
4697 | 292 | t.TransferEncoding, err = fixTransferEncoding(t.RequestMethod, t.Header) | ||
4698 | 293 | if err != nil { | ||
4699 | 294 | return err | ||
4700 | 295 | } | ||
4701 | 296 | |||
4702 | 297 | t.ContentLength, err = fixLength(isResponse, t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding) | ||
4703 | 298 | if err != nil { | ||
4704 | 299 | return err | ||
4705 | 300 | } | ||
4706 | 301 | |||
4707 | 302 | // Trailer | ||
4708 | 303 | t.Trailer, err = fixTrailer(t.Header, t.TransferEncoding) | ||
4709 | 304 | if err != nil { | ||
4710 | 305 | return err | ||
4711 | 306 | } | ||
4712 | 307 | |||
4713 | 308 | // If there is no Content-Length or chunked Transfer-Encoding on a *Response | ||
4714 | 309 | // and the status is not 1xx, 204 or 304, then the body is unbounded. | ||
4715 | 310 | // See RFC2616, section 4.4. | ||
4716 | 311 | switch msg.(type) { | ||
4717 | 312 | case *Response: | ||
4718 | 313 | if t.ContentLength == -1 && | ||
4719 | 314 | !chunked(t.TransferEncoding) && | ||
4720 | 315 | bodyAllowedForStatus(t.StatusCode) { | ||
4721 | 316 | // Unbounded body. | ||
4722 | 317 | t.Close = true | ||
4723 | 318 | } | ||
4724 | 319 | } | ||
4725 | 320 | |||
4726 | 321 | // Prepare body reader. ContentLength < 0 means chunked encoding | ||
4727 | 322 | // or close connection when finished, since multipart is not supported yet | ||
4728 | 323 | switch { | ||
4729 | 324 | case chunked(t.TransferEncoding): | ||
4730 | 325 | t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close} | ||
4731 | 326 | case t.ContentLength >= 0: | ||
4732 | 327 | // TODO: limit the Content-Length. This is an easy DoS vector. | ||
4733 | 328 | t.Body = &body{Reader: io.LimitReader(r, t.ContentLength), closing: t.Close} | ||
4734 | 329 | default: | ||
4735 | 330 | // t.ContentLength < 0, i.e. "Content-Length" not mentioned in header | ||
4736 | 331 | if t.Close { | ||
4737 | 332 | // Close semantics (i.e. HTTP/1.0) | ||
4738 | 333 | t.Body = &body{Reader: r, closing: t.Close} | ||
4739 | 334 | } else { | ||
4740 | 335 | // Persistent connection (i.e. HTTP/1.1) | ||
4741 | 336 | t.Body = &body{Reader: io.LimitReader(r, 0), closing: t.Close} | ||
4742 | 337 | } | ||
4743 | 338 | } | ||
4744 | 339 | |||
4745 | 340 | // Unify output | ||
4746 | 341 | switch rr := msg.(type) { | ||
4747 | 342 | case *Request: | ||
4748 | 343 | rr.Body = t.Body | ||
4749 | 344 | rr.ContentLength = t.ContentLength | ||
4750 | 345 | rr.TransferEncoding = t.TransferEncoding | ||
4751 | 346 | rr.Close = t.Close | ||
4752 | 347 | rr.Trailer = t.Trailer | ||
4753 | 348 | case *Response: | ||
4754 | 349 | rr.Body = t.Body | ||
4755 | 350 | rr.ContentLength = t.ContentLength | ||
4756 | 351 | rr.TransferEncoding = t.TransferEncoding | ||
4757 | 352 | rr.Close = t.Close | ||
4758 | 353 | rr.Trailer = t.Trailer | ||
4759 | 354 | } | ||
4760 | 355 | |||
4761 | 356 | return nil | ||
4762 | 357 | } | ||
4763 | 358 | |||
4764 | 359 | // Checks whether chunked is part of the encodings stack | ||
4765 | 360 | func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" } | ||
4766 | 361 | |||
4767 | 362 | // Checks whether the encoding is explicitly "identity". | ||
4768 | 363 | func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" } | ||
4769 | 364 | |||
4770 | 365 | // Sanitize transfer encoding | ||
4771 | 366 | func fixTransferEncoding(requestMethod string, header Header) ([]string, error) { | ||
4772 | 367 | raw, present := header["Transfer-Encoding"] | ||
4773 | 368 | if !present { | ||
4774 | 369 | return nil, nil | ||
4775 | 370 | } | ||
4776 | 371 | |||
4777 | 372 | delete(header, "Transfer-Encoding") | ||
4778 | 373 | |||
4779 | 374 | // Head responses have no bodies, so the transfer encoding | ||
4780 | 375 | // should be ignored. | ||
4781 | 376 | if requestMethod == "HEAD" { | ||
4782 | 377 | return nil, nil | ||
4783 | 378 | } | ||
4784 | 379 | |||
4785 | 380 | encodings := strings.Split(raw[0], ",") | ||
4786 | 381 | te := make([]string, 0, len(encodings)) | ||
4787 | 382 | // TODO: Even though we only support "identity" and "chunked" | ||
4788 | 383 | // encodings, the loop below is designed with foresight. One | ||
4789 | 384 | // invariant that must be maintained is that, if present, | ||
4790 | 385 | // chunked encoding must always come first. | ||
4791 | 386 | for _, encoding := range encodings { | ||
4792 | 387 | encoding = strings.ToLower(strings.TrimSpace(encoding)) | ||
4793 | 388 | // "identity" encoding is not recorded | ||
4794 | 389 | if encoding == "identity" { | ||
4795 | 390 | break | ||
4796 | 391 | } | ||
4797 | 392 | if encoding != "chunked" { | ||
4798 | 393 | return nil, &badStringError{"unsupported transfer encoding", encoding} | ||
4799 | 394 | } | ||
4800 | 395 | te = te[0 : len(te)+1] | ||
4801 | 396 | te[len(te)-1] = encoding | ||
4802 | 397 | } | ||
4803 | 398 | if len(te) > 1 { | ||
4804 | 399 | return nil, &badStringError{"too many transfer encodings", strings.Join(te, ",")} | ||
4805 | 400 | } | ||
4806 | 401 | if len(te) > 0 { | ||
4807 | 402 | // Chunked encoding trumps Content-Length. See RFC 2616 | ||
4808 | 403 | // Section 4.4. Currently len(te) > 0 implies chunked | ||
4809 | 404 | // encoding. | ||
4810 | 405 | delete(header, "Content-Length") | ||
4811 | 406 | return te, nil | ||
4812 | 407 | } | ||
4813 | 408 | |||
4814 | 409 | return nil, nil | ||
4815 | 410 | } | ||
4816 | 411 | |||
4817 | 412 | // Determine the expected body length, using RFC 2616 Section 4.4. This | ||
4818 | 413 | // function is not a method, because ultimately it should be shared by | ||
4819 | 414 | // ReadResponse and ReadRequest. | ||
4820 | 415 | func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, error) { | ||
4821 | 416 | |||
4822 | 417 | // Logic based on response type or status | ||
4823 | 418 | if noBodyExpected(requestMethod) { | ||
4824 | 419 | return 0, nil | ||
4825 | 420 | } | ||
4826 | 421 | if status/100 == 1 { | ||
4827 | 422 | return 0, nil | ||
4828 | 423 | } | ||
4829 | 424 | switch status { | ||
4830 | 425 | case 204, 304: | ||
4831 | 426 | return 0, nil | ||
4832 | 427 | } | ||
4833 | 428 | |||
4834 | 429 | // Logic based on Transfer-Encoding | ||
4835 | 430 | if chunked(te) { | ||
4836 | 431 | return -1, nil | ||
4837 | 432 | } | ||
4838 | 433 | |||
4839 | 434 | // Logic based on Content-Length | ||
4840 | 435 | cl := strings.TrimSpace(header.Get("Content-Length")) | ||
4841 | 436 | if cl != "" { | ||
4842 | 437 | n, err := strconv.ParseInt(cl, 10, 64) | ||
4843 | 438 | if err != nil || n < 0 { | ||
4844 | 439 | return -1, &badStringError{"bad Content-Length", cl} | ||
4845 | 440 | } | ||
4846 | 441 | return n, nil | ||
4847 | 442 | } else { | ||
4848 | 443 | header.Del("Content-Length") | ||
4849 | 444 | } | ||
4850 | 445 | |||
4851 | 446 | if !isResponse && requestMethod == "GET" { | ||
4852 | 447 | // RFC 2616 doesn't explicitly permit nor forbid an | ||
4853 | 448 | // entity-body on a GET request so we permit one if | ||
4854 | 449 | // declared, but we default to 0 here (not -1 below) | ||
4855 | 450 | // if there's no mention of a body. | ||
4856 | 451 | return 0, nil | ||
4857 | 452 | } | ||
4858 | 453 | |||
4859 | 454 | // Logic based on media type. The purpose of the following code is just | ||
4860 | 455 | // to detect whether the unsupported "multipart/byteranges" is being | ||
4861 | 456 | // used. A proper Content-Type parser is needed in the future. | ||
4862 | 457 | if strings.Contains(strings.ToLower(header.Get("Content-Type")), "multipart/byteranges") { | ||
4863 | 458 | return -1, ErrNotSupported | ||
4864 | 459 | } | ||
4865 | 460 | |||
4866 | 461 | // Body-EOF logic based on other methods (like closing, or chunked coding) | ||
4867 | 462 | return -1, nil | ||
4868 | 463 | } | ||
4869 | 464 | |||
4870 | 465 | // Determine whether to hang up after sending a request and body, or | ||
4871 | 466 | // receiving a response and body | ||
4872 | 467 | // 'header' is the request headers | ||
4873 | 468 | func shouldClose(major, minor int, header Header) bool { | ||
4874 | 469 | if major < 1 { | ||
4875 | 470 | return true | ||
4876 | 471 | } else if major == 1 && minor == 0 { | ||
4877 | 472 | if !strings.Contains(strings.ToLower(header.Get("Connection")), "keep-alive") { | ||
4878 | 473 | return true | ||
4879 | 474 | } | ||
4880 | 475 | return false | ||
4881 | 476 | } else { | ||
4882 | 477 | // TODO: Should split on commas, toss surrounding white space, | ||
4883 | 478 | // and check each field. | ||
4884 | 479 | if strings.ToLower(header.Get("Connection")) == "close" { | ||
4885 | 480 | header.Del("Connection") | ||
4886 | 481 | return true | ||
4887 | 482 | } | ||
4888 | 483 | } | ||
4889 | 484 | return false | ||
4890 | 485 | } | ||
4891 | 486 | |||
4892 | 487 | // Parse the trailer header | ||
4893 | 488 | func fixTrailer(header Header, te []string) (Header, error) { | ||
4894 | 489 | raw := header.Get("Trailer") | ||
4895 | 490 | if raw == "" { | ||
4896 | 491 | return nil, nil | ||
4897 | 492 | } | ||
4898 | 493 | |||
4899 | 494 | header.Del("Trailer") | ||
4900 | 495 | trailer := make(Header) | ||
4901 | 496 | keys := strings.Split(raw, ",") | ||
4902 | 497 | for _, key := range keys { | ||
4903 | 498 | key = CanonicalHeaderKey(strings.TrimSpace(key)) | ||
4904 | 499 | switch key { | ||
4905 | 500 | case "Transfer-Encoding", "Trailer", "Content-Length": | ||
4906 | 501 | return nil, &badStringError{"bad trailer key", key} | ||
4907 | 502 | } | ||
4908 | 503 | trailer.Del(key) | ||
4909 | 504 | } | ||
4910 | 505 | if len(trailer) == 0 { | ||
4911 | 506 | return nil, nil | ||
4912 | 507 | } | ||
4913 | 508 | if !chunked(te) { | ||
4914 | 509 | // Trailer and no chunking | ||
4915 | 510 | return nil, ErrUnexpectedTrailer | ||
4916 | 511 | } | ||
4917 | 512 | return trailer, nil | ||
4918 | 513 | } | ||
4919 | 514 | |||
4920 | 515 | // body turns a Reader into a ReadCloser. | ||
4921 | 516 | // Close ensures that the body has been fully read | ||
4922 | 517 | // and then reads the trailer if necessary. | ||
4923 | 518 | type body struct { | ||
4924 | 519 | io.Reader | ||
4925 | 520 | hdr interface{} // non-nil (Response or Request) value means read trailer | ||
4926 | 521 | r *bufio.Reader // underlying wire-format reader for the trailer | ||
4927 | 522 | closing bool // is the connection to be closed after reading body? | ||
4928 | 523 | closed bool | ||
4929 | 524 | |||
4930 | 525 | res *response // response writer for server requests, else nil | ||
4931 | 526 | } | ||
4932 | 527 | |||
4933 | 528 | // ErrBodyReadAfterClose is returned when reading a Request Body after | ||
4934 | 529 | // the body has been closed. This typically happens when the body is | ||
4935 | 530 | // read after an HTTP Handler calls WriteHeader or Write on its | ||
4936 | 531 | // ResponseWriter. | ||
4937 | 532 | var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed request Body") | ||
4938 | 533 | |||
4939 | 534 | func (b *body) Read(p []byte) (n int, err error) { | ||
4940 | 535 | if b.closed { | ||
4941 | 536 | return 0, ErrBodyReadAfterClose | ||
4942 | 537 | } | ||
4943 | 538 | n, err = b.Reader.Read(p) | ||
4944 | 539 | |||
4945 | 540 | // Read the final trailer once we hit EOF. | ||
4946 | 541 | if err == io.EOF && b.hdr != nil { | ||
4947 | 542 | if e := b.readTrailer(); e != nil { | ||
4948 | 543 | err = e | ||
4949 | 544 | } | ||
4950 | 545 | b.hdr = nil | ||
4951 | 546 | } | ||
4952 | 547 | return n, err | ||
4953 | 548 | } | ||
4954 | 549 | |||
4955 | 550 | var ( | ||
4956 | 551 | singleCRLF = []byte("\r\n") | ||
4957 | 552 | doubleCRLF = []byte("\r\n\r\n") | ||
4958 | 553 | ) | ||
4959 | 554 | |||
4960 | 555 | func seeUpcomingDoubleCRLF(r *bufio.Reader) bool { | ||
4961 | 556 | for peekSize := 4; ; peekSize++ { | ||
4962 | 557 | // This loop stops when Peek returns an error, | ||
4963 | 558 | // which it does when r's buffer has been filled. | ||
4964 | 559 | buf, err := r.Peek(peekSize) | ||
4965 | 560 | if bytes.HasSuffix(buf, doubleCRLF) { | ||
4966 | 561 | return true | ||
4967 | 562 | } | ||
4968 | 563 | if err != nil { | ||
4969 | 564 | break | ||
4970 | 565 | } | ||
4971 | 566 | } | ||
4972 | 567 | return false | ||
4973 | 568 | } | ||
4974 | 569 | |||
4975 | 570 | func (b *body) readTrailer() error { | ||
4976 | 571 | // The common case, since nobody uses trailers. | ||
4977 | 572 | buf, _ := b.r.Peek(2) | ||
4978 | 573 | if bytes.Equal(buf, singleCRLF) { | ||
4979 | 574 | b.r.ReadByte() | ||
4980 | 575 | b.r.ReadByte() | ||
4981 | 576 | return nil | ||
4982 | 577 | } | ||
4983 | 578 | |||
4984 | 579 | // Make sure there's a header terminator coming up, to prevent | ||
4985 | 580 | // a DoS with an unbounded size Trailer. It's not easy to | ||
4986 | 581 | // slip in a LimitReader here, as textproto.NewReader requires | ||
4987 | 582 | // a concrete *bufio.Reader. Also, we can't get all the way | ||
4988 | 583 | // back up to our conn's LimitedReader that *might* be backing | ||
4989 | 584 | // this bufio.Reader. Instead, a hack: we iteratively Peek up | ||
4990 | 585 | // to the bufio.Reader's max size, looking for a double CRLF. | ||
4991 | 586 | // This limits the trailer to the underlying buffer size, typically 4kB. | ||
4992 | 587 | if !seeUpcomingDoubleCRLF(b.r) { | ||
4993 | 588 | return errors.New("http: suspiciously long trailer after chunked body") | ||
4994 | 589 | } | ||
4995 | 590 | |||
4996 | 591 | hdr, err := textproto.NewReader(b.r).ReadMIMEHeader() | ||
4997 | 592 | if err != nil { | ||
4998 | 593 | return err | ||
4999 | 594 | } | ||
5000 | 595 | switch rr := b.hdr.(type) { |
Looks good!
[1]
--- fork/README 1970-01-01 00:00:00 +0000
+++ fork/README 2013-07-22 12:54:30 +0000
@@ -0,0 +1,7 @@
+This directory contains a fork of Go's standard libraries net/http and crypto/tls.
...
Please wrap lines in here at no more than 80 columns. I suggest 72.
[2]
=== added file 'fork/go- use-patched- tls.patch' use-patched- tls.patch 1970-01-01 00:00:00 +0000 use-patched- tls.patch 2013-07-22 13:11:27 +0000 net/gwacl/ fork/tls"
--- fork/go-
+++ fork/go-
@@ -0,0 +1,5 @@
+15c15
+< "launchpad.
+---
+> "crypto/tls"
+
I'm not sure this is useful. Without context it's not very
informative. It's also in the wrong direction. I suggest omitting it.
[3]
+func performX509Requ est(session *x509Session, request *X509Request) (*x509Response, error) {
...
+ response.Header = httpResponse.Header
+ if err != nil {
+ return nil, err
+ }
I don't think that condition is needed here. Could this be one of confuses- DVCS moments?
those Go-boilerplate-