@@ -153,16 +153,14 @@ def get(self, url, headers={}, **params):
153153 def post (self , url , body = None , headers = {}, ** params ):
154154 url += self .urlencode (params )
155155 if not 'content-type' in headers :
156- # We're doing a json.dumps of body, so let's set the content-type to json
157156 headers ['content-type' ] = 'application/json'
158- return self .request ('POST' , url , json . dumps ( body ) , headers )
157+ return self .request ('POST' , url , body , headers )
159158
160159 def put (self , url , body = None , headers = {}, ** params ):
161160 url += self .urlencode (params )
162161 if not 'content-type' in headers :
163- # We're doing a json.dumps of body, so let's set the content-type to json
164162 headers ['content-type' ] = 'application/json'
165- return self .request ('PUT' , url , json . dumps ( body ) , headers )
163+ return self .request ('PUT' , url , body , headers )
166164
167165 def delete (self , url , headers = {}, ** params ):
168166 url += self .urlencode (params )
@@ -175,19 +173,19 @@ def patch(self, url, body=None, headers={}, **params):
175173 """
176174 url += self .urlencode (params )
177175 if not 'content-type' in headers :
178- # We're doing a json.dumps of body, so let's set the content-type to json
179176 headers ['content-type' ] = 'application/json'
180- return self .request ('PATCH' , url , json . dumps ( body ) , headers )
177+ return self .request ('PATCH' , url , body , headers )
181178
182- def request (self , method , url , body , headers ):
179+ def request (self , method , url , bodyData , headers ):
183180 '''Low-level networking. All HTTP-method methods call this'''
184181
185182 headers = self ._fix_headers (headers )
186183 url = self .prop .constructUrl (url )
187184
188185 #TODO: Context manager
186+ requestBody = RequestBody (bodyData , headers )
189187 conn = self .get_connection ()
190- conn .request (method , url , body , headers )
188+ conn .request (method , url , requestBody . process () , headers )
191189 response = conn .getresponse ()
192190 status = response .status
193191 content = ResponseBody (response )
@@ -327,6 +325,56 @@ def application_json(self):
327325
328326 # Insert new media-type handlers here
329327
328+ class RequestBody (Body ):
329+ '''
330+ Encode a request body from the client, respecting the Content-Type
331+ field
332+ '''
333+ def __init__ (self , body , headers ):
334+ self .body = body
335+ self .headers = headers
336+ self .parseContentType (
337+ getattr (self .headers , 'content-type' , None ))
338+ self .encoding = self .ctypeParameters ['charset' ]
339+
340+ def encodeBody (self ):
341+ '''
342+ Encode (and overwrite) self.body via the charset encoding
343+ specified in the request headers. This should be called by the
344+ media-type handler when appropriate
345+ '''
346+ self .body = self .body .encode (self .encoding )
347+
348+ def process (self ):
349+ '''
350+ Process the request body by applying a media-type specific
351+ handler to it.
352+ '''
353+ if self .body is None :
354+ return None
355+
356+ handlerName = self .funMangledMediaType ()
357+ handler = getattr ( self , handlerName ,
358+ self .application_octet_stream
359+ )
360+ return handler ()
361+
362+ ## media-type handlers
363+
364+ def application_octet_stream (self ):
365+ '''Handler for binary data and unknown media-types. Importantly,
366+ it does absolutely no pre-processing of the body, which means it
367+ will not mess it up.
368+ '''
369+ return self .body
370+
371+ def application_json (self ):
372+ self .body = json .dumps (self .body )
373+ self .encodeBody ()
374+ return self .body
375+
376+ # Insert new Request media-type handlers here
377+
330378class ConnectionProperties (object ):
331379 __slots__ = ['api_url' , 'url_prefix' , 'secure_http' , 'extra_headers' ]
332380
0 commit comments