1. Randall Leeds
  2. restkit

Commits

benoitc  committed 40be280 Merge

merge threadsafe branch

  • Participants
  • Parent commits 7635881, f4bfb95
  • Branches default

Comments (0)

Files changed (10)

File .hgignore

View file
 *.beam
 *.log
 restkit.egg-info
-
+dist/
 doc/_build/
 
 syntax: regexp

File restkit/errors.py

File contents unchanged.

File restkit/ext/__init__.py

Empty file added.

File restkit/ext/eventlet_pool.py

View file
+# -*- coding: utf-8 -
+#
+# Copyright (c) 2008, 2009 Benoit Chesneau <benoitc@e-engura.com> 
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import os
+
+from eventlet.green import socket
+from eventlet.green import httplib
+from eventlet.pools import Pool
+from eventlet.util import wrap_socket_with_coroutine_socket
+wrap_socket_with_coroutine_socket()
+
+def make_proxy_connection(uri):
+    headers = headers or {}
+    proxy = None
+    if uri.scheme == 'https':
+        proxy = os.environ.get('https_proxy')
+    elif uri.scheme == 'http':
+        proxy = os.environ.get('http_proxy')
+
+    if not proxy:
+        return make_connection(uri, use_proxy=False)
+  
+    if uri.scheme == 'https':
+        proxy_auth = _get_proxy_auth()
+        if proxy_auth:
+            proxy_auth = 'Proxy-authorization: %s' % proxy_auth
+        port = uri.port
+        if not port:
+            port = 443
+        proxy_connect = 'CONNECT %s:%s HTTP/1.0\r\n' % (uri.hostname, port)
+        user_agent = 'User-Agent: %s\r\n' % restkit.USER_AGENT
+        proxy_pieces = '%s%s%s\r\n' % (proxy_connect, proxy_auth, user_agent)
+        proxy_uri = url_parser(proxy)
+        if not proxy_uri.port:
+            proxy_uri.port = '80'
+        # Connect to the proxy server, very simple recv and error checking
+        p_sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
+        p_sock.connect((proxy_uri.host, int(proxy_uri.port)))
+        p_sock.sendall(proxy_pieces)
+        response = ''
+        # Wait for the full response.
+        while response.find("\r\n\r\n") == -1:
+            response += p_sock.recv(8192)
+        p_status = response.split()[1]
+        if p_status != str(200):
+            raise ProxyError('Error status=%s' % str(p_status))
+        # Trivial setup for ssl socket.
+        ssl = socket.ssl(p_sock, None, None)
+        fake_sock = httplib.FakeSocket(p_sock, ssl)
+        # Initalize httplib and replace with the proxy socket.
+        connection = httplib.HTTPConnection(proxy_uri.host)
+        connection.sock=fake_sock
+        return connection
+    else:
+        proxy_uri = url_parser(proxy)
+        if not proxy_uri.port:
+            proxy_uri.port = '80'
+        return httplib.HTTPConnection(proxy_uri.hostname, proxy_uri.port)
+    return None
+    
+def make_connection(uri, use_proxy=True):
+    if use_proxy:
+        return make_proxy_connection(uri)
+    
+    if uri.scheme == 'https':
+        if not uri.port:
+            connection = httplib.HTTPSConnection(uri.hostname)
+        else:
+            connection = httplib.HTTPSConnection(uri.hostname, uri.port)
+    else:
+        if not uri.port:
+            connection = httplib.HTTPConnection(uri.hostname)
+        else:
+            connection = httplib.HTTPConnection(uri.hostname, uri.port)
+    return connection
+
+
+class ConnectionPool(Pool):
+    def __init__(self, uri, use_proxy=False, min_size=0, max_size=4):
+        self.uri = uri
+        self.use_proxy = use_proxy
+        Pool.__init__(self, min_size, max_size)
+    
+    def create(self):
+        return make_connection(self.uri, self.use_proxy)
+           
+    def put(self, connection):
+        try:
+            connection.close()
+        except:
+            pass
+        Pool.put(self, make_connection(self.uri, self.use_proxy))

File restkit/httpc.py

View file
 
 import restkit
 from restkit import errors
+from restkit.pool import ConnectionPool
 from restkit.utils import to_bytestring
 
