Commits

Anonymous committed da67e8d

fix empty body, redirection & error

  • Participants
  • Parent commits 941d63c

Comments (0)

Files changed (4)

File restkit/httpc.py

 import copy
 import httplib
 import re
+import socket
 import StringIO
 import types
 import urllib
         connection = self._get_connection(uri, headers)
         connection.debuglevel = restkit.debuglevel
         
-        if connection.host != uri.hostname:
-            connection.putrequest(method, uri.geturl())
-        else:
-            connection.putrequest(method, _relative_uri(uri))
+        for i in range(2):
+            try:
+                if connection.host != uri.hostname:
+                    connection.putrequest(method, uri.geturl())
+                else:
+                    connection.putrequest(method, _relative_uri(uri))
         
-        # bug in Python 2.4 and 2.5
-        # httplib.HTTPConnection.putrequest adding 
-        # HTTP request header 'Host: domain.tld:443' instead of
-        # 'Host: domain.tld'
-        if (uri.scheme == 'https' and (uri.port or 443) == 443 and
-                hasattr(connection, '_buffer') and
-                isinstance(connection._buffer, list)):
-            header_line = 'Host: %s:443' % uri.hostname
-            replacement_header_line = 'Host: %s' % uri.hostname
-            try:
-                connection._buffer[connection._buffer.index(header_line)] = (
-                    replacement_header_line)
-            except ValueError:  # header_line missing from connection._buffer
-                pass
+                # bug in Python 2.4 and 2.5
+                # httplib.HTTPConnection.putrequest adding 
+                # HTTP request header 'Host: domain.tld:443' instead of
+                # 'Host: domain.tld'
+                if (uri.scheme == 'https' and (uri.port or 443) == 443 and
+                        hasattr(connection, '_buffer') and
+                        isinstance(connection._buffer, list)):
+                    header_line = 'Host: %s:443' % uri.hostname
+                    replacement_header_line = 'Host: %s' % uri.hostname
+                    try:
+                        connection._buffer[connection._buffer.index(header_line)] = (
+                            replacement_header_line)
+                    except ValueError:  # header_line missing from connection._buffer
+                        pass
         
-        # Send the HTTP headers.
-        for header_name, value in headers.iteritems():
-          connection.putheader(header_name, value)
-        connection.endheaders()
+                # Send the HTTP headers.
+                for header_name, value in headers.iteritems():
+                    connection.putheader(header_name, value)
+                connection.endheaders()
         
-        if body:
-            if isinstance(body, types.StringTypes) or hasattr(body, 'read'):
-                _send_body_part(body, connection)
-            else:
-                for part in body_parts:
-                    _send_body_part(part, connection)
+                if body is not None:
+                    if i > 0 and hasattr(body, 'seek'):
+                        body.seek(0)
+                        
+                    if isinstance(body, types.StringTypes) and len(body) == 0:
+                        connection.send("")
+                    elif isinstance(body, types.StringTypes) or hasattr(body, 'read'):
+                        _send_body_part(body, connection)
+                    else:
+                        for part in body_parts:
+                            _send_body_part(part, connection)
+                    
+            except socket.gaierror:
+                connection.close()
+                raise errors.ResourceNotFound("Unable to find the server at %s" % connection.host, 404)
+            except (socket.error, httplib.HTTPException):
+                if i == 0:
+                    connection.close()
+                    continue
+                else:
+                    raise
+            break
                     
         # Return the HTTP Response from the server.
         return connection.getresponse()
         
-    def request(self, url, method='GET', body=None, headers=None, stream=False, stream_size=16384,
-            nb_redirections=0):  
-        headers = headers or {}
-        uri = url_parser(url)
-        
-        headers.setdefault('User-Agent', restkit.USER_AGENT)
+    def _request(self, uri, method, body, headers, nb_redirections=0):
         auths = [(auth.depth(uri), auth) for auth in self.authorizations if auth.inscope(uri.hostname, uri)]
         auth = auths and sorted(auths)[0][1] or None
         if auth:
-            auth.request(url, method, body, headers)
+            auth.request(uri, method, body, headers)
             
         headers = _normalize_headers(headers)
         old_response = None
         
         response = self._make_request(uri, method, body, headers)
