Documentation
¶
Index ¶
- func PartSeq(parts ...*Part) iter.Seq2[*Part, error]
- func PartsFromReader(r *multipart.Reader, raw bool) iter.Seq2[*Part, error]
- func PartsFromRequest(r *http.Request, raw bool) iter.Seq2[*Part, error]
- type Part
- func (p *Part) AddHeaderValue(key, value string) *Part
- func (p *Part) AddToWriter(mw *multipart.Writer) error
- func (p *Part) ContentType() string
- func (p *Part) DetectContentType() *Part
- func (p *Part) FileName() string
- func (p *Part) FormName() string
- func (p *Part) MergeHeaders(h textproto.MIMEHeader) *Part
- func (p *Part) Reset()
- func (p *Part) SetContent(content io.Reader) *Part
- func (p *Part) SetContentBytes(content []byte) *Part
- func (p *Part) SetContentString(content string) *Part
- func (p *Part) SetContentType(contentType string) *Part
- func (p *Part) SetContentTypeByExtension() *Part
- func (p *Part) SetFileName(fileName string) *Part
- func (p *Part) SetFormName(formName string) *Part
- func (p *Part) SetHeaderValue(key, value string) *Part
- type Source
- func (s *Source) Boundary() string
- func (s *Source) Close() error
- func (s *Source) FormDataContentType() string
- func (s *Source) Read(p []byte) (n int, err error)
- func (s *Source) Reset(parts iter.Seq2[*Part, error])
- func (s *Source) SetBoundary(boundary string) error
- func (s *Source) WriteTo(target io.Writer) (int64, error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func PartsFromReader ¶
PartsFromReader reads each part from the provided multipart.Reader and yields it to the caller. If raw is true, it reads the raw part using multipart.Reader.NextRawPart. Note that Part becomes invalid on the next iteration so reference to it must not be held.
func PartsFromRequest ¶
PartsFromRequest reads each part from the http request and yields it to the caller. If raw is true, it reads the raw part using multipart.Part.NextRawPart. Note that Part becomes invalid on the next iteration so reference to it must not be held.
Example ¶
package main import ( "fmt" "io" "maps" "net/http/httptest" "os" "slices" "strings" "github.com/xakep666/itermultipart" ) func main() { message := `--boundary Content-Disposition: form-data; name="myfile"; filename="example.txt" contents of myfile --boundary Content-Disposition: form-data; name="key" value for key --boundary--` message = strings.ReplaceAll(message, "\n", "\r\n") r := httptest.NewRequest("POST", "/", strings.NewReader(message)) r.Header.Set("Content-Type", "multipart/form-data; boundary=boundary") for part, err := range itermultipart.PartsFromRequest(r, false) { if err != nil { panic(err) } if part == nil { continue } fmt.Println("---headers---") for _, k := range slices.Sorted(maps.Keys(part.Header)) { fmt.Printf("%s: %s\n", k, part.Header[k]) } fmt.Println("---identifiers---") if part.FormName() != "" { fmt.Println("name:", part.FormName()) } if part.FileName() != "" { fmt.Println("filename:", part.FileName()) } fmt.Println("---content---") io.Copy(os.Stdout, part.Content) fmt.Println() } }
Output: ---headers--- Content-Disposition: [form-data; name="myfile"; filename="example.txt"] ---identifiers--- name: myfile filename: example.txt ---content--- contents of myfile ---headers--- Content-Disposition: [form-data; name="key"] ---identifiers--- name: key ---content--- value for key
Types ¶
type Part ¶
type Part struct { Header textproto.MIMEHeader Content io.Reader // contains filtered or unexported fields }
Part represents a part of a multipart message.
func NewPart ¶
func NewPart() *Part
NewPart creates a new part.
Example ¶
package main import ( "fmt" "io" "maps" "os" "slices" "github.com/xakep666/itermultipart" ) func main() { part := itermultipart.NewPart(). SetFormName("customfile"). SetFileName("example.txt"). SetContentTypeByExtension(). SetHeaderValue("X-Custom-Header", "value"). SetContentString("Hello, World!") for _, k := range slices.Sorted(maps.Keys(part.Header)) { fmt.Printf("%s: %s\n", k, part.Header[k]) } fmt.Println("---") io.Copy(os.Stdout, part.Content) }
Output: Content-Disposition: [form-data; filename=example.txt; name=customfile] Content-Type: [text/plain; charset=utf-8] X-Custom-Header: [value] --- Hello, World!
func (*Part) AddHeaderValue ¶
AddHeaderValue adds the value to the given header key.
func (*Part) AddToWriter ¶
AddToWriter adds the part to the standard mime/multipart.Writer.
Example ¶
package main import ( "bytes" "fmt" "mime/multipart" "strings" "github.com/xakep666/itermultipart" ) func main() { var buf bytes.Buffer mw := multipart.NewWriter(&buf) mw.SetBoundary("boundary") itermultipart.NewPart(). SetFormName("customfile"). SetFileName("example.txt"). SetContentTypeByExtension(). SetHeaderValue("X-Custom-Header", "value"). SetContentString("Hello, World!"). AddToWriter(mw) itermultipart.NewPart(). SetFormName("key"). SetContentString("val"). AddToWriter(mw) mw.Close() fmt.Println(strings.ReplaceAll(buf.String(), "\r\n", "\n")) }
Output: --boundary Content-Disposition: form-data; filename=example.txt; name=customfile Content-Type: text/plain; charset=utf-8 X-Custom-Header: value Hello, World! --boundary Content-Disposition: form-data; name=key val --boundary--
func (*Part) ContentType ¶
ContentType returns the content type of the part.
func (*Part) DetectContentType ¶
DetectContentType detects the content type of the part using net/http.DetectContentType. It peeks the first 512 bytes of the content to determine the content type. Content must be already set before calling this method. If content-type cannot be detected, it sets the content type to "application/octet-stream". Note that this method modifies Content field of the part.
Example ¶
package main import ( "fmt" "github.com/xakep666/itermultipart" ) func main() { part := itermultipart.NewPart(). SetFormName("customfile"). SetFileName("example.txt"). SetContentString("<html><body>test</body></html>"). DetectContentType() fmt.Println(part.ContentType()) }
Output: text/html; charset=utf-8
func (*Part) FileName ¶
FileName returns the filename parameter of the Part's Content-Disposition header. If not empty, the filename is passed through filepath.Base (which is platform dependent) before being returned.
func (*Part) FormName ¶
FormName returns the name parameter if p has a Content-Disposition of type "form-data". Otherwise, it returns the empty string.
func (*Part) MergeHeaders ¶
func (p *Part) MergeHeaders(h textproto.MIMEHeader) *Part
MergeHeaders merges the given headers into the part's headers.
func (*Part) SetContent ¶
SetContent sets the content of the part.
func (*Part) SetContentBytes ¶
SetContentBytes sets the content of the part to the given bytes.
func (*Part) SetContentString ¶
SetContentString sets the content of the part to the given string.
func (*Part) SetContentType ¶
SetContentType sets the content type of the part.
func (*Part) SetContentTypeByExtension ¶
SetContentTypeByExtension sets the content type of the part based on the file extension. If the file name was not set, it does nothing. The content type is set using mime.TypeByExtension so you can register custom types using mime.AddExtensionType.
func (*Part) SetFileName ¶
SetFileName sets the file name of the part. It also sets the "Content-Type" header to "application/octet-stream" like multipart.Writer.CreateFormFile.
func (*Part) SetFormName ¶
SetFormName sets the form name of the part.
func (*Part) SetHeaderValue ¶
SetHeaderValue sets the value of the given header key.
type Source ¶
type Source struct {
// contains filtered or unexported fields
}
Source is a generator of multipart message as you read from it.
func NewSource ¶
NewSource returns a new Source that generates a multipart message from provided part sequence. Part sequence must be finite. Source holds reference for Part only until it's fully read.
func (*Source) FormDataContentType ¶
FormDataContentType returns the Content-Type for an HTTP multipart/form-data with this Source's Boundary.
func (*Source) SetBoundary ¶
SetBoundary overrides the Source's default randomly-generated boundary separator with an explicit value.
SetBoundary must be called before any parts are created, may only contain certain ASCII characters, and must be non-empty and at most 70 bytes long.