+
 url_parser = urlparse.urlparse
 
 NORMALIZE_SPACE = re.compile(r'(?:\r\n)?[ \t]+')
     def add_credentials(self, username, password=None):
         password = password or ""
         self.credentials = (username, password)
-        
 
 #TODO : manage authentification detection
 class HttpClient(object):
     MAX_REDIRECTIONS = 5
     
-    def __init__(self, follow_redirect=True, force_follow_redirect=False):
+    def __init__(self, follow_redirect=True, force_follow_redirect=False,
+            use_proxy=False, min_size=0, max_size=4, pool_class=None):
         self.authorizations = []
-        self.use_proxy = False
+        self.use_proxy = use_proxy
         self.follow_redirect = follow_redirect
         self.force_follow_redirect = force_follow_redirect
+        self.min_size = min_size
+        self.max_size = max_size
+        self.connections = {}
+        if pool_class is None:
+            self.pool_class = ConnectionPool
+        else:
+            self.pool_class = pool_class
         
     def add_authorization(self, obj_auth):
         self.authorizations.append(obj_auth)
         
     def _get_connection(self, uri, headers=None):
         connection = None
-        if uri.scheme == 'https':
-            if not uri.port:
-                connection = httplib.HTTPSConnection(uri.hostname)
-            else:
-                connection = httplib.HTTPSConnection(uri.hostname, uri.port)
+        conn_key = (uri.scheme, uri.netloc, self.use_proxy)
+
+        if conn_key in self.connections:
+            pool = self.connections[conn_key]
         else:
-            if not uri.port:
-                connection = httplib.HTTPConnection(uri.hostname)
-            else:
-                connection = httplib.HTTPConnection(uri.hostname, uri.port)
+            pool = self.connections[conn_key] = self.pool_class(uri, self.use_proxy)
+        connection = pool.get()
+        
+        if connection.sock is False:
+            connection.connect()
+            
         return connection
         
-        
-    def _make_request(self, uri, method, body, headers):
-        connection = self._get_connection(uri, headers)
-        connection.debuglevel = restkit.debuglevel
-        
+    def _release_connection(self, uri, connection):
+        conn_key = (uri.scheme, uri.netloc, self.use_proxy)
+
+        if conn_key in self.connections:
+            pool = self.connections[conn_key]
+        else:
+            pool = self.connections[conn_key] = ConnectionPool(make_connexion(uri, 
+                                                    self.use_proxy), )
+        pool.put(connection)
+
+            
+    def _make_request(self, uri, method, body, headers): 
         for i in range(2):
+            connection = self._get_connection(uri, headers)
+            
+            connection.debuglevel = restkit.debuglevel
             try:
                 if connection.host != uri.hostname:
                     connection.putrequest(method, uri.geturl())
             auth.request(uri, method, headers, body)
             connection = self._make_request(uri, method, body, headers)
             response = connection.getresponse()
-
+            
         if self.follow_redirect:
             if nb_redirections < self.MAX_REDIRECTIONS: 
                 if response.status in [301, 302, 307]:
                         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)
+                        self._release_connection(uri, connection)
                         response, connection = self._request(url_parser(new_url), method, body, 
                             headers, nb_redirections + 1)
                         self.final_url = new_url
                         absolute_uri = "%s://%s" % (uri.scheme, uri.netloc)
                         new_uri = url_parser(new_url)
                         new_url = urlparse.urljoin(absolute_uri, new_url)
+                    self._release_connection(uri, connection)
                     response, connection = self._request(url_parser(new_url), 'GET', headers, nb_redirections + 1)
                     self.final_url = new_url
             else:
         if method in ["POST", "PUT"] and body is None:
             body = ""
             headers.setdefault("Content-Length", str(len(body)))
-
+            
+        if self.use_proxy and uri.scheme != "https":
+            proxy_auth = _get_proxy_auth()
+            if proxy_auth:
+                headers['Proxy-Authorization'] = proxy_auth.strip()
+            
         response, connection = self._request(uri, method, body, headers)
         resp = HTTPResponse(response)
         resp.final_url = self.final_url
             connection.close()
             return resp, ""
         else:
