Package restkit :: Module forms
[hide private]
[frames] | no frames]

Source Code for Module restkit.forms

  1  # -*- coding: utf-8 - 
  2  # 
  3  # This file is part of restkit released under the MIT license.  
  4  # See the NOTICE for more information. 
  5   
  6   
  7  import mimetypes 
  8  import os 
  9  import re 
 10  import urllib 
 11   
 12   
 13  from restkit.util import to_bytestring, url_quote 
 14   
 15  MIME_BOUNDARY = 'END_OF_PART' 
 16  CRLF = '\r\n' 
 17   
18 -def form_encode(obj, charser="utf8"):
19 tmp = [] 20 for key, value in obj.items(): 21 tmp.append("%s=%s" % (url_quote(key), 22 url_quote(value))) 23 return to_bytestring("&".join(tmp))
24 25
26 -class BoundaryItem(object):
27 - def __init__(self, name, value, fname=None, filetype=None, filesize=None):
28 self.name = url_quote(name) 29 if value is not None and not hasattr(value, 'read'): 30 value = self.encode_unreadable_value(value) 31 self.size = len(value) 32 self.value = value 33 if fname is not None: 34 if isinstance(fname, unicode): 35 fname = fname.encode("utf-8").encode("string_escape").replace('"', '\\"') 36 else: 37 fname = fname.encode("string_escape").replace('"', '\\"') 38 self.fname = fname 39 if filetype is not None: 40 filetype = to_bytestring(filetype) 41 self.filetype = filetype 42 43 if isinstance(value, file) and filesize is None: 44 try: 45 value.flush() 46 except IOError: 47 pass 48 self.size = int(os.fstat(value.fileno())[6]) 49 50 self._encoded_hdr = None 51 self._encoded_bdr = None
52
53 - def encode_hdr(self, boundary):
54 """Returns the header of the encoding of this parameter""" 55 if not self._encoded_hdr or self._encoded_bdr != boundary: 56 boundary = url_quote(boundary) 57 self._encoded_bdr = boundary 58 headers = ["--%s" % boundary] 59 if self.fname: 60 disposition = 'form-data; name="%s"; filename="%s"' % (self.name, 61 self.fname) 62 else: 63 disposition = 'form-data; name="%s"' % self.name 64 headers.append("Content-Disposition: %s" % disposition) 65 if self.filetype: 66 filetype = self.filetype 67 else: 68 filetype = "text/plain; charset=utf-8" 69 headers.append("Content-Type: %s" % filetype) 70 headers.append("Content-Length: %i" % self.size) 71 headers.append("") 72 headers.append("") 73 self._encoded_hdr = CRLF.join(headers) 74 return self._encoded_hdr
75
76 - def encode(self, boundary):
77 """Returns the string encoding of this parameter""" 78 value = self.value 79 if re.search("^--%s$" % re.escape(boundary), value, re.M): 80 raise ValueError("boundary found in encoded string") 81 82 return "%s%s%s" % (self.encode_hdr(boundary), value, CRLF)
83
84 - def iter_encode(self, boundary, blocksize=16384):
85 if not hasattr(self.value, "read"): 86 yield self.encode(boundary) 87 else: 88 yield self.encode_hdr(boundary) 89 while True: 90 block = self.value.read(blocksize) 91 if not block: 92 yield CRLF 93 return 94 yield block
95
96 - def encode_unreadable_value(self, value):
97 return url_quote(value)
98 99
100 -class MultipartForm(object):
101 - def __init__(self, params, boundary, headers, bitem_cls=BoundaryItem):
102 self.boundary = boundary 103 self.tboundary = "--%s--%s" % (boundary, CRLF) 104 self.boundaries = [] 105 self._clen = headers.get('Content-Length') 106 107 if hasattr(params, 'items'): 108 params = params.items() 109 110 for param in params: 111 name, value = param 112 if hasattr(value, "read"): 113 fname = getattr(value, 'name') 114 if fname is not None: 115 filetype = ';'.join(filter(None, mimetypes.guess_type(fname))) 116 else: 117 filetype = None 118 if not isinstance(value, file) and self._clen is None: 119 value = value.read() 120 121 boundary = bitem_cls(name, value, fname, filetype) 122 else: 123 boundary = bitem_cls(name, value) 124 self.boundaries.append(boundary)
125
126 - def get_size(self):
127 if self._clen is None: 128 self._clen = 0 129 for boundary in self.boundaries: 130 self._clen += boundary.size 131 self._clen += len(boundary.encode_hdr(self.boundary)) 132 self._clen += len(CRLF) 133 self._clen += len(self.tboundary) 134 return int(self._clen)
135
136 - def __iter__(self):
137 for boundary in self.boundaries: 138 for block in boundary.iter_encode(self.boundary): 139 yield block 140 yield self.tboundary
141 142
143 -def multipart_form_encode(params, headers, boundary):
144 headers = headers or {} 145 boundary = urllib.quote_plus(boundary) 146 body = MultipartForm(params, boundary, headers) 147 headers['Content-Type'] = "multipart/form-data; boundary=%s" % boundary 148 headers['Content-Length'] = str(body.get_size()) 149 return body, headers
150