@@ -199,11 +199,11 @@ def get(self, url, headers={}, **params):
199199
200200 def post (self , url , body = None , headers = {}, ** params ):
201201 url += self .urlEncode (params )
202- return self .request ('POST' , url , json . dumps ( body ) , headers )
202+ return self .request ('POST' , url , body , headers )
203203
204204 def put (self , url , body = None , headers = {}, ** params ):
205205 url += self .urlEncode (params )
206- return self .request ('PUT' , url , json . dumps ( body ) , headers )
206+ return self .request ('PUT' , url , body , headers )
207207
208208 def delete (self , url , headers = {}, ** params ):
209209 url += self .urlEncode (params )
@@ -215,7 +215,7 @@ def patch(self, url, body=None, headers={}, **params):
215215 Parameters is a dictionary that will will be url-encoded
216216 """
217217 url += self .urlEncode (params )
218- return self .request (self .PATCH , url , json . dumps ( body ) , headers )
218+ return self .request (self .PATCH , url , body , headers )
219219
220220 def request (self , method , url , body , headers ):
221221 '''Low-level networking. All HTTP-method methods call this'''
@@ -225,9 +225,9 @@ def request(self, method, url, body, headers):
225225 if self .username :
226226 headers ['authorization' ] = self .authHeader
227227
228- #TODO: Context manager
228+ reqBody = RequestBody ( body , headers )
229229 conn = self .getConnection ()
230- conn .request (method , url , body , headers )
230+ conn .request (method , url , reqBody . process () , headers )
231231 response = conn .getresponse ()
232232 status = response .status
233233 resBody = ResponseBody (response )
@@ -383,6 +383,59 @@ def application_json(self):
383383
384384 # Insert new media-type handlers here
385385
386+ class RequestBody (Body ):
387+ '''
388+ Encode a request body from the client, respecting the Content-Type
389+ field
390+ '''
391+ def __init__ (self , body , headers ):
392+ self .body = body
393+ self .headers = headers
394+ self .parseContentType (
395+ getattr (self .headers , 'content-type' , None )
396+ )
397+ self .encoding = self .ctypeParameters ['charset' ]
398+
399+ def encodeBody (self ):
400+ '''
401+ Encode (and overwrite) self.body via the charset encoding
402+ specified in the request headers
403+ '''
404+ self .body = self .body .encode (self .encoding )
405+
406+ def process (self ):
407+ '''
408+ Process the request body by applying a media-type specific
409+ handler to it. Some media-types need charset encoding as well,
410+ and it is up to the handler to do this by calling
411+ self.encodeBody()
412+ '''
413+ if self .body is None :
414+ return None
415+
416+ handlerName = self .funMangledMediaType ()
417+ handler = getattr ( self , handlerName ,
418+ self .application_octet_stream
419+ )
420+ return handler ()
421+
422+ ## media-type handlers
423+
424+ def application_octet_stream (self ):
425+ '''Handler for binary data and unknown media-types. Importantly,
426+ it does absolutely no pre-processing of the body, which means it
427+ will not mess it up.
428+ '''
429+ return self .body
430+
431+ def application_json (self ):
432+ self .body = json .dumps (self .body )
433+ self .encodeBody ()
434+ return self .body
435+
436+ # Insert new Request media-type handlers here
437+
438+
386439class ConnectionProperties (object ):
387440 __slots__ = ['api_url' , 'secure_http' , 'extra_headers' ]
388441
0 commit comments