-        
+            
         if auth and auth.response(response, body):
-            auth.request(method, request_uri, headers, body)
-            response = self._make_request(conn, request_uri, method, body, headers)
-            
+            auth.request(method, uri, headers, body)
+            response = self._make_request(conn, uri, method, body, headers)
             
         if self.follow_redirect:
             if nb_redirections < self.MAX_REDIRECTIONS: 
                 if response.status in [301, 302, 307]:
                     if method in ["GET", "HEAD"] or self.force_follow_redirect:
-                        old_response = copy.deepcopy(response)
-                        new_url = response['location']
-                        response = self.request(new_url, method, body, headers, 
-                            nb_redirections + 1)
-                elif response.status == 303:
-                    new_url = response['location']
-                    response = self.request(new_url, 'GET', headers)
+                        if method not in ["GET", "HEAD"] and hasattr(body, 'seek'):
+                            body.seek(0)
+                        
+                        new_url = response.getheader('location')
+                        new_uri = url_parser(new_url)
+                        if not new_uri.netloc: # we got a relative url
+                            absolute_uri = "%s://%s" % (uri.scheme, uri.netloc)
+                            new_url = urlparse.urljoin(absolute_uri, new_url)
+                        response = self._request(url_parser(new_url), method, body, 
+                            headers, nb_redirections + 1)
+                        self.final_url = new_url
+                elif response.status == 303: # only get request on this status
+                    new_url = response.getheader('location')
+                    if not new_uri.netloc: # we got a relative url
+                        absolute_uri = "%s://%s" % (uri.scheme, uri.netloc)
+                        new_uri = url_parser(new_url)
+                        new_url = urlparse.urljoin(absolute_uri, new_url)
+                    response = self._request(url_parser(new_url), 'GET', headers, nb_redirections + 1)
+                    self.final_url = new_url
             else:
                 raise errors.RedirectLimit("Redirection limit is reached")
+        return response
         
+    def request(self, url, method='GET', body=None, headers=None, stream=False, stream_size=16384):  
+        headers = headers or {}
+        uri = url_parser(url)
+        self.final_url = url
+        
+        headers.setdefault('User-Agent', restkit.USER_AGENT)
+        if method in ["POST", "PUT"] and body is None:
+            body = ""
+            headers.setdefault("Content-Length", str(len(body)))
+            
+        print headers
+        response = self._request(uri, method, body, headers)
         resp = HTTPResponse(response)
+        resp.final_url = self.final_url
+        
         if method == "HEAD":
             return resp, ""
         else:

File restkit/rest.py

         
         is_unicode = True
         
-        if body and body is not None and 'Content-Length' not in headers:
+        if body is not None and 'Content-Length' not in headers:
             if isinstance(body, file):
                 try:
                     body.flush()

File tests/_server_test.py

                     self._respond(200, extra_headers, "ok")
                 else:
                     self._respond(403, extra_headers, "niet!")
+        elif path == "/redirect":
+            extra_headers = [('Content-type', 'text/plain'), 
+                ('Location', '/complete_redirect')]
+            self._respond(301, extra_headers, "")
+        elif path == "/complete_redirect":
+            extra_headers = [('Content-type', 'text/plain')]
+            self._respond(200, extra_headers, "ok")
         else:
             self._respond(404, 
                 [('Content-type', 'text/plain')], "Not Found" )

File tests/httpc_test.py

     def testGetWithQuery(self):
         result = self.res.get('/query', test="testing")
         self.assert_(self.res.response.status == 200)
+        self.assert_(result == "ok")
+        self.assert_(self.res.response.status == 200)
 
     def testGetBinary(self):
         import imghdr
         f.close()
         self.assert_(imghdr.what(fname) == 'gif')
 
-
+    def testGetRedirect(self):
+        result = self.res.get('/redirect')
+        complete_url = "%s/complete_redirect" % self.url
+        self.assert_(self.res.response.status == 200)
+        self.assert_(self.res.response.final_url == complete_url)
+        self.assert_(result == "ok")
+        
     def testSimplePost(self):
         result = self.res.post(payload="test")
         self.assert_(result=="test")