~ubuntu-branches/ubuntu/saucy/golang/saucy

« back to all changes in this revision

Viewing changes to src/pkg/mime/multipart/multipart.go

  • Committer: Package Import Robot
  • Author(s): Ondřej Surý, Ondřej Surý, Michael Stapelberg
  • Date: 2012-06-28 12:14:15 UTC
  • mfrom: (1.1.15)
  • Revision ID: package-import@ubuntu.com-20120628121415-w1b0076ixkarr1ml
[ Ondřej Surý ]
* Imported Upstream version 1.0.2
* Update Vcs fields to reflect new git repository location
* Kill get-orig-source, since 1.0.0, the tarballs can be downloaded
  from webpage

[ Michael Stapelberg ]
* golang-mode: use debian-pkg-add-load-path-item (Closes: #664802)
* Add manpages (Closes: #632964)
* Use updated pt.po from Pedro Ribeiro (Closes: #674958)

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
        "net/textproto"
23
23
)
24
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
25
var emptyParams = make(map[string]string)
31
26
 
32
27
// A Part represents a single part in a multipart body.
36
31
        // i.e. "foo-bar" changes case to "Foo-Bar"
37
32
        Header textproto.MIMEHeader
38
33
 
39
 
        buffer *bytes.Buffer
40
 
        mr     *Reader
 
34
        buffer    *bytes.Buffer
 
35
        mr        *Reader
 
36
        bytesRead int
41
37
 
42
38
        disposition       string
43
39
        dispositionParams map[string]string
113
109
// Read reads the body of a part, after its headers and before the
114
110
// next part (if any) begins.
115
111
func (p *Part) Read(d []byte) (n int, err error) {
 
112
        defer func() {
 
113
                p.bytesRead += n
 
114
        }()
116
115
        if p.buffer.Len() >= len(d) {
117
116
                // Internal buffer of unconsumed data is large enough for
118
117
                // the read request.  No need to parse more at the moment.
119
118
                return p.buffer.Read(d)
120
119
        }
121
120
        peek, err := p.mr.bufReader.Peek(4096) // TODO(bradfitz): add buffer size accessor
122
 
        unexpectedEof := err == io.EOF
123
 
        if err != nil && !unexpectedEof {
 
121
 
 
122
        // Look for an immediate empty part without a leading \r\n
 
123
        // before the boundary separator.  Some MIME code makes empty
 
124
        // parts like this. Most browsers, however, write the \r\n
 
125
        // before the subsequent boundary even for empty parts and
 
126
        // won't hit this path.
 
127
        if p.bytesRead == 0 && p.mr.peekBufferIsEmptyPart(peek) {
 
128
                return 0, io.EOF
 
129
        }
 
130
        unexpectedEOF := err == io.EOF
 
131
        if err != nil && !unexpectedEOF {
124
132
                return 0, fmt.Errorf("multipart: Part Read: %v", err)
125
133
        }
126
134
        if peek == nil {
138
146
                foundBoundary = true
139
147
        } else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 {
140
148
                nCopy = safeCount
141
 
        } else if unexpectedEof {
 
149
        } else if unexpectedEOF {
142
150
                // If we've run out of peek buffer and the boundary
143
151
                // wasn't found (and can't possibly fit), we must have
144
152
                // hit the end of the file unexpectedly.
172
180
        currentPart *Part
173
181
        partsRead   int
174
182
 
175
 
        nl, nlDashBoundary, dashBoundaryDash, dashBoundary []byte
 
183
        nl               []byte // "\r\n" or "\n" (set after seeing first boundary line)
 
184
        nlDashBoundary   []byte // nl + "--boundary"
 
185
        dashBoundaryDash []byte // "--boundary--"
 
186
        dashBoundary     []byte // "--boundary"
176
187
}
177
188
 
178
189
// NextPart returns the next part in the multipart or an error.
185
196
        expectNewPart := false
186
197
        for {
187
198
                line, err := r.bufReader.ReadSlice('\n')
188
 
                if err == io.EOF && bytes.Equal(line, r.dashBoundaryDash) {
 
199
                if err == io.EOF && r.isFinalBoundary(line) {
189
200
                        // If the buffer ends in "--boundary--" without the
190
201
                        // trailing "\r\n", ReadSlice will return an error
191
202
                        // (since it's missing the '\n'), but this is a valid
207
218
                        return bp, nil
208
219
                }
209
220
 
210
 
                if hasPrefixThenNewline(line, r.dashBoundaryDash) {
 
221
                if r.isFinalBoundary(line) {
211
222
                        // Expected EOF
212
223
                        return nil, io.EOF
213
224
                }
235
246
        panic("unreachable")
236
247
}
237
248
 
238
 
func (mr *Reader) isBoundaryDelimiterLine(line []byte) bool {
 
249
// isFinalBoundary returns whether line is the final boundary line
 
250
// indiciating that all parts are over.
 
251
// It matches `^--boundary--[ \t]*(\r\n)?$`
 
252
func (mr *Reader) isFinalBoundary(line []byte) bool {
 
253
        if !bytes.HasPrefix(line, mr.dashBoundaryDash) {
 
254
                return false
 
255
        }
 
256
        rest := line[len(mr.dashBoundaryDash):]
 
257
        rest = skipLWSPChar(rest)
 
258
        return len(rest) == 0 || bytes.Equal(rest, mr.nl)
 
259
}
 
260
 
 
261
func (mr *Reader) isBoundaryDelimiterLine(line []byte) (ret bool) {
239
262
        // http://tools.ietf.org/html/rfc2046#section-5.1
240
263
        //   The boundary delimiter line is then defined as a line
241
264
        //   consisting entirely of two hyphen characters ("-",
245
268
        if !bytes.HasPrefix(line, mr.dashBoundary) {
246
269
                return false
247
270
        }
248
 
        if bytes.HasSuffix(line, mr.nl) {
249
 
                return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-len(mr.nl)])
250
 
        }
251
 
        // Violate the spec and also support newlines without the
252
 
        // carriage return...
253
 
        if mr.partsRead == 0 && bytes.HasSuffix(line, lf) {
254
 
                if onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-1]) {
255
 
                        mr.nl = mr.nl[1:]
256
 
                        mr.nlDashBoundary = mr.nlDashBoundary[1:]
257
 
                        return true
258
 
                }
259
 
        }
260
 
        return false
261
 
}
262
 
 
263
 
func onlyHorizontalWhitespace(s []byte) bool {
264
 
        for _, b := range s {
265
 
                if b != ' ' && b != '\t' {
266
 
                        return false
267
 
                }
268
 
        }
269
 
        return true
270
 
}
271
 
 
272
 
func hasPrefixThenNewline(s, prefix []byte) bool {
273
 
        return bytes.HasPrefix(s, prefix) &&
274
 
                (len(s) == len(prefix)+1 && s[len(s)-1] == '\n' ||
275
 
                        len(s) == len(prefix)+2 && bytes.HasSuffix(s, crlf))
 
271
        rest := line[len(mr.dashBoundary):]
 
272
        rest = skipLWSPChar(rest)
 
273
 
 
274
        // On the first part, see our lines are ending in \n instead of \r\n
 
275
        // and switch into that mode if so.  This is a violation of the spec,
 
276
        // but occurs in practice.
 
277
        if mr.partsRead == 0 && len(rest) == 1 && rest[0] == '\n' {
 
278
                mr.nl = mr.nl[1:]
 
279
                mr.nlDashBoundary = mr.nlDashBoundary[1:]
 
280
        }
 
281
        return bytes.Equal(rest, mr.nl)
 
282
}
 
283
 
 
284
// peekBufferIsEmptyPart returns whether the provided peek-ahead
 
285
// buffer represents an empty part.  This is only called if we've not
 
286
// already read any bytes in this part and checks for the case of MIME
 
287
// software not writing the \r\n on empty parts. Some does, some
 
288
// doesn't.
 
289
//
 
290
// This checks that what follows the "--boundary" is actually the end
 
291
// ("--boundary--" with optional whitespace) or optional whitespace
 
292
// and then a newline, so we don't catch "--boundaryFAKE", in which
 
293
// case the whole line is part of the data.
 
294
func (mr *Reader) peekBufferIsEmptyPart(peek []byte) bool {
 
295
        // End of parts case.
 
296
        // Test whether peek matches `^--boundary--[ \t]*(?:\r\n|$)`
 
297
        if bytes.HasPrefix(peek, mr.dashBoundaryDash) {
 
298
                rest := peek[len(mr.dashBoundaryDash):]
 
299
                rest = skipLWSPChar(rest)
 
300
                return bytes.HasPrefix(rest, mr.nl) || len(rest) == 0
 
301
        }
 
302
        if !bytes.HasPrefix(peek, mr.dashBoundary) {
 
303
                return false
 
304
        }
 
305
        // Test whether rest matches `^[ \t]*\r\n`)
 
306
        rest := peek[len(mr.dashBoundary):]
 
307
        rest = skipLWSPChar(rest)
 
308
        return bytes.HasPrefix(rest, mr.nl)
 
309
}
 
310
 
 
311
// skipLWSPChar returns b with leading spaces and tabs removed.
 
312
// RFC 822 defines:
 
313
//    LWSP-char = SPACE / HTAB
 
314
func skipLWSPChar(b []byte) []byte {
 
315
        for len(b) > 0 && (b[0] == ' ' || b[0] == '\t') {
 
316
                b = b[1:]
 
317
        }
 
318
        return b
276
319
}