Skip to content

Commit 40618a7

Browse files
author
Michael Hoisie
committed
Initial multipart form data parser
1 parent 4c3f987 commit 40618a7

File tree

2 files changed

+74
-11
lines changed

2 files changed

+74
-11
lines changed

request.go

+64-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package web
22

33
import (
4+
"bytes"
45
"container/vector"
56
"fmt"
67
"http"
@@ -25,6 +26,7 @@ type Request struct {
2526
UserAgent string
2627
Params map[string][]string
2728
Cookies map[string]string
29+
Files map[string][]byte
2830
}
2931

3032
type badStringError struct {
@@ -144,7 +146,58 @@ func (r *Request) ParseParams() (err os.Error) {
144146
return err
145147
}
146148
query = string(b)
147-
// TODO(dsymonds): Handle multipart/form-data
149+
case "multipart/form-data":
150+
r.Files = make(map[string][]byte)
151+
boundary := strings.Split(ct, "boundary=", 2)[1]
152+
var b []byte
153+
if b, err = ioutil.ReadAll(r.Body); err != nil {
154+
return err
155+
}
156+
parts := bytes.Split(b, strings.Bytes("--"+boundary+"\r\n"), 0)
157+
for _, data := range (parts) {
158+
if len(data) == 0 {
159+
continue
160+
}
161+
var line []byte
162+
var rest = data
163+
headers := map[string]string{}
164+
isfile := false
165+
var name string
166+
for {
167+
res := bytes.Split(rest, []byte{'\r', '\n'}, 2)
168+
if len(res) != 2 {
169+
break
170+
}
171+
line = res[0]
172+
rest = res[1]
173+
if len(line) == 0 {
174+
break
175+
}
176+
177+
header := strings.Split(string(line), ":", 2)
178+
n := strings.TrimSpace(header[0])
179+
v := strings.TrimSpace(header[1])
180+
if n == "Content-Disposition" {
181+
parts := strings.Split(v, ";", 0)
182+
for _, parm := range (parts[1:]) {
183+
pp := strings.Split(parm, "=", 2)
184+
pn := strings.TrimSpace(pp[0])
185+
pv := strings.TrimSpace(pp[1])
186+
if pn == "name" {
187+
name = pv[1 : len(pv)-1]
188+
} else if pn == "filename" {
189+
isfile = true
190+
}
191+
}
192+
}
193+
194+
headers[n] = v
195+
}
196+
if isfile {
197+
parts = bytes.Split(rest, strings.Bytes("\r\n--"+boundary+"--\r\n"), 0)
198+
r.Files[name] = parts[0]
199+
}
200+
}
148201
default:
149202
return &badStringError{"unknown Content-Type", ct}
150203
}
@@ -174,6 +227,16 @@ func (r *Request) ParseCookies() (err os.Error) {
174227
}
175228

176229
func (r *Request) HasParam(name string) bool {
230+
if r.Params == nil || len(r.Params) == 0 {
231+
return false
232+
}
177233
_, ok := r.Params[name]
178234
return ok
179235
}
236+
func (r *Request) HasFile(name string) bool {
237+
if r.Files == nil || len(r.Files) == 0 {
238+
return false
239+
}
240+
_, ok := r.Files[name]
241+
return ok
242+
}

web.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -366,16 +366,16 @@ func SetStaticDir(dir string) os.Error {
366366
return nil
367367
}
368368

369-
func Urlencode ( data map[string]string ) string {
370-
var buf bytes.Buffer;
371-
for k,v := range ( data ) {
372-
buf.WriteString ( http.URLEscape(k) )
373-
buf.WriteByte('=' )
374-
buf.WriteString ( http.URLEscape(v) )
375-
buf.WriteByte('&' )
376-
}
377-
s := buf.String()
378-
return s[0:len(s) - 1]
369+
func Urlencode(data map[string]string) string {
370+
var buf bytes.Buffer
371+
for k, v := range (data) {
372+
buf.WriteString(http.URLEscape(k))
373+
buf.WriteByte('=')
374+
buf.WriteString(http.URLEscape(v))
375+
buf.WriteByte('&')
376+
}
377+
s := buf.String()
378+
return s[0 : len(s)-1]
379379
}
380380

381381
//copied from go's http package, because it's not public

0 commit comments

Comments
 (0)