which.linden
2007-10-08 03:12:35 -04:00
parent ba64483b7b
commit ef1afb4407
5 changed files with 73 additions and 29 deletions

View File

@@ -38,9 +38,12 @@ except ImportError:
pylibsupport.emulate() pylibsupport.emulate()
greenlet = sys.modules['greenlet'] greenlet = sys.modules['greenlet']
except ImportError: except ImportError:
import stacklesssupport try:
stacklesssupport.emulate() import stacklesssupport
greenlet = sys.modules['greenlet'] stacklesssupport.emulate()
greenlet = sys.modules['greenlet']
except ImportError:
raise ImportError("Unable to find an implementation of greenlet.")
from eventlet import greenlib, tls from eventlet import greenlib, tls

View File

@@ -50,7 +50,6 @@ def host_and_port_from_url(url):
""" """
host = None host = None
port = None port = None
#print url
parsed_url = urlparse.urlparse(url) parsed_url = urlparse.urlparse(url)
try: try:
host, port = parsed_url[1].split(':') host, port = parsed_url[1].split(':')
@@ -81,19 +80,28 @@ class HttpClient(httplib.HTTPConnection):
old_putrequest = httplib.HTTPConnection.putrequest old_putrequest = httplib.HTTPConnection.putrequest
putrequest = better_putrequest putrequest = better_putrequest
def wrap_httplib_with_httpc():
httplib.HTTP._connection_class = httplib.HTTPConnection = HttpClient
httplib.HTTPS._connection_class = httplib.HTTPSConnection = HttpsClient
class HttpsClient(httplib.HTTPSConnection): class HttpsClient(httplib.HTTPSConnection):
"""A subclass of httplib.HTTPSConnection which works around a bug
in the interaction between eventlet sockets and httplib. httplib relies
on gc to close the socket, causing the socket to be closed too early.
This is an awful hack and the bug should be fixed properly ASAP.
"""
def close(self): def close(self):
pass pass
old_putrequest = httplib.HTTPSConnection.putrequest old_putrequest = httplib.HTTPSConnection.putrequest
putrequest = better_putrequest putrequest = better_putrequest
def wrap_httplib_with_httpc():
"""Replace httplib's implementations of these classes with our enhanced ones.
Needed to work around code that uses httplib directly."""
httplib.HTTP._connection_class = httplib.HTTPConnection = HttpClient
httplib.HTTPS._connection_class = httplib.HTTPSConnection = HttpsClient
class FileScheme(object): class FileScheme(object):
"""Retarded scheme to local file wrapper.""" """Retarded scheme to local file wrapper."""
host = '<file>' host = '<file>'
@@ -161,6 +169,10 @@ class FileScheme(object):
class ConnectionError(Exception): class ConnectionError(Exception):
"""Detailed exception class for reporting on http connection problems.
There are lots of subclasses so you can use closely-specified
exception clauses."""
def __init__(self, method, host, port, path, status, reason, body): def __init__(self, method, host, port, path, status, reason, body):
self.method = method self.method = method
self.host = host self.host = host
@@ -180,6 +192,7 @@ class ConnectionError(Exception):
class UnparseableResponse(ConnectionError): class UnparseableResponse(ConnectionError):
"""Raised when a loader cannot parse the response from the server."""
def __init__(self, content_type, response): def __init__(self, content_type, response):
self.content_type = content_type self.content_type = content_type
self.response = response self.response = response
@@ -193,22 +206,27 @@ class UnparseableResponse(ConnectionError):
class Accepted(ConnectionError): class Accepted(ConnectionError):
""" 202 Accepted """
pass pass
class NotFound(ConnectionError): class NotFound(ConnectionError):
""" 404 Not Found """
pass pass
class Forbidden(ConnectionError): class Forbidden(ConnectionError):
""" 403 Forbidden """
pass pass
class InternalServerError(ConnectionError): class InternalServerError(ConnectionError):
""" 500 Internal Server Error """
pass pass
class Gone(ConnectionError): class Gone(ConnectionError):
""" 410 Gone """
pass pass
@@ -233,6 +251,12 @@ scheme_to_factory_map = {
def make_connection(scheme, location, use_proxy): def make_connection(scheme, location, use_proxy):
""" Create a connection object to a host:port.
@param scheme Protocol, scheme, whatever you want to call it. http, file, https are currently supported.
@param location Hostname and port number, formatted as host:port or http://host:port if you're so inclined.
@param use_proxy Connect to a proxy instead of the actual location. Uses environment variables to decide where the proxy actually lives.
"""
if use_proxy: if use_proxy:
if "http_proxy" in os.environ: if "http_proxy" in os.environ:
location = os.environ["http_proxy"] location = os.environ["http_proxy"]
@@ -241,7 +265,7 @@ def make_connection(scheme, location, use_proxy):
else: else:
location = "localhost:3128" #default to local squid location = "localhost:3128" #default to local squid
# run a little heuristic to see if it's an url, and if so parse out the hostpart # run a little heuristic to see if location is an url, and if so parse out the hostpart
if location.startswith('http'): if location.startswith('http'):
_scheme, location, path, parameters, query, fragment = urlparse.urlparse(location) _scheme, location, path, parameters, query, fragment = urlparse.urlparse(location)
@@ -251,11 +275,25 @@ def make_connection(scheme, location, use_proxy):
def connect(url, use_proxy=False): def connect(url, use_proxy=False):
""" Create a connection object to the host specified in a url. Convenience function for make_connection."""
scheme, location, path, params, query, id = urlparse.urlparse(url) scheme, location, path, params, query, id = urlparse.urlparse(url)
return make_connection(scheme, location, use_proxy) return make_connection(scheme, location, use_proxy)
def request(connection, method, url, body='', headers=None, dumper=None, loader=None, use_proxy=False, verbose=False, ok=None): def request(connection, method, url, body='', headers=None, dumper=None, loader=None, use_proxy=False, verbose=False, ok=None):
"""Make an http request to a url, for internal use mostly.
@param connection The connection (as returned by make_connection) to use for the request.
@param method HTTP method
@param url Full url to make request on.
@param body HTTP body, if necessary for the method. Can be any object, assuming an appropriate dumper is also provided.
@param headers Dict of header name to header value
@param dumper Method that formats the body as a string.
@param loader Method that converts the response body into an object.
@param use_proxy Set to True if the connection is to a proxy.
@param verbose Set to true to change the return value of the function to: status, status_message, body
@param ok Set of valid response statuses. If the returned status is not in this list, an exception is thrown.
"""
if ok is None: if ok is None:
ok = (200, 201, 204) ok = (200, 201, 204)
if headers is None: if headers is None:
@@ -271,10 +309,12 @@ def request(connection, method, url, body='', headers=None, dumper=None, loader=
if scheme == 'file': if scheme == 'file':
use_proxy = False use_proxy = False
if method in ('PUT', 'POST'):
if dumper is not None: if dumper is not None:
body = dumper(body) body = dumper(body)
headers['content-length'] = len(body) # don't set content-length header because httplib does it for us in _send_request
else:
body = ''
connection.request(method, url, body, headers) connection.request(method, url, body, headers)
response = connection.getresponse() response = connection.getresponse()
@@ -286,13 +326,11 @@ def request(connection, method, url, body='', headers=None, dumper=None, loader=
body = response.read() body = response.read()
if loader is None: if loader is not None:
return body try:
body = loader(body)
try: except Exception, e:
body = loader(body) raise UnparseableResponse(loader, body)
except Exception, e:
raise UnparseableResponse(loader, body)
if verbose: if verbose:
return response.status, response.msg, body return response.status, response.msg, body
@@ -324,7 +362,7 @@ class HttpSuite(object):
#import pdb; pdb.Pdb().set_trace() #import pdb; pdb.Pdb().set_trace()
if headers is None: if headers is None:
headers = {} headers = {}
connection = connect(url) connection = connect(url, use_proxy)
return request(connection, 'GET', url, '', headers, None, self.loader, use_proxy, verbose, ok) return request(connection, 'GET', url, '', headers, None, self.loader, use_proxy, verbose, ok)
def put(self, url, data, headers=None, content_type=None, verbose=False, ok=None): def put(self, url, data, headers=None, content_type=None, verbose=False, ok=None):
@@ -341,7 +379,6 @@ class HttpSuite(object):
return request(connect(url), 'DELETE', url, verbose=verbose, ok=ok) return request(connect(url), 'DELETE', url, verbose=verbose, ok=ok)
def post(self, url, data='', headers=None, content_type=None, verbose=False, ok=None): def post(self, url, data='', headers=None, content_type=None, verbose=False, ok=None):
connection = connect(url)
if headers is None: if headers is None:
headers = {} headers = {}
if 'content-type' not in headers: if 'content-type' not in headers:
@@ -353,6 +390,7 @@ class HttpSuite(object):
def make_suite(dumper, loader, fallback_content_type): def make_suite(dumper, loader, fallback_content_type):
""" Return a tuple of methods for making http requests with automatic bidirectional formatting with a particular content-type."""
suite = HttpSuite(dumper, loader, fallback_content_type) suite = HttpSuite(dumper, loader, fallback_content_type)
return suite.get, suite.put, suite.delete, suite.post return suite.get, suite.put, suite.delete, suite.post

View File

@@ -295,7 +295,7 @@ class Request(object):
typ, val, tb = sys.exc_info() typ, val, tb = sys.exc_info()
body = dict(type=str(typ), error=True, reason=str(val)) body = dict(type=str(typ), error=True, reason=str(val))
self.response(response) self.response(response)
if type(body) is str: if(type(body) is str and not self.response_written()):
self.write(body) self.write(body)
return return
try: try:
@@ -450,7 +450,7 @@ class Server(BaseHTTPServer.HTTPServer):
self.log = self self.log = self
def write(self, something): def write(self, something):
sys.stdout.write('%s\n' % (something, )) sys.stdout.write('%s' % (something, ))
def log_message(self, message): def log_message(self, message):
self.log.write(message) self.log.write(message)
@@ -463,7 +463,7 @@ class Server(BaseHTTPServer.HTTPServer):
client_address, date_time, requestline, code, size, request_time client_address, date_time, requestline, code, size, request_time
""" """
self.log.write( self.log.write(
'%s - - [%s] "%s" %s %s %.6f' % args) '%s - - [%s] "%s" %s %s %.6f\n' % args)
def server(sock, site, log=None, max_size=512): def server(sock, site, log=None, max_size=512):

View File

@@ -42,6 +42,9 @@ class Process(object):
self.command = command self.command = command
self.args = args self.args = args
self._dead_callback = dead_callback self._dead_callback = dead_callback
self.run()
def run(self):
self.dead = False self.dead = False
self.started = False self.started = False
self.popen4 = None self.popen4 = None

View File

@@ -86,7 +86,7 @@ class Hub(object):
pass pass
if exc is not None: if exc is not None:
try: try:
exc() exc(fileno)
except self.runloop.SYSTEM_EXCEPTIONS: except self.runloop.SYSTEM_EXCEPTIONS:
self.squelch_exception(fileno, sys.exc_info()) self.squelch_exception(fileno, sys.exc_info())
@@ -157,7 +157,7 @@ class Hub(object):
writers = self.writers writers = self.writers
excs = self.excs excs = self.excs
try: try:
r, w, ig = select.select(readers, writers, [], seconds) r, w, ig = select.select(readers.keys(), writers.keys(), [], seconds)
except select.error, e: except select.error, e:
if e.args[0] == errno.EINTR: if e.args[0] == errno.EINTR:
return return