diff options
Diffstat (limited to 'src/pkg/mime/multipart/writer.go')
-rw-r--r-- | src/pkg/mime/multipart/writer.go | 184 |
1 files changed, 0 insertions, 184 deletions
diff --git a/src/pkg/mime/multipart/writer.go b/src/pkg/mime/multipart/writer.go deleted file mode 100644 index e13a956af..000000000 --- a/src/pkg/mime/multipart/writer.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package multipart - -import ( - "bytes" - "crypto/rand" - "errors" - "fmt" - "io" - "net/textproto" - "strings" -) - -// A Writer generates multipart messages. -type Writer struct { - w io.Writer - boundary string - lastpart *part -} - -// NewWriter returns a new multipart Writer with a random boundary, -// writing to w. -func NewWriter(w io.Writer) *Writer { - return &Writer{ - w: w, - boundary: randomBoundary(), - } -} - -// Boundary returns the Writer's boundary. -func (w *Writer) Boundary() string { - return w.boundary -} - -// SetBoundary overrides the Writer's default randomly-generated -// boundary separator with an explicit value. -// -// SetBoundary must be called before any parts are created, may only -// contain certain ASCII characters, and must be 1-69 bytes long. -func (w *Writer) SetBoundary(boundary string) error { - if w.lastpart != nil { - return errors.New("mime: SetBoundary called after write") - } - // rfc2046#section-5.1.1 - if len(boundary) < 1 || len(boundary) > 69 { - return errors.New("mime: invalid boundary length") - } - for _, b := range boundary { - if 'A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' { - continue - } - switch b { - case '\'', '(', ')', '+', '_', ',', '-', '.', '/', ':', '=', '?': - continue - } - return errors.New("mime: invalid boundary character") - } - w.boundary = boundary - return nil -} - -// FormDataContentType returns the Content-Type for an HTTP -// multipart/form-data with this Writer's Boundary. -func (w *Writer) FormDataContentType() string { - return "multipart/form-data; boundary=" + w.boundary -} - -func randomBoundary() string { - var buf [30]byte - _, err := io.ReadFull(rand.Reader, buf[:]) - if err != nil { - panic(err) - } - return fmt.Sprintf("%x", buf[:]) -} - -// CreatePart creates a new multipart section with the provided -// header. The body of the part should be written to the returned -// Writer. After calling CreatePart, any previous part may no longer -// be written to. -func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) { - if w.lastpart != nil { - if err := w.lastpart.close(); err != nil { - return nil, err - } - } - var b bytes.Buffer - if w.lastpart != nil { - fmt.Fprintf(&b, "\r\n--%s\r\n", w.boundary) - } else { - fmt.Fprintf(&b, "--%s\r\n", w.boundary) - } - // TODO(bradfitz): move this to textproto.MimeHeader.Write(w), have it sort - // and clean, like http.Header.Write(w) does. - for k, vv := range header { - for _, v := range vv { - fmt.Fprintf(&b, "%s: %s\r\n", k, v) - } - } - fmt.Fprintf(&b, "\r\n") - _, err := io.Copy(w.w, &b) - if err != nil { - return nil, err - } - p := &part{ - mw: w, - } - w.lastpart = p - return p, nil -} - -var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") - -func escapeQuotes(s string) string { - return quoteEscaper.Replace(s) -} - -// CreateFormFile is a convenience wrapper around CreatePart. It creates -// a new form-data header with the provided field name and file name. -func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) { - h := make(textproto.MIMEHeader) - h.Set("Content-Disposition", - fmt.Sprintf(`form-data; name="%s"; filename="%s"`, - escapeQuotes(fieldname), escapeQuotes(filename))) - h.Set("Content-Type", "application/octet-stream") - return w.CreatePart(h) -} - -// CreateFormField calls CreatePart with a header using the -// given field name. -func (w *Writer) CreateFormField(fieldname string) (io.Writer, error) { - h := make(textproto.MIMEHeader) - h.Set("Content-Disposition", - fmt.Sprintf(`form-data; name="%s"`, escapeQuotes(fieldname))) - return w.CreatePart(h) -} - -// WriteField calls CreateFormField and then writes the given value. -func (w *Writer) WriteField(fieldname, value string) error { - p, err := w.CreateFormField(fieldname) - if err != nil { - return err - } - _, err = p.Write([]byte(value)) - return err -} - -// Close finishes the multipart message and writes the trailing -// boundary end line to the output. -func (w *Writer) Close() error { - if w.lastpart != nil { - if err := w.lastpart.close(); err != nil { - return err - } - w.lastpart = nil - } - _, err := fmt.Fprintf(w.w, "\r\n--%s--\r\n", w.boundary) - return err -} - -type part struct { - mw *Writer - closed bool - we error // last error that occurred writing -} - -func (p *part) close() error { - p.closed = true - return p.we -} - -func (p *part) Write(d []byte) (n int, err error) { - if p.closed { - return 0, errors.New("multipart: can't write to finished part") - } - n, err = p.mw.w.Write(d) - if err != nil { - p.we = err - } - return -} |