github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/appengine/blobstore_mgt/my-multipart-parse.go (about)

     1  package blobstore_mgt
     2  
     3  import (
     4  	"bufio"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"mime"
    10  	"mime/multipart"
    11  	"net/http"
    12  	"net/textproto"
    13  
    14  	"net/url"
    15  	"strconv"
    16  	"strings"
    17  	"time"
    18  
    19  	"appengine"
    20  )
    21  
    22  
    23  
    24  // ParseUpload parses the synthetic POST request that your app gets from
    25  // App Engine after a user's successful upload of blobs. 
    26  func MyParseUpload(req *http.Request) (blobs map[string][]*BlobInfo, 
    27  	other url.Values, err error) {
    28  	
    29  	_, params, errCT := mime.ParseMediaType(req.Header.Get("Content-Type"))
    30  	if errCT != nil {
    31  		return nil, nil, errCT
    32  	}
    33  
    34  	boundary := params["boundary"]
    35  	if boundary == "" {
    36  		return nil, nil, fmt.Errorf("did not find MIME multipart boundary")
    37  	}
    38  
    39  	blobs = make(map[string][]*BlobInfo)
    40  	other = make(url.Values)
    41  
    42  	mreader := multipart.NewReader(io.MultiReader(req.Body, strings.NewReader("\r\n\r\n")), boundary)
    43  	cntr := 0
    44  	for {
    45  		part, perr := mreader.NextPart()
    46  		if perr == io.EOF {
    47  			break
    48  		}
    49  		if perr != nil {
    50  			return nil, nil, errorf("error reading next mime part with boundary %q (len=%d): %v",
    51  				boundary, len(boundary), perr)
    52  		}
    53  
    54  		bi := &BlobInfo{}
    55  		ctype, params, err := mime.ParseMediaType(part.Header.Get("Content-Disposition"))
    56  		if err != nil {
    57  			return nil, nil, err
    58  		}
    59  		bi.Filename = params["filename"]
    60  		pFile := params["post_field_file"] // WRONG
    61  		pFile = params["name"]
    62  
    63  		ctype, params, err = mime.ParseMediaType(part.Header.Get("Content-Type"))
    64  		if err != nil {
    65  			return nil, nil, err
    66  		}
    67  		
    68  
    69  		bi.BlobKey = appengine.BlobKey(params["blob-key"])
    70  		if ctype != "message/external-body" || bi.BlobKey == "" {
    71  			if pFile != "" {
    72  				slurp, serr := ioutil.ReadAll(part)
    73  				if serr != nil {
    74  					return nil, nil, errorf("error reading %q MIME part", pFile)
    75  				}
    76  				other[pFile] = append(other[pFile], string(slurp))
    77  			}
    78  			continue
    79  		}
    80  
    81  
    82  		// App Engine sends a MIME header as the body of each MIME part.
    83  		tp := textproto.NewReader(bufio.NewReader(part))
    84  
    85  
    86  		header, mimeerr := tp.ReadMIMEHeader()
    87  		if mimeerr != nil {
    88  			s := mimeerr.Error()
    89  			if strings.HasPrefix(s, "malformed MIME header") {
    90  				return nil, nil, fmt.Errorf("'malformed'  %q", mimeerr)
    91  			} else {
    92  				return nil, nil, fmt.Errorf("error reading again %q", mimeerr)
    93  			}
    94  		}
    95  
    96  		bi.Size, err = strconv.ParseInt(header.Get("Content-Length"), 10, 64)
    97  		if err != nil {
    98  			return nil, nil, err
    99  		}
   100  		bi.ContentType = header.Get("Content-Type")
   101  
   102  		// Parse the time from the MIME header like:
   103  		// X-AppEngine-Upload-Creation: 2011-03-15 21:38:34.712136
   104  		createDate := header.Get("X-AppEngine-Upload-Creation")
   105  		if createDate == "" {
   106  			return nil, nil, fmt.Errorf("expected to find an X-AppEngine-Upload-Creation header")
   107  		}
   108  		bi.CreationTime, err = time.Parse("2006-01-02 15:04:05.000000", createDate)
   109  		if err != nil {
   110  			return nil, nil, fmt.Errorf("error parsing X-AppEngine-Upload-Creation: %s", err)
   111  		}
   112  
   113  		if hdr := header.Get("Content-MD5"); hdr != "" {
   114  			md5, err := base64.URLEncoding.DecodeString(hdr)
   115  			if err != nil {
   116  				return nil, nil, fmt.Errorf("bad Content-MD5 %q: %v", hdr, err)
   117  			}
   118  			bi.MD5 = string(md5)
   119  		}
   120  
   121  
   122  		if pFile != "" {
   123  			// slurp, serr := ioutil.ReadAll(part)
   124  			// if serr != nil {
   125  			// 	return nil, nil, fmt.Errorf("error reading all from %q", pFile)
   126  			// }
   127  			// other[pFile] = append(other[pFile], string(slurp))
   128  		}
   129  
   130  		blobs[pFile] = append(blobs[pFile], bi)
   131  		cntr++
   132  	}
   133  	return
   134  }
   135  
   136  
   137  
   138