libgo: update to go1.9
[official-gcc.git] / libgo / go / mime / multipart / writer.go
blob3dd0c8fb1368a48e31228c348c977e98437d9620
1 // Copyright 2011 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.
5 package multipart
7 import (
8 "bytes"
9 "crypto/rand"
10 "errors"
11 "fmt"
12 "io"
13 "net/textproto"
14 "sort"
15 "strings"
18 // A Writer generates multipart messages.
19 type Writer struct {
20 w io.Writer
21 boundary string
22 lastpart *part
25 // NewWriter returns a new multipart Writer with a random boundary,
26 // writing to w.
27 func NewWriter(w io.Writer) *Writer {
28 return &Writer{
29 w: w,
30 boundary: randomBoundary(),
34 // Boundary returns the Writer's boundary.
35 func (w *Writer) Boundary() string {
36 return w.boundary
39 // SetBoundary overrides the Writer's default randomly-generated
40 // boundary separator with an explicit value.
42 // SetBoundary must be called before any parts are created, may only
43 // contain certain ASCII characters, and must be non-empty and
44 // at most 70 bytes long.
45 func (w *Writer) SetBoundary(boundary string) error {
46 if w.lastpart != nil {
47 return errors.New("mime: SetBoundary called after write")
49 // rfc2046#section-5.1.1
50 if len(boundary) < 1 || len(boundary) > 70 {
51 return errors.New("mime: invalid boundary length")
53 end := len(boundary) - 1
54 for i, b := range boundary {
55 if 'A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' {
56 continue
58 switch b {
59 case '\'', '(', ')', '+', '_', ',', '-', '.', '/', ':', '=', '?':
60 continue
61 case ' ':
62 if i != end {
63 continue
66 return errors.New("mime: invalid boundary character")
68 w.boundary = boundary
69 return nil
72 // FormDataContentType returns the Content-Type for an HTTP
73 // multipart/form-data with this Writer's Boundary.
74 func (w *Writer) FormDataContentType() string {
75 return "multipart/form-data; boundary=" + w.boundary
78 func randomBoundary() string {
79 var buf [30]byte
80 _, err := io.ReadFull(rand.Reader, buf[:])
81 if err != nil {
82 panic(err)
84 return fmt.Sprintf("%x", buf[:])
87 // CreatePart creates a new multipart section with the provided
88 // header. The body of the part should be written to the returned
89 // Writer. After calling CreatePart, any previous part may no longer
90 // be written to.
91 func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) {
92 if w.lastpart != nil {
93 if err := w.lastpart.close(); err != nil {
94 return nil, err
97 var b bytes.Buffer
98 if w.lastpart != nil {
99 fmt.Fprintf(&b, "\r\n--%s\r\n", w.boundary)
100 } else {
101 fmt.Fprintf(&b, "--%s\r\n", w.boundary)
104 keys := make([]string, 0, len(header))
105 for k := range header {
106 keys = append(keys, k)
108 sort.Strings(keys)
109 for _, k := range keys {
110 for _, v := range header[k] {
111 fmt.Fprintf(&b, "%s: %s\r\n", k, v)
114 fmt.Fprintf(&b, "\r\n")
115 _, err := io.Copy(w.w, &b)
116 if err != nil {
117 return nil, err
119 p := &part{
120 mw: w,
122 w.lastpart = p
123 return p, nil
126 var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
128 func escapeQuotes(s string) string {
129 return quoteEscaper.Replace(s)
132 // CreateFormFile is a convenience wrapper around CreatePart. It creates
133 // a new form-data header with the provided field name and file name.
134 func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) {
135 h := make(textproto.MIMEHeader)
136 h.Set("Content-Disposition",
137 fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
138 escapeQuotes(fieldname), escapeQuotes(filename)))
139 h.Set("Content-Type", "application/octet-stream")
140 return w.CreatePart(h)
143 // CreateFormField calls CreatePart with a header using the
144 // given field name.
145 func (w *Writer) CreateFormField(fieldname string) (io.Writer, error) {
146 h := make(textproto.MIMEHeader)
147 h.Set("Content-Disposition",
148 fmt.Sprintf(`form-data; name="%s"`, escapeQuotes(fieldname)))
149 return w.CreatePart(h)
152 // WriteField calls CreateFormField and then writes the given value.
153 func (w *Writer) WriteField(fieldname, value string) error {
154 p, err := w.CreateFormField(fieldname)
155 if err != nil {
156 return err
158 _, err = p.Write([]byte(value))
159 return err
162 // Close finishes the multipart message and writes the trailing
163 // boundary end line to the output.
164 func (w *Writer) Close() error {
165 if w.lastpart != nil {
166 if err := w.lastpart.close(); err != nil {
167 return err
169 w.lastpart = nil
171 _, err := fmt.Fprintf(w.w, "\r\n--%s--\r\n", w.boundary)
172 return err
175 type part struct {
176 mw *Writer
177 closed bool
178 we error // last error that occurred writing
181 func (p *part) close() error {
182 p.closed = true
183 return p.we
186 func (p *part) Write(d []byte) (n int, err error) {
187 if p.closed {
188 return 0, errors.New("multipart: can't write to finished part")
190 n, err = p.mw.w.Write(d)
191 if err != nil {
192 p.we = err
194 return