// Reads & parses the request body, handling either JSON or multipart. func (h *handler) readDocument() (db.Body, error) { contentType, attrs, _ := mime.ParseMediaType(h.rq.Header.Get("Content-Type")) switch contentType { case "", "application/json": return h.readJSON() case "multipart/related": if DebugMultipart { raw, err := h.readBody() if err != nil { return nil, err } reader := multipart.NewReader(bytes.NewReader(raw), attrs["boundary"]) body, err := db.ReadMultipartDocument(reader) if err != nil { ioutil.WriteFile("GatewayPUT.mime", raw, 0600) base.Warn("Error reading MIME data: copied to file GatewayPUT.mime") } return body, err } else { reader := multipart.NewReader(h.requestBody, attrs["boundary"]) return db.ReadMultipartDocument(reader) } default: return nil, base.HTTPErrorf(http.StatusUnsupportedMediaType, "Invalid content type %s", contentType) } }
func TestShardFilter(t *testing.T) { t.Parallel() shard := NewShard("", "TestShardFilterData", "TestShardFilterPipelines", 0, 1, etcache.NewCache()) require.NoError(t, shard.EnsureRepos()) s := httptest.NewServer(NewShardHTTPHandler(shard)) defer s.Close() res, err := http.Post(s.URL+"/pipeline/files", "application/text", strings.NewReader(` image ubuntu run touch /out/foo run touch /out/bar run touch /out/buzz run touch /out/bizz `)) require.NoError(t, err) res.Body.Close() res, err = http.Post(s.URL+"/commit?commit=commit1", "", nil) require.NoError(t, err) // Map to store files we receive files := make(map[string]struct{}) res, err = http.Get(s.URL + path.Join("/pipeline", "files", "file", "*") + "?commit=commit1&shard=0-2") require.NoError(t, err) require.Equal(t, http.StatusOK, res.StatusCode) reader := multipart.NewReader(res.Body, res.Header.Get("Boundary")) for p, err := reader.NextPart(); err != io.EOF; p, err = reader.NextPart() { require.NoError(t, err) match, err := route.Match(p.FileName(), "0-2") require.NoError(t, err) require.True(t, match, fmt.Sprintf("%s should match", p.FileName())) if _, ok := files[p.FileName()]; ok == true { t.Fatalf("File: %s received twice.", p.FileName()) } files[p.FileName()] = struct{}{} } res, err = http.Get(s.URL + path.Join("/pipeline", "files", "file", "*") + "?commit=commit1&shard=1-2") require.NoError(t, err) require.Equal(t, http.StatusOK, res.StatusCode) reader = multipart.NewReader(res.Body, res.Header.Get("Boundary")) for p, err := reader.NextPart(); err != io.EOF; p, err = reader.NextPart() { require.NoError(t, err) match, err := route.Match(p.FileName(), "1-2") require.NoError(t, err) require.True(t, match, fmt.Sprintf("%s should match", p.FileName())) if _, ok := files[p.FileName()]; ok == true { t.Fatalf("File: %s received twice.", p.FileName()) } files[p.FileName()] = struct{}{} } }
func messageReader(message *imap.MessageInfo) (io.Reader, error) { // Get content-type of the message. msg := messageAttr(message, BODY_PART_NAME) if msg != nil { mediaType, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type")) if err != nil { return nil, err } if strings.HasPrefix(mediaType, "multipart/") { mpReader := multipart.NewReader(msg.Body, params["boundary"]) for { part, err := mpReader.NextPart() textPlainPart, err := partReader(part) if err == io.EOF { LOG.Println("Reached EOF while reading multipart message") return nil, err } panicMaybe(err) if textPlainPart != nil { return textPlainPart, err } } } else if mediaType == "text/plain" { return msg.Body, nil } return nil, errors.New("No text/plain message part found") } return nil, errors.New("Could not find message body") }
func testBasicAgainstStdLib(t *testing.T, msg *Message, rawBytes []byte) { // confirm stdlib can parse it too stdlibMsg, err := mail.ReadMessage(bytes.NewReader(rawBytes)) if err != nil { t.Fatal("Standard Library could not parse message:", err) } // confirm stdlib headers match our headers if !reflect.DeepEqual(map[string][]string(msg.Header), map[string][]string(stdlibMsg.Header)) { t.Fatal("Message does not match its parsed counterpart") } // confirm subsequent parts match mixedReader := multipart.NewReader(stdlibMsg.Body, boundary(map[string][]string(stdlibMsg.Header))) alternativePart, err := mixedReader.NextPart() if err != nil { t.Fatal("Couldn't get next part", err) } // test the multipart/alternative testMultipartAlternativeWithStdLib(t, msg.Parts[0], alternativePart) // confirm EOF if _, err = mixedReader.NextPart(); err != io.EOF { t.Fatal("Should be EOF", err) } }
func testMultipartInlineWithStdLib(t *testing.T, originalPart *Message, stdlibAltPart *multipart.Part) { // confirm stdlib headers match our headers if !reflect.DeepEqual(map[string][]string(originalPart.Header), map[string][]string(stdlibAltPart.Header)) { t.Fatal("Message does not match its parsed counterpart") } // multipart/alternative with inlines should have text/plain and multipart/related parts alternativeReader := multipart.NewReader(stdlibAltPart, boundary(map[string][]string(stdlibAltPart.Header))) plainPart, err := alternativeReader.NextPart() if err != nil { t.Fatal("Couldn't get next part", err) } testBodyPartWithStdLib(t, originalPart.Parts[0], plainPart) relatedPart, err := alternativeReader.NextPart() if err != nil { t.Fatal("Couldn't get next part", err) } testMultipartRelatedWithStdLib(t, originalPart.Parts[1], relatedPart) // confirm EOF and Close if _, err = alternativeReader.NextPart(); err != io.EOF || stdlibAltPart.Close() != nil { t.Fatal("Should be EOF", err) } }
// ForEach ... func (r *GetObjectResponse) ForEach(result GetObjectResult) error { resp := r.response defer resp.Body.Close() mediaType, params, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) if err != nil { return err } // its not multipart, just leave if !strings.HasPrefix(mediaType, "multipart/") { return result(NewObjectFromStream(textproto.MIMEHeader(resp.Header), resp.Body)) } // its multipart, need to break it up partsReader := multipart.NewReader(resp.Body, params["boundary"]) for { part, err := partsReader.NextPart() switch { case err == io.EOF: return nil case err != nil: return err } err = result(NewObjectFromStream(part.Header, part)) if err != nil { return err } } // return nil }
func newEntity(h textproto.MIMEHeader, r io.Reader, shared *sharedData) (*Entity, error) { contType := h.Get("Content-Type") if contType == "" { return &Entity{ Header: h, body: &SinglepartBody{Reader: r}, shared: shared, }, nil } mediaType, params, err := mime.ParseMediaType(contType) if err != nil { return nil, err } if !strings.HasPrefix(mediaType, "multipart/") { return &Entity{ Header: h, body: &SinglepartBody{Reader: r}, shared: shared, }, nil } boundary, ok := params["boundary"] if !ok { return nil, fmt.Errorf("Boundary not found in Content-Type field: %v", contType) } return &Entity{ Header: h, body: &MultipartBody{multipart.NewReader(r, boundary)}, shared: shared, }, nil }
func parseEmail(data []byte) *templates.Email { r := bufio.NewReader(bytes.NewReader(data)) hr := textproto.NewReader(r) h, err := hr.ReadMIMEHeader() So(err, ShouldBeNil) So(h.Get("Mime-Version"), ShouldEqual, "1.0") ctype := h.Get("Content-Type") So(ctype, ShouldStartWith, "multipart/alternative;") So(ctype, ShouldEndWith, `"`) idx := strings.Index(ctype, `boundary="`) So(idx, ShouldBeGreaterThan, -1) mpr := multipart.NewReader(r, ctype[idx+len(`boundary="`):len(ctype)-1]) part, err := mpr.NextPart() So(err, ShouldBeNil) So(part.Header.Get("Content-Type"), ShouldEqual, `text/plain; charset="utf-8"; format="fixed"`) text, err := ioutil.ReadAll(part) So(err, ShouldBeNil) part, err = mpr.NextPart() So(err, ShouldBeNil) So(part.Header.Get("Content-Type"), ShouldEqual, `text/html; charset="utf-8"`) html, err := ioutil.ReadAll(part) So(err, ShouldBeNil) email := &templates.Email{ Header: h, Text: text, HTML: html, Attachments: []templates.Attachment{}, } for { part, err = mpr.NextPart() if err == io.EOF { break } So(err, ShouldBeNil) contentID := part.Header.Get("Content-ID") disposition := part.Header.Get("Content-Disposition") idx = strings.Index(disposition, `filename="`) So(idx, ShouldBeGreaterThan, -1) filename := disposition[idx+len(`filename="`):] idx = strings.IndexRune(filename, '"') So(idx, ShouldBeGreaterThan, -1) filename = filename[:idx] content, err := ioutil.ReadAll(part) So(err, ShouldBeNil) email.Attachments = append(email.Attachments, templates.Attachment{ Name: filename, ContentID: contentID, Content: content, }) } return email }
func (m *message) process() error { // chat recipient addrs, _ := m.headers.Header.AddressList("From") addr := addrs[0].Address //log.Printf("%d * FROM: %v", m.seq, addr) // date date, _ := m.headers.Header.Date() date = date.Local() //log.Printf("%d * DATE: %v", m.seq, date) // multipart boundary contentType := m.headers.Header.Get("Content-Type") boundaryRegexp, _ := regexp.Compile(`boundary="(.*)"`) boundary := boundaryRegexp.FindStringSubmatch(contentType)[1] //log.Printf("%d * BOUNDARY: %v", m.seq, boundary) // HTML mimeReader := multipart.NewReader(m.body.Body, boundary) mimeReader.NextPart() // skip the XML part html, _ := mimeReader.NextPart() buf := new(bytes.Buffer) buf.ReadFrom(html) body := buf.String() //log.Printf("%d * HTML: %v", m.seq, body) err := writeLog(addr, body, date) checkError(err) m.done = true return nil }
func (cs *clientSuite) TestClientOpTryMode(c *check.C) { cs.rsp = `{ "change": "66b3", "status-code": 202, "type": "async" }` snapdir := filepath.Join(c.MkDir(), "/some/path") for _, opts := range []*client.SnapOptions{ {DevMode: false, JailMode: false}, {DevMode: false, JailMode: true}, {DevMode: true, JailMode: true}, {DevMode: true, JailMode: false}, } { id, err := cs.cli.Try(snapdir, opts) c.Assert(err, check.IsNil) // ensure we send the right form-data _, params, err := mime.ParseMediaType(cs.req.Header.Get("Content-Type")) c.Assert(err, check.IsNil) mr := multipart.NewReader(cs.req.Body, params["boundary"]) formData := formToMap(c, mr) c.Check(formData, check.DeepEquals, map[string]string{ "action": "try", "snap-path": snapdir, "devmode": strconv.FormatBool(opts.DevMode), "jailmode": strconv.FormatBool(opts.JailMode), }) c.Check(cs.req.Method, check.Equals, "POST") c.Check(cs.req.URL.Path, check.Equals, fmt.Sprintf("/v2/snaps")) c.Assert(cs.req.Header.Get("Content-Type"), check.Matches, "multipart/form-data; boundary=.*") c.Check(id, check.Equals, "66b3") } }
func partsIterate(head getter, body io.Reader, emlbase string, errors chan error) { mediaType, params, err := mime.ParseMediaType(head.Get("Content-Type")) if err != nil || !strings.HasPrefix(mediaType, "multipart/") { return } mr := multipart.NewReader(body, params["boundary"]) for { p, err := mr.NextPart() if err == io.EOF { return } if err != nil { errors <- MessageError( fmt.Sprintf( "Problem opening a part of the %q message: %s", emlbase, err.Error())) return } partsIterate(p.Header, p, emlbase, errors) unpackPart(p, emlbase, errors) } }
func (Image) Post(values url.Values, request *http.Request, id int, adj string) (int, interface{}) { uploadFolder := "upload/" mediaType, params, err := mime.ParseMediaType(request.Header.Get("Content-Type")) checkErr(err, "Could Not Determine the Content Type") img := Image{} if strings.HasPrefix(mediaType, "multipart/") { log.Println("YOU ARE POSTING AN IMAGE") multipartReader := multipart.NewReader(request.Body, params["boundary"]) // Should Build buffer and Write it at the end (loop thour the nextpart !) partReader, err := multipartReader.NextPart() fileName := partReader.FileName() filePath := uploadFolder + fileName file, err := os.Create(filePath) if err != nil { log.Println(err) return 500, err } checkErr(err, "Could Not Get the Next Part") if _, err := io.Copy(file, partReader); err != nil { log.Fatal(err) return 500, err } // Let's record this image and return it to our client img = Image{Name: fileName, Path: filePath} recordedImg := img.save() log.Printf("Posted : %#v", img) return 200, recordedImg } else { return 500, "Nhope" } return 200, img }
// Ensure that a multipart message conforms to the specified description. func checkMultipart(r io.Reader, contentType string, d *multipartDesc) error { c, params, err := mime.ParseMediaType(contentType) if err != nil { return err } if c != d.ContentType { return fmt.Errorf("%s != %s", c, d.ContentType) } if len(d.Parts) == 0 { return attest.Read(r, d.Content) } boundary, ok := params["boundary"] if !ok { return errors.New("\"boundary\" parameter missing") } reader := multipart.NewReader(r, boundary) for _, part := range d.Parts { p, err := reader.NextPart() if err != nil { return err } if err := checkMultipart(p, p.Header.Get("Content-Type"), part); err != nil { return err } } return nil }
func parseMultipartContent(content, boundary string) (Content, error) { var ( reader *multipart.Reader = multipart.NewReader(strings.NewReader(content), boundary) part *multipart.Part mailParts Content = make(Content, 1) partHeader PMIMEHeader err error ) for { if part, err = reader.NextPart(); err == io.EOF { // 1) EOF error means, we're finished reading the multiparts break } else if err != nil { // 2) other errors are real => print a warning for that part and continue with the next fmt.Printf("[watney] WARNING: Couldn't parse multipart 'Part' Header & Content: %s\n", err.Error()) continue } // 3) Try to read the content of this multipart body ... if readBytes, err := ioutil.ReadAll(part); err != nil { fmt.Printf("[watney] WARNING: Couldn't read multipart body content: %s\n", err.Error()) continue } else { // 4) The body of this part has been successfully parsed => extract content if partHeader = parseMIMEHeader(part.Header); len(partHeader.ContentType) > 0 { // 5) We got a Content-Type, check if that one is multipart again if strings.Contains(partHeader.ContentType, "multipart") { // 5a) It is multipart => recursively add its parts if innerParts, err := parseMultipartContent(string(readBytes), partHeader.MultipartBoundary); err != nil { fmt.Printf("[watney] WARNING: Couldn't parse inner multipart body: %s\n", err.Error()) continue } else { for key, value := range innerParts { mailParts[key] = value } } } else { // 5b) We have a content type other than multipart, just add it mailParts[partHeader.ContentType] = ContentPart{ Encoding: partHeader.Encoding, Charset: "UTF-8", Body: string(readBytes), } } } else { // 4b) This part has no MIME information -> assume text/plain // ATTENTION: We're overwriting previously parsed text/plain parts mailParts["text/plain"] = ContentPart{ Encoding: "quoted-printable", Charset: "UTF-8", Body: string(readBytes), } } } } return mailParts, nil }
// DecoderFormData maps multipart/form-data => json.Decoder # because fuckit func DecoderFormData(r io.Reader, params map[string]string) (interface{}, locale.Error) { boundary, ok := params["boundary"] if !ok { return nil, locale.UntranslatedError(http.ErrMissingBoundary) } reader := multipart.NewReader(r, boundary) form, uerr := reader.ReadForm(0) if uerr != nil { return nil, locale.UntranslatedError(uerr) } entity := make(map[string]interface{}, len(form.Value)+len(form.File)) for k, v := range form.Value { entity[k] = v } for k, v := range form.File { if _, exists := entity[k]; exists { values := entity[k].([]string) list := make([]interface{}, len(values)+len(v)) i := uint(0) for _, value := range values { list[i] = value i++ } for _, value := range v { list[i] = value i++ } entity[k] = list } else { entity[k] = v } } return fuckitJSON(entity) }
// from https://github.com/bradfitz/websomtep/blob/master/websomtep.go func parseMultipart(r io.Reader, boundary string, mimetype string) (body io.Reader, err error) { mr := multipart.NewReader(r, boundary) for { var part *multipart.Part part, err = mr.NextPart() if err == io.EOF { break } if err != nil { return } partType, partParams, _ := mime.ParseMediaType(part.Header.Get("Content-Type")) if strings.HasPrefix(partType, "multipart/") { body, err = parseMultipart(part, partParams["boundary"], mimetype) if err != nil { // log.Printf("in boundary %q, returning error for multipart child %q: %v", boundary, partParams["boundary"], err) return } continue } if !strings.HasPrefix(partType, "text/") { continue } if partType == mimetype { body, err = decodePartBody(part) return } } return }
func TestBuildRequest_BuildHTTP_Files(t *testing.T) { cont, _ := ioutil.ReadFile("./client.go") reqWrtr := client.RequestWriterFunc(func(req client.Request, reg strfmt.Registry) error { req.SetFormParam("something", "some value") req.SetFileParam("file", "./client.go") req.SetQueryParam("hello", "world") req.SetPathParam("id", "1234") req.SetHeaderParam("X-Rate-Limit", "200") return nil }) r, _ := newRequest("GET", "/flats/{id}/", reqWrtr) r.SetHeaderParam(httpkit.HeaderContentType, httpkit.JSONMime) req, err := r.BuildHTTP(httpkit.JSONProducer(), nil) if assert.NoError(t, err) && assert.NotNil(t, req) { assert.Equal(t, "200", req.Header.Get("x-rate-limit")) assert.Equal(t, "world", req.URL.Query().Get("hello")) assert.Equal(t, "/flats/1234/", req.URL.Path) mediaType, params, err := mime.ParseMediaType(req.Header.Get(httpkit.HeaderContentType)) if assert.NoError(t, err) { assert.Equal(t, httpkit.MultipartFormMime, mediaType) boundary := params["boundary"] mr := multipart.NewReader(req.Body, boundary) frm, err := mr.ReadForm(1 << 20) if assert.NoError(t, err) { assert.Equal(t, "some value", frm.Value["something"][0]) mpff := frm.File["file"][0] mpf, _ := mpff.Open() assert.Equal(t, "client.go", mpff.Filename) actual, _ := ioutil.ReadAll(mpf) assert.Equal(t, cont, actual) } } } }
func parseGetObjectsResult(quit <-chan struct{}, boundary string, body io.ReadCloser) <-chan GetObjectResult { data := make(chan GetObjectResult) go func() { defer body.Close() defer close(data) partsReader := multipart.NewReader(body, boundary) for { part, err := partsReader.NextPart() switch { case err == io.EOF: return case err != nil: data <- GetObjectResult{nil, err} return } select { case data <- parseHeadersAndStream(part.Header, part): case <-quit: return } } }() return data }
func NewFileFromPart(part *multipart.Part) (File, error) { f := &MultipartFile{ Part: part, } contentType := part.Header.Get(contentTypeHeader) var params map[string]string var err error f.Mediatype, params, err = mime.ParseMediaType(contentType) if err != nil { return nil, err } if f.IsDirectory() { boundary, found := params["boundary"] if !found { return nil, http.ErrMissingBoundary } f.Reader = multipart.NewReader(part, boundary) } return f, nil }
func NewAxisCamera(host string, username, password string) (*AxisCamera, error) { const path = "/mjpg/video.mjpg" req, err := http.NewRequest("GET", "http://"+host+path, nil) if err != nil { return nil, err } if username != "" || password != "" { // TODO: may need stronger authentication req.SetBasicAuth(username, password) } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } // TODO: parse this out from Content-Type const boundary = "myboundary" r := multipart.NewReader(resp.Body, boundary) cam := &AxisCamera{ closer: resp.Body, mr: r, frames: make(chan *cv.IplImage), quit: make(chan struct{}), } go cam.fetchFrames() return cam, nil }
// read through the varios multiple parts func extractMime(con *data.Context, boundary string, bodyReader io.Reader) (e Email, err error) { mimeReader := multipart.NewReader(bodyReader, boundary) for { part, errT := mimeReader.NextPart() if errT == io.EOF { break } if errT != nil { return e, err } defer part.Close() result, errT := extract(con, part.Header, part) if errT != nil { con.Log.Errorf("Error in while calling extract in extractMime: %v", err) err = errT } if result != nil { e.Texts = append(e.Texts, result.Texts...) e.Images = append(e.Images, result.Images...) } } return e, err }
// parses the body of a message, using the given content-type. If the content // type is multipart, the parts slice will contain an entry for each part // present; otherwise, it will contain a single entry, with the entire (raw) // message contents. func parseBody(ct string, body []byte) (parts []Part, err error) { mt, ps, err := mime.ParseMediaType(ct) if err != nil { return } if mt != "multipart/alternative" { parts = append(parts, Part{ct, body, nil}) return } boundary, ok := ps["boundary"] if !ok { return nil, errors.New("multipart specified without boundary") } r := multipart.NewReader(bytes.NewReader(body), boundary) p, err := r.NextPart() for err == nil { data, _ := ioutil.ReadAll(p) // ignore error ct := p.Header["Content-Type"] part := Part{ct[0], data, p.Header} parts = append(parts, part) p, err = r.NextPart() } if err == io.EOF { err = nil } return }
// Extract plain text from multipart mime email. func readPlainTextFromMultipart(body string, multiBoundary string) (string, error) { multiReader := multipart.NewReader(strings.NewReader(body), multiBoundary) var plainTexts []string for { part, err := multiReader.NextPart() if err == io.EOF { break } else if err != nil { return "", err } partContentType := part.Header.Get("Content-Type") partContentEncoding := part.Header.Get("Content-Transfer-Encoding") partBodyBytes, err := ioutil.ReadAll(part) if err != nil { return "", err } partBody := string(partBodyBytes) partDecodedBody := decodeContent(partBody, partContentEncoding) partPlainText, err := readPlainText(partDecodedBody, partContentType) if err != nil { return "", err } plainTexts = append(plainTexts, partPlainText) } return strings.Join(plainTexts, ""), nil }
// ParsePlain disassembles a plain email message. func ParsePlain(ct string, body io.Reader) (*MailContent, error) { mc := new(MailContent) mc.Mode = modePLAIN boundary := extractValue(ct, "boundary") rdr := multipart.NewReader(body, boundary) for { if part, err := rdr.NextPart(); err == nil { ct = part.Header.Get("Content-Type") switch { case strings.HasPrefix(ct, "text/plain;"): data, err := ioutil.ReadAll(part) if err != nil { return nil, err } mc.Body = string(data) case strings.HasPrefix(ct, "application/pgp-keys;"): mc.Key, err = ioutil.ReadAll(part) if err != nil { return nil, err } default: return nil, errors.New("Unhandled MIME part: " + ct) } } else if err == io.EOF { break } else { return nil, err } } return mc, nil }
func testInlineAgainstStdLib(t *testing.T, msg *Message, rawBytes []byte) { // confirm stdlib can parse it too stdlibMsg, err := mail.ReadMessage(bytes.NewReader(rawBytes)) if err != nil { t.Fatal("Standard Library could not parse message:", err) } // confirm stdlib headers match our headers // StandardLibrary is not decoding Q-encoded headers. TODO: Re-enable when GoLang does this. //if !reflect.DeepEqual(map[string][]string(msg.Header), map[string][]string(stdlibMsg.Header)) { // t.Fatal("Message does not match its parsed counterpart") //} // confirm subsequent parts match mixedReader := multipart.NewReader(stdlibMsg.Body, boundary(map[string][]string(stdlibMsg.Header))) alternativePart, err := mixedReader.NextPart() if err != nil { t.Fatal("Couldn't get next part", err) } // test the multipart/alternative testMultipartInlineWithStdLib(t, msg.Parts[0], alternativePart) // test attachments attachmentPart, err := mixedReader.NextPart() if err != nil { t.Fatal("Couldn't get next part", err) } testBodyPartWithStdLib(t, msg.Parts[1], attachmentPart) // confirm EOF if _, err = mixedReader.NextPart(); err != io.EOF { t.Fatal("Should be EOF", err) } }
// ParseSigned reads an unencrypted, but signed message. func ParseSigned(ct, addr string, getInfo MailUserInfo, body io.Reader) (*MailContent, error) { mc := new(MailContent) mc.Mode = modeSIGN boundary := extractValue(ct, "boundary") rdr := multipart.NewReader(body, boundary) for { if part, err := rdr.NextPart(); err == nil { ct = part.Header.Get("Content-Type") switch { case strings.HasPrefix(ct, "text/plain;"): data, err := ioutil.ReadAll(part) if err != nil { return nil, err } mc.Body = string(data) case strings.HasPrefix(ct, "application/pgp-signature;"): id := getIdentity(getInfo, infoSENDER, addr) if id == nil { mc.Mode = modeUSIGN continue } buf := bytes.NewBufferString(mc.Body) if _, err := openpgp.CheckArmoredDetachedSignature(openpgp.EntityList{id}, buf, part); err != nil { return nil, err } logger.Println(logger.INFO, "Signature verified OK") } } else if err == io.EOF { break } else { return nil, err } } return mc, nil }
func testMultipartRelatedWithStdLib(t *testing.T, originalPart *Message, stdlibRelatedPart *multipart.Part) { // confirm stdlib headers match our headers if !reflect.DeepEqual(map[string][]string(originalPart.Header), map[string][]string(stdlibRelatedPart.Header)) { t.Fatal("Message does not match its parsed counterpart") } // multipart/related should have text/html, image/gif, and image/png parts relatedReader := multipart.NewReader(stdlibRelatedPart, boundary(map[string][]string(stdlibRelatedPart.Header))) htmlPart, err := relatedReader.NextPart() if err != nil { t.Fatal("Couldn't get next part", err) } testBodyPartWithStdLib(t, originalPart.Parts[0], htmlPart) gifPart, err := relatedReader.NextPart() if err != nil { t.Fatal("Couldn't get next part", err) } testBodyPartWithStdLib(t, originalPart.Parts[1], gifPart) pngPart, err := relatedReader.NextPart() if err != nil { t.Fatal("Couldn't get next part", err) } testBodyPartWithStdLib(t, originalPart.Parts[2], pngPart) // confirm EOF and Close if _, err = relatedReader.NextPart(); err != io.EOF || stdlibRelatedPart.Close() != nil { t.Fatal("Should be EOF", err) } }
func (s *S) TestExtractZip(c *gocheck.C) { boundary := "muchBOUNDARY" params := map[string]string{} var files = []File{ {"doge.txt", "Much doge"}, {"much.txt", "Much mucho"}, {"WOW/WOW.WOW1", "WOW\nWOW"}, {"WOW/WOW.WOW2", "WOW\nWOW"}, {"/usr/WOW/WOW.WOW3", "WOW\nWOW"}, {"/usr/WOW/WOW.WOW4", "WOW\nWOW"}, } buf, err := CreateZipBuffer(files) c.Assert(err, gocheck.IsNil) reader, writer := io.Pipe() go StreamWriteMultipartForm(params, "zipfile", "scaffold.zip", boundary, writer, buf) mpr := multipart.NewReader(reader, boundary) form, err := mpr.ReadForm(0) c.Assert(err, gocheck.IsNil) formfile := form.File["zipfile"][0] tempDir, err := ioutil.TempDir("", "TestCopyZipFileDir") defer func() { os.RemoveAll(tempDir) }() c.Assert(err, gocheck.IsNil) ExtractZip(formfile, tempDir) for _, file := range files { body, err := ioutil.ReadFile(path.Join(tempDir, file.Name)) c.Assert(err, gocheck.IsNil) c.Assert(string(body), gocheck.Equals, file.Body) } }
func selectMultiPart(msg *mail.Message, boundary, preferType string) (*mail.Message, error) { reader := multipart.NewReader(msg.Body, boundary) parts := make(map[string]*mail.Message) for part, err := reader.NextPart(); err != io.EOF; part, err = reader.NextPart() { if err != nil { return nil, err } header := mail.Header(part.Header) mediatype, _, err := mime.ParseMediaType(header.Get("Content-Type")) if err != nil { continue } if mediatype == preferType { return &mail.Message{header, part}, nil } types := strings.Split(mediatype, "/") if len(types) == 0 { continue } if _, ok := parts[types[0]]; !ok { body, err := ioutil.ReadAll(part) if err == nil { parts[types[0]] = &mail.Message{header, bytes.NewBuffer(body)} } } } types := strings.Split(preferType, "/") if part, ok := parts[types[0]]; ok { return part, nil } if part, ok := parts["multipart"]; ok { return part, nil } return nil, fmt.Errorf("No prefered part") }
// Get the reader for a particular Part of a multipart message. // This function is called recursively until we find a text/plain part. func partReader(part *multipart.Part) (io.Reader, error) { mediaType, params, err := mime.ParseMediaType(part.Header.Get("Content-Type")) if err != nil { return nil, err } if strings.HasPrefix(mediaType, "multipart/") { LOG.Println("inner-part boundary: %s\n", params["boundary"]) mpReader := multipart.NewReader(part, params["boundary"]) for { nextPart, err := mpReader.NextPart() if err == io.EOF { LOG.Println("Reached EOF while scanning inner message parts.") return nil, err } panicMaybe(err) nextReader, err := partReader(nextPart) if nextReader != nil { return nextReader, err } } } else if mediaType == "text/plain" { return part, nil } return nil, errors.New("Not a text/plain part") }