-            return resp, _decompress_content(resp, response, connection, stream, stream_size)
-        
-class ProxiedHttpClient(HttpClient):
-    """ HTTP Client with simple proxy management """
-
-    def _get_connection(self, uri, headers=None):
-        headers = headers or {}
-        proxy = None
-        if uri.scheme == 'https':
-            proxy = os.environ.get('https_proxy')
-        elif uri.scheme == 'http':
-            proxy = os.environ.get('http_proxy')
-
-        if not proxy:
-            return HttpClient._get_connection(self, uri, headers=headers)
-
-        proxy_auth = _get_proxy_auth()
-        if uri.scheme == 'https':
-            if proxy_auth:
-                proxy_auth = 'Proxy-authorization: %s' % proxy_auth
-            port = uri.port
-            if not port:
-                port = 443
-            proxy_connect = 'CONNECT %s:%s HTTP/1.0\r\n' % (uri.hostname, port)
-            user_agent = 'User-Agent: %s\r\n' % (headers.get('User-Agent', restkit.USER_AGENT))
-            proxy_pieces = '%s%s%s\r\n' % (proxy_connect, proxy_auth, user_agent)
-            proxy_uri = url_parser(proxy)
-            if not proxy_uri.port:
-                proxy_uri.port = '80'
-            # Connect to the proxy server, very simple recv and error checking
-            p_sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
-            p_sock.connect((proxy_uri.host, int(proxy_uri.port)))
-            p_sock.sendall(proxy_pieces)
-            response = ''
-            # Wait for the full response.
-            while response.find("\r\n\r\n") == -1:
-                response += p_sock.recv(8192)
-            p_status = response.split()[1]
-            if p_status != str(200):
-                raise ProxyError('Error status=%s' % str(p_status))
-            # Trivial setup for ssl socket.
-            ssl = socket.ssl(p_sock, None, None)
-            fake_sock = httplib.FakeSocket(p_sock, ssl)
-            # Initalize httplib and replace with the proxy socket.
-            connection = httplib.HTTPConnection(proxy_uri.host)
-            connection.sock=fake_sock
-            return connection
-        else:
-            proxy_uri = url_parser(proxy)
-            if not proxy_uri.port:
-                proxy_uri.port = '80'
-            if proxy_auth:
-                headers['Proxy-Authorization'] = proxy_auth.strip()
-            return httplib.HTTPConnection(proxy_uri.hostname, proxy_uri.port)
-        return None
-            
-def _decompress_content(resp, response, connection, stream=False, stream_size=16384):
+            return resp, _decompress_content(resp, response, 
+                lambda: self._release_connection(uri, connection), 
+                stream, stream_size)
+                
+def _decompress_content(resp, response, release_callback, stream=False, stream_size=16384):
     try:
         encoding = resp.get('content-encoding', None)
         if encoding in ['gzip', 'deflate']:
             
             if encoding == 'gzip':
                 compressedstream = StringIO.StringIO(response.read())
-                connection.close()
+                release_callback()
                 data = gzip.GzipFile(fileobj=compressedstream)
                 if stream:
                     return ResponseStream(data, stream_size)
                     return data.read()
             else:
                 data =  zlib.decompress(response.read())
-                connection.close()
+                release_callback()
                 if stream:
                     return ResponseStream(StringIO.StringIO(data), stream_size)
                 else:
                     return data
         else:
             if stream:
-                return ResponseStream(response, stream_size, connection)
+                return ResponseStream(response, stream_size, release_callback)
             else:
                 data = response.read()
-                connection.close()
+                release_callback()
                 return data
     except Exception, e:
         raise errors.ResponseError("Decompression failed %s" % str(e))
         
 class ResponseStream(object):
     
-    def __init__(self, response, amnt=16384, connection=None):
+    def __init__(self, response, amnt=16384, release_callback=None):
         self.response = response
         self.amnt = amnt
-        self.connection = connection
+        self.callback = release_callback
         
     def next(self):
         return self.response.read(self.amnt)
                 yield data
             else:
                 break
-        if hasattr(self.connection, 'close'):
-            self.connection.close()
+        if self.callback is not None:
+            self.callback()
         
 class HTTPResponse(dict):
     """An object more like email.Message than httplib.HTTPResponse.
     reason = "Ok"
 
     def __init__(self, info):
-        if isinstance(info, httplib.HTTPResponse):
+        if hasattr(info, "getheaders"):
             for key, value in info.getheaders():
                 self[key.lower()] = value
             self.status = info.status
             self.reason = info.reason
             self.version = info.version
         else:
+            print info
             for key, value in info.iteritems(): 
                 self[key.lower()] = value 
             self.status = int(self.get('status', self.status))

File restkit/pool.py

View file
+# -*- coding: utf-8 -
+#
+# Copyright (c) 2008, 2009 Benoit Chesneau <benoitc@e-engura.com> 
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+"""
+Threadsafe Pool class based on eventlet.pools.Pool but using Queue.Queue
+"""
+
+# TODO: log error
+
+import collections
+import httplib
+from Queue import Queue, Full, Empty
+import threading
+
+from restkit import errors
+
+def make_proxy_connection(uri):
+    headers = headers or {}
+    proxy = None
+    if uri.scheme == 'https':
+        proxy = os.environ.get('https_proxy')
+    elif uri.scheme == 'http':
+        proxy = os.environ.get('http_proxy')
+
+    if not proxy:
+        return make_connection(uri, use_proxy=False)
+  
+    if uri.scheme == 'https':
+        proxy_auth = _get_proxy_auth()
+        if proxy_auth:
+            proxy_auth = 'Proxy-authorization: %s' % proxy_auth
+        port = uri.port
+        if not port:
+            port = 443
+        proxy_connect = 'CONNECT %s:%s HTTP/1.0\r\n' % (uri.hostname, port)
+        user_agent = 'User-Agent: %s\r\n' % restkit.USER_AGENT
+        proxy_pieces = '%s%s%s\r\n' % (proxy_connect, proxy_auth, user_agent)
+        proxy_uri = url_parser(proxy)
+        if not proxy_uri.port:
+            proxy_uri.port = '80'
+        # Connect to the proxy server, very simple recv and error checking
+        p_sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
+        p_sock.connect((proxy_uri.host, int(proxy_uri.port)))
+        p_sock.sendall(proxy_pieces)
+        response = ''
+        # Wait for the full response.
+        while response.find("\r\n\r\n") == -1:
+            response += p_sock.recv(8192)
+        p_status = response.split()[1]
+        if p_status != str(200):
+            raise ProxyError('Error status=%s' % str(p_status))
+        # Trivial setup for ssl socket.
+        ssl = socket.ssl(p_sock, None, None)
+        fake_sock = httplib.FakeSocket(p_sock, ssl)
+        # Initalize httplib and replace with the proxy socket.
+        connection = httplib.HTTPConnection(proxy_uri.host)
+        connection.sock=fake_sock
+        return connection
+    else:
+        proxy_uri = url_parser(proxy)
+        if not proxy_uri.port:
+            proxy_uri.port = '80'
+        return httplib.HTTPConnection(proxy_uri.hostname, proxy_uri.port)
+    return None
+    
+def make_connection(uri, use_proxy=True):
+    if use_proxy:
+        return make_proxy_connection(uri)
+    
+    if uri.scheme == 'https':
+        if not uri.port:
+            connection = httplib.HTTPSConnection(uri.hostname)
+        else:
+            connection = httplib.HTTPSConnection(uri.hostname, uri.port)
+    else:
+        if not uri.port:
+            connection = httplib.HTTPConnection(uri.hostname)
+        else:
+            connection = httplib.HTTPConnection(uri.hostname, uri.port)
+    return connection
+
+class Pool(object):
+    def __init__(self, min_size=0, max_size=4, order_as_stack=False):
+        self.min_size = min_size
+        self.max_size = max_size
+        self.order_as_stack = order_as_stack
+        self.current_size = 0
+        self.channel = Queue(0)
+        self.free_items = collections.deque()
+        for x in xrange(min_size):
+            self.current_size += 1
+            self.free_items.append(self.create())
+            
+        self.lock = threading.Lock()
+            
+    def do_get(self):
+        """
+        Return an item from the pool, when one is available
+        """
+        self.lock.acquire()
+        try:
+            if self.free_items:
+                return self.free_items.popleft()
+            if self.current_size < self.max_size:
+                created = self.create()
+                self.current_size += 1
+                return created
+            try:
+                return self.channel.get(False)
+            except Empty:
+                return self.create()
+        finally:
+            self.lock.release()
+
+    def get(self):
+        connection =  self.do_get()
+        return connection
+        
+    def put(self, item):
+        """Put an item back into the pool, when done
+        """
+        self.lock.acquire()
+        try:
+            if self.current_size > self.max_size:
+                self.current_size -= 1
+                return
+            
+            if self.waiting():
+                self.channel.put(item, False)
+            else:
+                if self.order_as_stack:
+                    self.free_items.appendleft(item)
+                else:
+                    self.free_items.append(item)
+        finally:
+            self.lock.release()
+            
+    def resize(self, new_size):
+        """Resize the pool
+        """
+        self.max_size = new_size
+    
+    def free(self):
+        """Return the number of free items in the pool.
+        """
+        return len(self.free_items) + self.max_size - self.current_size
+    
+    def waiting(self):
+        """Return the number of routines waiting for a pool item.
+        """
+        return max(0, self.max_size - self.channel.qsize())
+    
+    def create(self):
+        """Generate a new pool item
+        """
+        raise NotImplementedError("Implement in subclass")
+        
+        
+class ConnectionPool(Pool):
+    def __init__(self, uri, use_proxy=False, min_size=0, max_size=4):
+        self.uri = uri
+        self.use_proxy = use_proxy
+        Pool.__init__(self, min_size, max_size)
+    
+    def create(self):
+        return make_connection(self.uri, self.use_proxy)
+           
+    def put(self, connection):
+        try:
+            connection.close()
+        except:
+            pass
+        Pool.put(self, make_connection(self.uri, self.use_proxy))

File restkit/rest.py

View file
 """
 
 import cgi
+import httplib
 import mimetypes
 import uuid
 import os
 import re
+import socket
 import StringIO
+import time
 import types
 import urllib
 
     chardet = False
 
 from restkit.errors import *
-from restkit.httpc import ProxiedHttpClient, ResponseStream
+from restkit.httpc import HttpClient, ResponseStream
 from restkit.utils import to_bytestring
 
 MIME_BOUNDARY = 'END_OF_PART'
     `restkit.http.HTTPClient`.
 
     """
-    def __init__(self, uri, transport=None, headers=None):
+    def __init__(self, uri, transport=None, headers=None, follow_redirect=True, 
+        force_follow_redirect=False, use_proxy=False, min_size=0, max_size=4, pool_class=None):
         """Constructor for a `Resource` object.
 
         Resource represent an HTTP resource.
                 (authentification, proxy, ....).
         :param headers: dict, optionnal headers that will
             be added to HTTP request.
+        :param follow_redirect: boolean, default is True, allow the client to follow redirection
+        :param force_follow_redirect: boolean, default is False, force redirection on POST/PUT
+        :param use_proxy: boolean, default is False, if you want to use a proxy
+        :param min_size: minimum number of connections in the pool
+        :param max_size: maximum number of connection in the pool
+        :param pool_class: custom pool class
         """
 
-        self.client = RestClient(transport, headers=headers)
+        self.client = RestClient(transport, headers=headers, follow_redirect=follow_redirect,
+            force_follow_redirect=force_follow_redirect, use_proxy=use_proxy,
+            min_size=min_size, max_size=max_size, pool_class=pool_class)
         self.uri = uri
         self.transport = self.client.transport 
+        self.follow_redirect = follow_redirect
+        self.force_follow_redirect = force_follow_redirect
+        self.use_proxy = use_proxy
+        self.min_size = min_size
+        self.max_size = max_size
+        self.pool_class = pool_class
         self._headers = headers
 
     def __repr__(self):
             resr2 = res.clone()
         
         """
-        obj = self.__class__(self.uri, transport=self.transport)
+        obj = self.__class__(self.uri, transport=self.transport, headers=self._headers,
+                follow_redirect=self.follow_redirect, force_follow_redirect=self.force_follow_redirect, 
+                use_proxy=self.use_proxy, min_size=self.min_size, max_size=self.max_size)
         return obj
    
     def __call__(self, path):
         """
 
         return type(self)(self.client.make_uri(self.uri, path),
-                transport=self.transport)
+                transport=self.transport, headers=self._headers,
+                follow_redirect=self.follow_redirect, force_follow_redirect=self.force_follow_redirect, 
+                use_proxy=self.use_proxy, min_size=self.min_size, max_size=self.max_size)
 
     
     def get(self, path=None, headers=None, _stream=False, _stream_size=16384,
     encode_keys = True
     safe = "/:"
 
-    def __init__(self, transport=None, headers=None):
+    def __init__(self, transport=None, headers=None, follow_redirect=True, 
+            force_follow_redirect=False, use_proxy=False, min_size=0, max_size=4, 
+            pool_class=None):
         """Constructor for a `RestClient` object.
 
         RestClient represent an HTTP client.
                 (authentification, proxy, ....).
         :param headers: dict, optionnal headers that will
             be added to HTTP request.
+        :param follow_redirect: boolean, default is True, allow the client to follow redirection
+        :param force_follow_redirect: boolean, default is False, force redirection on POST/PUT
+        :param use_proxy: boolean, False, if you want to use a proxy
+        :param min_size: minimum number of connections in the pool
+        :param max_size: maximum number of connection in the pool
+        :param pool_class: custom Pool class
         """ 
 
         if transport is None:
-            transport = ProxiedHttpClient()
+            transport = HttpClient(follow_redirect=follow_redirect, force_follow_redirect=force_follow_redirect, 
+                            use_proxy=use_proxy, min_size=min_size, max_size=max_size, pool_class=pool_class)
 
         self.transport = transport
+        self.follow_redirect=follow_redirect
+        self.force_follow_redirect = force_follow_redirect
+        self.use_proxy = use_proxy
+        self.min_size = min_size
+        self.max_size = max_size
+        self.pool_class = pool_class
 
         self.status = None
         self.response = None
                     type_ = mimetypes.guess_type(body.name)[0]
                 _headers['Content-Type'] = type_ and type_ or 'application/octet-stream'
                 
-        try:
-            resp, data = self.transport.request(self.make_uri(uri, path, **params), 
-                method=method, body=body, headers=_headers, 
-                stream=_stream, stream_size=_stream_size)
-        except TransportError, e:
-            raise RequestError(str(e))
-
+                
+        def _try_request(retry=1):
+            try:
+                return self.transport.request(self.make_uri(uri, path, **params), 
+                            method=method, body=body, headers=_headers, 
+                            stream=_stream, stream_size=_stream_size)
+            except (socket.error, httplib.BadStatusLine), e:
+                if retry > 0:
+                    time.sleep(0.4)
+                return _try_request(retry-1)
+            except Exception, e:
+                RequestError(str(e))
+        
+        resp, data = _try_request()
         self.status  = status_code = resp.status
         self.response = resp
         

File tests/_server_test.py

View file
 import cgi
 import os
 import socket
+import tempfile
 import threading
 import unittest
 import urlparse
 
     def __init__(self, request, client_address, server):
         self.auth = 'Basic ' + base64.encodestring('test:test')[:-1]
+        self.count = 0
         BaseHTTPRequestHandler.__init__(self, request, client_address, server)
         
+        
     def do_GET(self):
         self.parsed_uri = urlparse.urlparse(urllib.unquote(self.path))
         self.query = {}
             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")
+        elif path == "/pool":
+            extra_headers = [('Content-type', 'text/plain')]
+            self._respond(200, extra_headers, "ok")
         else:
             self._respond(404, 
                 [('Content-type', 'text/plain')], "Not Found" )

File tests/eventlet_test.py

View file
+# -*- coding: utf-8 -
+#
+# Copyright (c) 2008 (c) Benoit Chesneau <benoitc@e-engura.com> 
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+import unittest
+from eventlet.util import wrap_threading_local_with_coro_local
+wrap_threading_local_with_coro_local()
+
+from restkit.rest import Resource
+from restkit.ext.eventlet_pool import ConnectionPool
+from _server_test import HOST, PORT, run_server_test
+
+from httpc_test import HTTPClientTestCase
+
+
+
+
+class EventletTestCase(HTTPClientTestCase):
+    def setUp(self):
+        
+        run_server_test()
+        self.url = 'http://%s:%s' % (HOST, PORT)
+        self.res = Resource(self.url, pool_class=ConnectionPool)
+
+if __name__ == '__main__':
+    from _server_test import run_server_test
+    run_server_test()
+    unittest.main()

File tests/httpc_test.py

View file
 import os
 import socket
 import threading
+import Queue
 import unittest
 import urlparse
 
 from restkit import httpc
+
 from restkit.rest import Resource, RestClient
 from restkit.errors import RequestFailed, ResourceNotFound, Unauthorized
 from _server_test import HOST, PORT, run_server_test
             res = Resource(self.url, httptransport)
             result = res.get('/auth')
         self.assertRaises(Unauthorized, niettest)
- 
+        
+
 if __name__ == '__main__':
     from _server_test import run_server_test
     run_server_test()