Beispiel #1
0
// 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)
	}
}
Beispiel #2
0
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{}{}
	}
}
Beispiel #3
0
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")
}
Beispiel #4
0
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)
	}
}
Beispiel #5
0
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)
	}
}
Beispiel #6
0
// 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
}
Beispiel #7
0
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
}
Beispiel #8
0
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
}
Beispiel #9
0
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
}
Beispiel #10
0
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")
	}
}
Beispiel #11
0
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)
	}
}
Beispiel #12
0
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
}
Beispiel #13
0
// 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
}
Beispiel #14
0
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
}
Beispiel #15
0
// 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)
}
Beispiel #16
0
// 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
}
Beispiel #17
0
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)
			}
		}
	}
}
Beispiel #18
0
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
}
Beispiel #20
0
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
}
Beispiel #21
0
// 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
}
Beispiel #22
0
// 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
}
Beispiel #23
0
// 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
}
Beispiel #24
0
// 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
}
Beispiel #25
0
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)
	}
}
Beispiel #26
0
// 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
}
Beispiel #27
0
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)
	}
}
Beispiel #28
0
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)
	}
}
Beispiel #29
0
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")
}
Beispiel #30
0
// 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")
}