1
0
mirror of https://github.com/golang/go synced 2024-10-02 20:31:21 -06:00

multipart: add FileName accessor on Part

R=rsc, adg
CC=golang-dev
https://golang.org/cl/4426074
This commit is contained in:
Brad Fitzpatrick 2011-05-02 08:14:31 -07:00
parent bc926713c7
commit ef94520380
3 changed files with 42 additions and 29 deletions

View File

@ -41,10 +41,7 @@ func (r *multiReader) ReadForm(maxMemory int64) (f *Form, err os.Error) {
if name == "" { if name == "" {
continue continue
} }
var filename string filename := p.FileName()
if p.dispositionParams != nil {
filename = p.dispositionParams["filename"]
}
var b bytes.Buffer var b bytes.Buffer

View File

@ -26,6 +26,8 @@ import (
var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r\n]+)") var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r\n]+)")
var emptyParams = make(map[string]string)
// Reader is an iterator over parts in a MIME multipart body. // Reader is an iterator over parts in a MIME multipart body.
// Reader's underlying parser consumes its input as needed. Seeking // Reader's underlying parser consumes its input as needed. Seeking
// isn't supported. // isn't supported.
@ -51,6 +53,7 @@ type Part struct {
buffer *bytes.Buffer buffer *bytes.Buffer
mr *multiReader mr *multiReader
disposition string
dispositionParams map[string]string dispositionParams map[string]string
} }
@ -59,21 +62,33 @@ type Part struct {
func (p *Part) FormName() string { func (p *Part) FormName() string {
// See http://tools.ietf.org/html/rfc2183 section 2 for EBNF // See http://tools.ietf.org/html/rfc2183 section 2 for EBNF
// of Content-Disposition value format. // of Content-Disposition value format.
if p.dispositionParams != nil { if p.dispositionParams == nil {
return p.dispositionParams["name"] p.parseContentDisposition()
} }
v := p.Header.Get("Content-Disposition") if p.disposition != "form-data" {
if v == "" {
return "" return ""
} }
if d, params := mime.ParseMediaType(v); d != "form-data" {
return ""
} else {
p.dispositionParams = params
}
return p.dispositionParams["name"] return p.dispositionParams["name"]
} }
// FileName returns the filename parameter of the Part's
// Content-Disposition header.
func (p *Part) FileName() string {
if p.dispositionParams == nil {
p.parseContentDisposition()
}
return p.dispositionParams["filename"]
}
func (p *Part) parseContentDisposition() {
v := p.Header.Get("Content-Disposition")
p.disposition, p.dispositionParams = mime.ParseMediaType(v)
if p.dispositionParams == nil {
p.dispositionParams = emptyParams
}
}
// NewReader creates a new multipart Reader reading from r using the // NewReader creates a new multipart Reader reading from r using the
// given MIME boundary. // given MIME boundary.
func NewReader(reader io.Reader, boundary string) Reader { func NewReader(reader io.Reader, boundary string) Reader {

View File

@ -56,24 +56,25 @@ func expectEq(t *testing.T, expected, actual, what string) {
what, escapeString(actual), len(actual), escapeString(expected), len(expected)) what, escapeString(actual), len(actual), escapeString(expected), len(expected))
} }
func TestFormName(t *testing.T) { func TestNameAccessors(t *testing.T) {
p := new(Part) tests := [...][3]string{
p.Header = make(map[string][]string) {`form-data; name="foo"`, "foo", ""},
tests := [...][2]string{ {` form-data ; name=foo`, "foo", ""},
{`form-data; name="foo"`, "foo"}, {`FORM-DATA;name="foo"`, "foo", ""},
{` form-data ; name=foo`, "foo"}, {` FORM-DATA ; name="foo"`, "foo", ""},
{`FORM-DATA;name="foo"`, "foo"}, {` FORM-DATA ; name="foo"`, "foo", ""},
{` FORM-DATA ; name="foo"`, "foo"}, {` FORM-DATA ; name=foo`, "foo", ""},
{` FORM-DATA ; name="foo"`, "foo"}, {` FORM-DATA ; filename="foo.txt"; name=foo; baz=quux`, "foo", "foo.txt"},
{` FORM-DATA ; name=foo`, "foo"}, {` not-form-data ; filename="bar.txt"; name=foo; baz=quux`, "", "bar.txt"},
{` FORM-DATA ; filename="foo.txt"; name=foo; baz=quux`, "foo"},
} }
for _, test := range tests { for i, test := range tests {
p := &Part{Header: make(map[string][]string)}
p.Header.Set("Content-Disposition", test[0]) p.Header.Set("Content-Disposition", test[0])
expected := test[1] if g, e := p.FormName(), test[1]; g != e {
actual := p.FormName() t.Errorf("test %d: FormName() = %q; want %q", i, g, e)
if actual != expected { }
t.Errorf("expected \"%s\"; got: \"%s\"", expected, actual) if g, e := p.FileName(), test[2]; g != e {
t.Errorf("test %d: FileName() = %q; want %q", i, g, e)
} }
} }
} }