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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [mime/] [multipart/] [multipart.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2010 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
//
5
 
6
/*
7
Package multipart implements MIME multipart parsing, as defined in RFC
8
2046.
9
 
10
The implementation is sufficient for HTTP (RFC 2388) and the multipart
11
bodies generated by popular browsers.
12
*/
13
package multipart
14
 
15
import (
16
        "bufio"
17
        "bytes"
18
        "fmt"
19
        "io"
20
        "io/ioutil"
21
        "mime"
22
        "net/textproto"
23
)
24
 
25
// TODO(bradfitz): inline these once the compiler can inline them in
26
// read-only situation (such as bytes.HasSuffix)
27
var lf = []byte("\n")
28
var crlf = []byte("\r\n")
29
 
30
var emptyParams = make(map[string]string)
31
 
32
// A Part represents a single part in a multipart body.
33
type Part struct {
34
        // The headers of the body, if any, with the keys canonicalized
35
        // in the same fashion that the Go http.Request headers are.
36
        // i.e. "foo-bar" changes case to "Foo-Bar"
37
        Header textproto.MIMEHeader
38
 
39
        buffer *bytes.Buffer
40
        mr     *Reader
41
 
42
        disposition       string
43
        dispositionParams map[string]string
44
}
45
 
46
// FormName returns the name parameter if p has a Content-Disposition
47
// of type "form-data".  Otherwise it returns the empty string.
48
func (p *Part) FormName() string {
49
        // See http://tools.ietf.org/html/rfc2183 section 2 for EBNF
50
        // of Content-Disposition value format.
51
        if p.dispositionParams == nil {
52
                p.parseContentDisposition()
53
        }
54
        if p.disposition != "form-data" {
55
                return ""
56
        }
57
        return p.dispositionParams["name"]
58
}
59
 
60
// FileName returns the filename parameter of the Part's
61
// Content-Disposition header.
62
func (p *Part) FileName() string {
63
        if p.dispositionParams == nil {
64
                p.parseContentDisposition()
65
        }
66
        return p.dispositionParams["filename"]
67
}
68
 
69
func (p *Part) parseContentDisposition() {
70
        v := p.Header.Get("Content-Disposition")
71
        var err error
72
        p.disposition, p.dispositionParams, err = mime.ParseMediaType(v)
73
        if err != nil {
74
                p.dispositionParams = emptyParams
75
        }
76
}
77
 
78
// NewReader creates a new multipart Reader reading from r using the
79
// given MIME boundary.
80
func NewReader(reader io.Reader, boundary string) *Reader {
81
        b := []byte("\r\n--" + boundary + "--")
82
        return &Reader{
83
                bufReader: bufio.NewReader(reader),
84
 
85
                nl:               b[:2],
86
                nlDashBoundary:   b[:len(b)-2],
87
                dashBoundaryDash: b[2:],
88
                dashBoundary:     b[2 : len(b)-2],
89
        }
90
}
91
 
92
func newPart(mr *Reader) (*Part, error) {
93
        bp := &Part{
94
                Header: make(map[string][]string),
95
                mr:     mr,
96
                buffer: new(bytes.Buffer),
97
        }
98
        if err := bp.populateHeaders(); err != nil {
99
                return nil, err
100
        }
101
        return bp, nil
102
}
103
 
104
func (bp *Part) populateHeaders() error {
105
        r := textproto.NewReader(bp.mr.bufReader)
106
        header, err := r.ReadMIMEHeader()
107
        if err == nil {
108
                bp.Header = header
109
        }
110
        return err
111
}
112
 
113
// Read reads the body of a part, after its headers and before the
114
// next part (if any) begins.
115
func (p *Part) Read(d []byte) (n int, err error) {
116
        if p.buffer.Len() >= len(d) {
117
                // Internal buffer of unconsumed data is large enough for
118
                // the read request.  No need to parse more at the moment.
119
                return p.buffer.Read(d)
120
        }
121
        peek, err := p.mr.bufReader.Peek(4096) // TODO(bradfitz): add buffer size accessor
122
        unexpectedEof := err == io.EOF
123
        if err != nil && !unexpectedEof {
124
                return 0, fmt.Errorf("multipart: Part Read: %v", err)
125
        }
126
        if peek == nil {
127
                panic("nil peek buf")
128
        }
129
 
130
        // Search the peek buffer for "\r\n--boundary". If found,
131
        // consume everything up to the boundary. If not, consume only
132
        // as much of the peek buffer as cannot hold the boundary
133
        // string.
134
        nCopy := 0
135
        foundBoundary := false
136
        if idx := bytes.Index(peek, p.mr.nlDashBoundary); idx != -1 {
137
                nCopy = idx
138
                foundBoundary = true
139
        } else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 {
140
                nCopy = safeCount
141
        } else if unexpectedEof {
142
                // If we've run out of peek buffer and the boundary
143
                // wasn't found (and can't possibly fit), we must have
144
                // hit the end of the file unexpectedly.
145
                return 0, io.ErrUnexpectedEOF
146
        }
147
        if nCopy > 0 {
148
                if _, err := io.CopyN(p.buffer, p.mr.bufReader, int64(nCopy)); err != nil {
149
                        return 0, err
150
                }
151
        }
152
        n, err = p.buffer.Read(d)
153
        if err == io.EOF && !foundBoundary {
154
                // If the boundary hasn't been reached there's more to
155
                // read, so don't pass through an EOF from the buffer
156
                err = nil
157
        }
158
        return
159
}
160
 
161
func (p *Part) Close() error {
162
        io.Copy(ioutil.Discard, p)
163
        return nil
164
}
165
 
166
// Reader is an iterator over parts in a MIME multipart body.
167
// Reader's underlying parser consumes its input as needed.  Seeking
168
// isn't supported.
169
type Reader struct {
170
        bufReader *bufio.Reader
171
 
172
        currentPart *Part
173
        partsRead   int
174
 
175
        nl, nlDashBoundary, dashBoundaryDash, dashBoundary []byte
176
}
177
 
178
// NextPart returns the next part in the multipart or an error.
179
// When there are no more parts, the error io.EOF is returned.
180
func (r *Reader) NextPart() (*Part, error) {
181
        if r.currentPart != nil {
182
                r.currentPart.Close()
183
        }
184
 
185
        expectNewPart := false
186
        for {
187
                line, err := r.bufReader.ReadSlice('\n')
188
                if err != nil {
189
                        return nil, fmt.Errorf("multipart: NextPart: %v", err)
190
                }
191
 
192
                if r.isBoundaryDelimiterLine(line) {
193
                        r.partsRead++
194
                        bp, err := newPart(r)
195
                        if err != nil {
196
                                return nil, err
197
                        }
198
                        r.currentPart = bp
199
                        return bp, nil
200
                }
201
 
202
                if hasPrefixThenNewline(line, r.dashBoundaryDash) {
203
                        // Expected EOF
204
                        return nil, io.EOF
205
                }
206
 
207
                if expectNewPart {
208
                        return nil, fmt.Errorf("multipart: expecting a new Part; got line %q", string(line))
209
                }
210
 
211
                if r.partsRead == 0 {
212
                        // skip line
213
                        continue
214
                }
215
 
216
                // Consume the "\n" or "\r\n" separator between the
217
                // body of the previous part and the boundary line we
218
                // now expect will follow. (either a new part or the
219
                // end boundary)
220
                if bytes.Equal(line, r.nl) {
221
                        expectNewPart = true
222
                        continue
223
                }
224
 
225
                return nil, fmt.Errorf("multipart: unexpected line in Next(): %q", line)
226
        }
227
        panic("unreachable")
228
}
229
 
230
func (mr *Reader) isBoundaryDelimiterLine(line []byte) bool {
231
        // http://tools.ietf.org/html/rfc2046#section-5.1
232
        //   The boundary delimiter line is then defined as a line
233
        //   consisting entirely of two hyphen characters ("-",
234
        //   decimal value 45) followed by the boundary parameter
235
        //   value from the Content-Type header field, optional linear
236
        //   whitespace, and a terminating CRLF.
237
        if !bytes.HasPrefix(line, mr.dashBoundary) {
238
                return false
239
        }
240
        if bytes.HasSuffix(line, mr.nl) {
241
                return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-len(mr.nl)])
242
        }
243
        // Violate the spec and also support newlines without the
244
        // carriage return...
245
        if mr.partsRead == 0 && bytes.HasSuffix(line, lf) {
246
                if onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-1]) {
247
                        mr.nl = mr.nl[1:]
248
                        mr.nlDashBoundary = mr.nlDashBoundary[1:]
249
                        return true
250
                }
251
        }
252
        return false
253
}
254
 
255
func onlyHorizontalWhitespace(s []byte) bool {
256
        for _, b := range s {
257
                if b != ' ' && b != '\t' {
258
                        return false
259
                }
260
        }
261
        return true
262
}
263
 
264
func hasPrefixThenNewline(s, prefix []byte) bool {
265
        return bytes.HasPrefix(s, prefix) &&
266
                (len(s) == len(prefix)+1 && s[len(s)-1] == '\n' ||
267
                        len(s) == len(prefix)+2 && bytes.HasSuffix(s, crlf))
268
}

powered by: WebSVN 2.1.0

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