Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where is mimetools.choose_boundary function in Python3?

I currently want to use the following piece of code in Python3, but found the function mimetools.choose_boundary to be deprecated, how to change the code and make it works?

import re
from urllib.request import urlopen, Request
import os 
import mimetypes 
import mimetools 

def get_content_type(filepath): 
    return mimetypes.guess_type(filepath)[0] or 'application/octet-stream' 

def encode_multipart_formdata(fields, files=[]): 
    """
    fields is a sequence of (name, value) elements for regular form fields.
    files is a sequence of (name, filepath) elements for data to be uploaded as files
    Return (content_type, body) ready for httplib.HTTP instance
    """ 
    BOUNDARY = mimetools.choose_boundary() 
    CRLF = '\r\n' 
    L = [] 
    for (key, value) in fields: 
        L.append('--' + BOUNDARY) 
        L.append('Content-Disposition: form-data; name="%s"' % key) 
        L.append('') 
        L.append(value) 
    for (key, filepath) in files: 
        L.append('--' + BOUNDARY) 
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, os.path.basename(filepath))) 
        L.append('Content-Type: %s' % get_content_type(filepath)) 
        L.append('') 
        L.append(open(filepath, 'rb').read()) 
    L.append('--' + BOUNDARY + '--') 
    L.append('') 
    body = CRLF.join(L) 
    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY 
    return content_type, body 
like image 685
Alfred Huang Avatar asked Nov 24 '14 06:11

Alfred Huang


1 Answers

Well, I answer my question since no other available answer here.

Yes, I got the result finally, for more info about my work around the question, the below information may help.


1. What does boundary do in an multipart/form-data request?

In fact, to separate the different parts of data is such a request, we use a separator, here we call boundary, to divide the form data.

These parts may be field value (plain text), or uploading file contents.

2. First we put the boundary string in the request header.

To claim a request to be accepted as a mulitipart/form-data format, we first choose a special string, called boundary, and put it in the request header:

Content-Type: multipart/form-data; boundary=FORM-BOUNDARY

Seeing that we choose the boundary string to be FORM-BOUNDARY here, in fact we can choose any string we want.

Most time we may choose a long, randomly string, to prevent collision.

3. Use the chosen boundary in the request body.

In the request body (payload), we separate the data with the boundary separator, for example:

--FORM-BOUNDARY
Content-Disposition: form-data; name="template"; filename=".xls"
Content-Type: application/vnd.ms-excel

A654ADE5^%^#%@%$@ (BINARY DATA IN THIS SECTION)
--FORM-BOUNDARY
Content-Disposition: form-data; name="username"

admin
--FORM-BOUNDARY
Content-Disposition: form-data; name="password"

admin_password
--FORM-BOUNDARY--

Seeing that, we start one form-part with a separator, with the boundary after a single -- symbol.

Then in that form-part, we export the header to claim the content type and the name of that posted field.

Then a single blank line is required.

Then we export the value(data) of that form-part.

After all form-parts, we ended the request body with a separator, with the boundary between two -- symbol.

4. So what does mimetools.choose_boundary do then?

In fact, this function (deprecated since py3) generate a random boundary, with a specified format, see: https://docs.python.org/2.7/library/mimetools.html?highlight=choose_boundary#mimetools.choose_boundary

The format is:

'hostipaddr.uid.pid.timestamp.random'

Just that simple.

If we insist on getting the same result,

  1. we can write the functional by ourselves.
  2. Or call the email.generator module's _make_boundary() function.

But in fact, to make it work, no need to do that, just generate a random string to replace it!

like image 64
Alfred Huang Avatar answered Sep 22 '22 21:09

Alfred Huang