// 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 multipartimport ()// ErrMessageTooLarge is returned by ReadForm if the message form// data is too large to be processed.varErrMessageTooLarge = errors.New("multipart: message too large")// TODO(adg,bradfitz): find a way to unify the DoS-prevention strategy here// with that of the http package's ParseForm.// ReadForm parses an entire multipart message whose parts have// a Content-Disposition of "form-data".// It stores up to maxMemory bytes + 10MB (reserved for non-file parts)// in memory. File parts which can't be stored in memory will be stored on// disk in temporary files.// It returns ErrMessageTooLarge if all non-file parts can't be stored in// memory.func ( *Reader) ( int64) (*Form, error) {return .readForm()}func ( *Reader) ( int64) ( *Form, error) { := &Form{make(map[string][]string), make(map[string][]*FileHeader)}deferfunc() {if != nil { .RemoveAll() } }()// Reserve an additional 10 MB for non-file parts. := + int64(10<<20)if <= 0 {if < 0 { = 0 } else { = math.MaxInt64 } }for { , := .NextPart()if == io.EOF {break }if != nil {returnnil, } := .FormName()if == "" {continue } := .FileName()varbytes.Bufferif == "" {// value, store as string in memory , := io.CopyN(&, , +1)if != nil && != io.EOF {returnnil, } -= if < 0 {returnnil, ErrMessageTooLarge } .Value[] = append(.Value[], .String())continue }// file, store in memory or on disk := &FileHeader{Filename: ,Header: .Header, } , := io.CopyN(&, , +1)if != nil && != io.EOF {returnnil, }if > {// too big, write to disk and flush buffer , := os.CreateTemp("", "multipart-")if != nil {returnnil, } , := io.Copy(, io.MultiReader(&, ))if := .Close(); == nil { = }if != nil {os.Remove(.Name())returnnil, } .tmpfile = .Name() .Size = } else { .content = .Bytes() .Size = int64(len(.content)) -= -= } .File[] = append(.File[], ) }return , nil}// Form is a parsed multipart form.// Its File parts are stored either in memory or on disk,// and are accessible via the *FileHeader's Open method.// Its Value parts are stored as strings.// Both are keyed by field name.typeFormstruct {Valuemap[string][]stringFilemap[string][]*FileHeader}// RemoveAll removes any temporary files associated with a Form.func ( *Form) () error {varerrorfor , := range .File {for , := range {if .tmpfile != "" { := os.Remove(.tmpfile)if != nil && == nil { = } } } }return}// A FileHeader describes a file part of a multipart request.typeFileHeaderstruct {FilenamestringHeadertextproto.MIMEHeaderSizeint64content []bytetmpfilestring}// Open opens and returns the FileHeader's associated File.func ( *FileHeader) () (File, error) {if := .content; != nil { := io.NewSectionReader(bytes.NewReader(), 0, int64(len()))returnsectionReadCloser{}, nil }returnos.Open(.tmpfile)}// File is an interface to access the file part of a multipart message.// Its contents may be either stored in memory or on disk.// If stored on disk, the File's underlying concrete type will be an *os.File.typeFileinterface {io.Readerio.ReaderAtio.Seekerio.Closer}// helper types to turn a []byte into a FiletypesectionReadCloserstruct { *io.SectionReader}func ( sectionReadCloser) () error {returnnil}
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)