Commit 98f95b80 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

mime/multipart: convert Reader from interface to struct

It was always a weird interface but I didn't know what I
was doing at the time.  rsc questioned me about it then
but didn't press on it during review.  Then adg bugged me
about it too recently.

So clean it up. It parallels the Writer struct too.

R=golang-dev, r, rsc
CC=golang-dev
https://golang.org/cl/4602063
parent 95963e62
...@@ -188,7 +188,7 @@ var multipartByReader = &multipart.Form{ ...@@ -188,7 +188,7 @@ var multipartByReader = &multipart.Form{
// multipart/form-data POST request, else returns nil and an error. // multipart/form-data POST request, else returns nil and an error.
// Use this function instead of ParseMultipartForm to // Use this function instead of ParseMultipartForm to
// process the request body as a stream. // process the request body as a stream.
func (r *Request) MultipartReader() (multipart.Reader, os.Error) { func (r *Request) MultipartReader() (*multipart.Reader, os.Error) {
if r.MultipartForm == multipartByReader { if r.MultipartForm == multipartByReader {
return nil, os.NewError("http: MultipartReader called twice") return nil, os.NewError("http: MultipartReader called twice")
} }
...@@ -199,7 +199,7 @@ func (r *Request) MultipartReader() (multipart.Reader, os.Error) { ...@@ -199,7 +199,7 @@ func (r *Request) MultipartReader() (multipart.Reader, os.Error) {
return r.multipartReader() return r.multipartReader()
} }
func (r *Request) multipartReader() (multipart.Reader, os.Error) { func (r *Request) multipartReader() (*multipart.Reader, os.Error) {
v := r.Header.Get("Content-Type") v := r.Header.Get("Content-Type")
if v == "" { if v == "" {
return nil, ErrNotMultipart return nil, ErrNotMultipart
......
...@@ -19,7 +19,7 @@ import ( ...@@ -19,7 +19,7 @@ import (
// a Content-Disposition of "form-data". // a Content-Disposition of "form-data".
// It stores up to maxMemory bytes of the file parts in memory // It stores up to maxMemory bytes of the file parts in memory
// and the remainder on disk in temporary files. // and the remainder on disk in temporary files.
func (r *multiReader) ReadForm(maxMemory int64) (f *Form, err os.Error) { func (r *Reader) ReadForm(maxMemory int64) (f *Form, err os.Error) {
form := &Form{make(map[string][]string), make(map[string][]*FileHeader)} form := &Form{make(map[string][]string), make(map[string][]*FileHeader)}
defer func() { defer func() {
if err != nil { if err != nil {
......
...@@ -28,21 +28,6 @@ var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r ...@@ -28,21 +28,6 @@ var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r
var emptyParams = make(map[string]string) var emptyParams = make(map[string]string)
// Reader is an iterator over parts in a MIME multipart body.
// Reader's underlying parser consumes its input as needed. Seeking
// isn't supported.
type Reader interface {
// NextPart returns the next part in the multipart or an error.
// When there are no more parts, the error os.EOF is returned.
NextPart() (*Part, os.Error)
// ReadForm parses an entire multipart message whose parts have
// a Content-Disposition of "form-data".
// It stores up to maxMemory bytes of the file parts in memory
// and the remainder on disk in temporary files.
ReadForm(maxMemory int64) (*Form, os.Error)
}
// A Part represents a single part in a multipart body. // A Part represents a single part in a multipart body.
type Part struct { type Part struct {
// The headers of the body, if any, with the keys canonicalized // The headers of the body, if any, with the keys canonicalized
...@@ -51,7 +36,7 @@ type Part struct { ...@@ -51,7 +36,7 @@ type Part struct {
Header textproto.MIMEHeader Header textproto.MIMEHeader
buffer *bytes.Buffer buffer *bytes.Buffer
mr *multiReader mr *Reader
disposition string disposition string
dispositionParams map[string]string dispositionParams map[string]string
...@@ -91,9 +76,9 @@ func (p *Part) parseContentDisposition() { ...@@ -91,9 +76,9 @@ func (p *Part) parseContentDisposition() {
// 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 {
b := []byte("\r\n--" + boundary + "--") b := []byte("\r\n--" + boundary + "--")
return &multiReader{ return &Reader{
bufReader: bufio.NewReader(reader), bufReader: bufio.NewReader(reader),
nlDashBoundary: b[:len(b)-2], nlDashBoundary: b[:len(b)-2],
...@@ -102,9 +87,7 @@ func NewReader(reader io.Reader, boundary string) Reader { ...@@ -102,9 +87,7 @@ func NewReader(reader io.Reader, boundary string) Reader {
} }
} }
// Implementation .... func newPart(mr *Reader) (*Part, os.Error) {
func newPart(mr *multiReader) (*Part, os.Error) {
bp := &Part{ bp := &Part{
Header: make(map[string][]string), Header: make(map[string][]string),
mr: mr, mr: mr,
...@@ -188,7 +171,10 @@ func (bp *Part) Close() os.Error { ...@@ -188,7 +171,10 @@ func (bp *Part) Close() os.Error {
return nil return nil
} }
type multiReader struct { // Reader is an iterator over parts in a MIME multipart body.
// Reader's underlying parser consumes its input as needed. Seeking
// isn't supported.
type Reader struct {
bufReader *bufio.Reader bufReader *bufio.Reader
currentPart *Part currentPart *Part
...@@ -197,7 +183,9 @@ type multiReader struct { ...@@ -197,7 +183,9 @@ type multiReader struct {
nlDashBoundary, dashBoundaryDash, dashBoundary []byte nlDashBoundary, dashBoundaryDash, dashBoundary []byte
} }
func (mr *multiReader) NextPart() (*Part, os.Error) { // NextPart returns the next part in the multipart or an error.
// When there are no more parts, the error os.EOF is returned.
func (mr *Reader) NextPart() (*Part, os.Error) {
if mr.currentPart != nil { if mr.currentPart != nil {
mr.currentPart.Close() mr.currentPart.Close()
} }
...@@ -247,7 +235,7 @@ func (mr *multiReader) NextPart() (*Part, os.Error) { ...@@ -247,7 +235,7 @@ func (mr *multiReader) NextPart() (*Part, os.Error) {
panic("unreachable") panic("unreachable")
} }
func (mr *multiReader) isBoundaryDelimiterLine(line []byte) bool { func (mr *Reader) isBoundaryDelimiterLine(line []byte) bool {
// http://tools.ietf.org/html/rfc2046#section-5.1 // http://tools.ietf.org/html/rfc2046#section-5.1
// The boundary delimiter line is then defined as a line // The boundary delimiter line is then defined as a line
// consisting entirely of two hyphen characters ("-", // consisting entirely of two hyphen characters ("-",
......
...@@ -25,7 +25,7 @@ func TestHorizontalWhitespace(t *testing.T) { ...@@ -25,7 +25,7 @@ func TestHorizontalWhitespace(t *testing.T) {
} }
func TestBoundaryLine(t *testing.T) { func TestBoundaryLine(t *testing.T) {
mr := NewReader(strings.NewReader(""), "myBoundary").(*multiReader) mr := NewReader(strings.NewReader(""), "myBoundary")
if !mr.isBoundaryDelimiterLine([]byte("--myBoundary\r\n")) { if !mr.isBoundaryDelimiterLine([]byte("--myBoundary\r\n")) {
t.Error("expected") t.Error("expected")
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment