mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
166 lines
4.5 KiB
Python
166 lines
4.5 KiB
Python
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
|
|
"""Encoding for arguments to HTTP calls.
|
|
Uses the url-encoding with MIME type 'application/x-www-form-urlencoded'
|
|
if the data does not include files. Otherwise it uses the encoding with
|
|
MIME type 'multipart/form-data'. See the HTML4 spec for details.
|
|
|
|
"""
|
|
import sys
|
|
import types
|
|
from StringIO import StringIO
|
|
|
|
import urllib
|
|
import httplib
|
|
import random
|
|
import md5
|
|
|
|
# Extract from HTML4 spec.
|
|
## The following example illustrates "multipart/form-data"
|
|
## encoding. Suppose we have the following form:
|
|
|
|
## <FORM action="http://server.com/cgi/handle"
|
|
## enctype="multipart/form-data"
|
|
## method="post">
|
|
## <P>
|
|
## What is your name? <INPUT type="text" name="submit-name"><BR>
|
|
## What files are you sending? <INPUT type="file" name="files"><BR>
|
|
## <INPUT type="submit" value="Send"> <INPUT type="reset">
|
|
## </FORM>
|
|
|
|
## If the user enters "Larry" in the text input, and selects the text
|
|
## file "file1.txt", the user agent might send back the following data:
|
|
|
|
## Content-Type: multipart/form-data; boundary=AaB03x
|
|
|
|
## --AaB03x
|
|
## Content-Disposition: form-data; name="submit-name"
|
|
|
|
## Larry
|
|
## --AaB03x
|
|
## Content-Disposition: form-data; name="files"; filename="file1.txt"
|
|
## Content-Type: text/plain
|
|
|
|
## ... contents of file1.txt ...
|
|
## --AaB03x--
|
|
|
|
## If the user selected a second (image) file "file2.gif", the user agent
|
|
## might construct the parts as follows:
|
|
|
|
## Content-Type: multipart/form-data; boundary=AaB03x
|
|
|
|
## --AaB03x
|
|
## Content-Disposition: form-data; name="submit-name"
|
|
|
|
## Larry
|
|
## --AaB03x
|
|
## Content-Disposition: form-data; name="files"
|
|
## Content-Type: multipart/mixed; boundary=BbC04y
|
|
|
|
## --BbC04y
|
|
## Content-Disposition: file; filename="file1.txt"
|
|
## Content-Type: text/plain
|
|
|
|
## ... contents of file1.txt ...
|
|
## --BbC04y
|
|
## Content-Disposition: file; filename="file2.gif"
|
|
## Content-Type: image/gif
|
|
## Content-Transfer-Encoding: binary
|
|
|
|
## ...contents of file2.gif...
|
|
## --BbC04y--
|
|
## --AaB03x--
|
|
|
|
__all__ = ['encode_data', 'encode_multipart', 'encode_form', 'mime_boundary' ]
|
|
|
|
def data_values(d):
|
|
if isinstance(d, types.DictType):
|
|
return d.items()
|
|
else:
|
|
return d
|
|
|
|
def encode_data(d):
|
|
"""Encode some data for HTTP transport.
|
|
The encoding used is stored in 'Content-Type' in the headers.
|
|
|
|
d data - sequence of tuples or dictionary
|
|
returns a 2-tuple of the headers and the encoded data
|
|
"""
|
|
val = ({}, None)
|
|
if d is None: return val
|
|
multipart = 0
|
|
for (k, v) in data_values(d):
|
|
if encode_isfile(v):
|
|
multipart = 1
|
|
break
|
|
if multipart:
|
|
val = encode_multipart(d)
|
|
else:
|
|
val = encode_form(d)
|
|
return val
|
|
|
|
def encode_isfile(v):
|
|
if isinstance(v, types.FileType):
|
|
return 1
|
|
if hasattr(v, 'readlines'):
|
|
return 1
|
|
return 0
|
|
|
|
def encode_multipart(d):
|
|
boundary = mime_boundary()
|
|
hdr = { 'Content-Type': 'multipart/form-data; boundary=' + boundary }
|
|
out = StringIO()
|
|
for (k,v) in data_values(d):
|
|
out.write('--')
|
|
out.write(boundary)
|
|
out.write('\r\n')
|
|
if encode_isfile(v):
|
|
out.write('Content-Disposition: form-data; name="')
|
|
out.write(k)
|
|
if hasattr(v, 'name'):
|
|
out.write('"; filename="')
|
|
out.write(v.name)
|
|
out.write('"\r\n')
|
|
out.write('Content-Type: application/octet-stream\r\n')
|
|
out.write('\r\n')
|
|
for l in v.readlines():
|
|
out.write(l)
|
|
else:
|
|
out.write('Content-Disposition: form-data; name="')
|
|
out.write(k)
|
|
out.write('"\r\n')
|
|
out.write('\r\n')
|
|
out.write(str(v))
|
|
out.write('\r\n')
|
|
out.write('--')
|
|
out.write(boundary)
|
|
out.write('--')
|
|
out.write('\r\n')
|
|
return (hdr, out.getvalue())
|
|
|
|
def mime_boundary():
|
|
random.seed()
|
|
m = md5.new()
|
|
for i in range(0, 10):
|
|
c = chr(random.randint(1, 255))
|
|
m.update(c)
|
|
b = m.hexdigest()
|
|
return b[0:16]
|
|
|
|
def encode_form(d):
|
|
hdr = { 'Content-Type': 'application/x-www-form-urlencoded' }
|
|
val = urllib.urlencode(d)
|
|
return (hdr, val)
|
|
|
|
def main():
|
|
#d = {'a': 1, 'b': 'x y', 'c': file('conf.sxp') }
|
|
#d = {'a': 1, 'b': 'x y' }
|
|
d = [ ('a', 1), ('b', 'x y'), ('c', file('conf.sxp')) ]
|
|
#d = [ ('a', 1), ('b', 'x y')]
|
|
v = encode_data(d)
|
|
print v[0]
|
|
sys.stdout.write(v[1])
|
|
print
|
|
|
|
if __name__ == "__main__":
|
|
main()
|