Commit 2f8dc9c3 authored by Denis Bilenko's avatar Denis Bilenko

remove unused libevent-related .pxi and C sources

parent ab5b3850
__all__ += ['buffer']
cdef extern from "string.h":
void *memchr(void *s, int c, size_t n)
cdef extern from "libevent.h":
struct evbuffer:
char *buf "buffer"
int off
evbuffer *evbuffer_new()
int evbuffer_add(evbuffer *buf, char *p, int len)
char *evbuffer_readline(evbuffer *buf)
void evbuffer_free(evbuffer *buf)
size_t evbuffer_get_length(evbuffer *buffer)
unsigned char *EVBUFFER_PULLUP(evbuffer *buf, size_t size)
int EVBUFFER_DRAIN(evbuffer *buf, size_t len)
cdef class buffer:
"""file-like wrapper for libevent's :class:`evbuffer` structure.
Note, that the wrapper does not own the structure, libevent does.
"""
cdef evbuffer* __obj
def __init__(self, size_t _obj):
self.__obj = <evbuffer*>_obj
property _obj:
def __get__(self):
return <size_t>(self.__obj)
def __len__(self):
if self.__obj:
return evbuffer_get_length(self.__obj)
else:
return 0
def __nonzero__(self):
if self.__obj:
return evbuffer_get_length(self.__obj)
def detach(self):
self.__obj = NULL
def __iter__(self):
return self
def __next__(self):
line = self.readline()
if not line:
raise StopIteration
return line
def read(self, long size=-1):
"""Drain the first *size* bytes from the buffer (or what's left if there are less than *size* bytes).
If *size* is negative, drain the whole buffer.
"""
if not self.__obj:
return ''
cdef long length = evbuffer_get_length(self.__obj)
if size < 0:
size = length
else:
size = min(size, length)
if size <= 0:
return ''
cdef char* data = <char*>EVBUFFER_PULLUP(self.__obj, size)
if not data:
return ''
cdef object result = PyString_FromStringAndSize(data, size)
cdef int res = EVBUFFER_DRAIN(self.__obj, size)
if res:
try:
sys.stderr.write('evbuffer_drain(0x%x, %s) returned %s\n' % (self._obj, size, res))
except:
traceback.print_exc()
return result
def readline(self, size=None):
if not self.__obj:
return ''
cdef char* data = <char*>EVBUFFER_PULLUP(self.__obj, -1)
if not data:
return ''
cdef long length = evbuffer_get_length(self.__obj)
cdef char *nl = <char*> memchr(<void*>data, 10, length) # search for "\n"
if nl:
length = nl - data + 1
cdef object result = PyString_FromStringAndSize(data, length)
cdef int res = EVBUFFER_DRAIN(self.__obj, length)
if res:
try:
sys.stderr.write('evbuffer_drain(0x%x, %s) returned %s\n' % (self._obj, length, res))
except:
traceback.print_exc()
return result
def readlines(self, hint=-1):
return list(self)
def write(self, bytes data):
cdef int result = evbuffer_add(self.__obj, data, len(data))
if result < 0:
raise IOError("evbuffer_add() returned %s" % result)
return result
__all__ += ['dns_init', 'dns_shutdown', 'dns_err_to_string',
'dns_resolve_ipv4', 'dns_resolve_ipv6',
'dns_resolve_reverse', 'dns_resolve_reverse_ipv6']
cdef extern from *:
ctypedef char* const_char_ptr "const char*"
cdef extern from "libevent.h":
ctypedef void (*evdns_handler)(int result, char t, int count, int ttl, void *addrs, void *arg)
int evdns_init()
const_char_ptr evdns_err_to_string(int err)
int evdns_resolve_ipv4(char *name, int flags, evdns_handler callback, void *arg)
int evdns_resolve_ipv6(char *name, int flags, evdns_handler callback, void *arg)
int evdns_resolve_reverse(void *ip, int flags, evdns_handler callback, void *arg)
int evdns_resolve_reverse_ipv6(void *ip, int flags, evdns_handler callback, void *arg)
void evdns_shutdown(int fail_requests)
# Result codes
DNS_ERR_NONE = 0
DNS_ERR_FORMAT = 1
DNS_ERR_SERVERFAILED = 2
DNS_ERR_NOTEXIST = 3
DNS_ERR_NOTIMPL = 4
DNS_ERR_REFUSED = 5
DNS_ERR_TRUNCATED = 65
DNS_ERR_UNKNOWN = 66
DNS_ERR_TIMEOUT = 67
DNS_ERR_SHUTDOWN = 68
# Types
DNS_IPv4_A = 1
DNS_PTR = 2
DNS_IPv6_AAAA = 3
# Flags
DNS_QUERY_NO_SEARCH = 1
def dns_init():
"""Initialize async DNS resolver."""
evdns_init()
def dns_shutdown(int fail_requests=0):
"""Shutdown the async DNS resolver and terminate all active requests."""
evdns_shutdown(fail_requests)
def dns_err_to_string(int err):
cdef const_char_ptr result = evdns_err_to_string(err)
if result:
return result
cdef void __evdns_callback(int code, char type, int count, int ttl, void *addrs, void *arg) with gil:
cdef int i
cdef object callback = <object>arg
Py_DECREF(callback)
cdef object addr
cdef object result
if type == DNS_IPv4_A:
result = []
for i from 0 <= i < count:
addr = PyString_FromStringAndSize(&(<char *>addrs)[i*4], 4)
result.append(addr)
elif type == DNS_IPv6_AAAA:
result = []
for i from 0 <= i < count:
addr = PyString_FromStringAndSize(&(<char *>addrs)[i*16], 16)
result.append(addr)
elif type == DNS_PTR and count == 1: # only 1 PTR possible
result = PyString_FromString((<char **>addrs)[0])
else:
result = None
try:
callback(code, type, ttl, result)
except:
traceback.print_exc()
sys.exc_clear()
def dns_resolve_ipv4(char *name, int flags, object callback):
"""Lookup an A record for a given name.
- *name* -- DNS hostname
- *flags* -- either 0 or DNS_QUERY_NO_SEARCH
- *callback* -- callback with ``(result, type, ttl, addrs)`` prototype
"""
cdef int result = evdns_resolve_ipv4(name, flags, __evdns_callback, <void *>callback)
if result:
raise IOError('evdns_resolve_ipv4(%r, %r) returned %s' % (name, flags, result, ))
Py_INCREF(callback)
def dns_resolve_ipv6(char *name, int flags, object callback):
"""Lookup an AAAA record for a given name.
- *name* -- DNS hostname
- *flags* -- either 0 or DNS_QUERY_NO_SEARCH
- *callback* -- callback with ``(result, type, ttl, addrs)`` prototype
"""
cdef int result = evdns_resolve_ipv6(name, flags, __evdns_callback, <void *>callback)
if result:
raise IOError('evdns_resolve_ip6(%r, %r) returned %s' % (name, flags, result, ))
Py_INCREF(callback)
def dns_resolve_reverse(char* packed_ip, int flags, object callback):
"""Lookup a PTR record for a given IPv4 address.
- *packed_ip* -- IPv4 address (as 4-byte binary string)
- *flags* -- either 0 or DNS_QUERY_NO_SEARCH
- *callback* -- callback with ``(result, type, ttl, addrs)`` prototype
"""
cdef int result = evdns_resolve_reverse(<void *>packed_ip, flags, __evdns_callback, <void *>callback)
if result:
raise IOError('evdns_resolve_reverse(%r, %r) returned %s' % (packed_ip, flags, result, ))
Py_INCREF(callback)
def dns_resolve_reverse_ipv6(char* packed_ip, int flags, object callback):
"""Lookup a PTR record for a given IPv6 address.
- *packed_ip* -- IPv6 address (as 16-byte binary string)
- *flags* -- either 0 or DNS_QUERY_NO_SEARCH
- *callback* -- callback with ``(result, type, ttl, addrs)`` prototype
"""
cdef int result = evdns_resolve_reverse_ipv6(<void *>packed_ip, flags, __evdns_callback, <void *>callback)
if result:
raise IOError('evdns_resolve_reverse_ipv6(%r, %r) returned %s' % (packed_ip, flags, result, ))
Py_INCREF(callback)
__all__ += ['http_request', 'http_connection', 'http']
cdef extern from *:
cdef void emit_ifdef "#if defined(LIBEVENT_HTTP_MODERN) //" ()
cdef void emit_else "#else //" ()
cdef void emit_endif "#endif //" ()
EVHTTP_REQUEST = 0
EVHTTP_RESPONSE = 1
emit_ifdef()
EVHTTP_REQ_GET = 1 << 0
EVHTTP_REQ_POST = 1 << 1
EVHTTP_REQ_HEAD = 1 << 2
EVHTTP_REQ_PUT = 1 << 3
EVHTTP_REQ_DELETE = 1 << 4
EVHTTP_REQ_OPTIONS = 1 << 5
EVHTTP_REQ_TRACE = 1 << 6
EVHTTP_REQ_CONNECT = 1 << 7
EVHTTP_REQ_PATCH = 1 << 8
HTTP_method2name = {
EVHTTP_REQ_GET: "GET",
EVHTTP_REQ_POST: "POST",
EVHTTP_REQ_HEAD: "HEAD",
EVHTTP_REQ_PUT: "PUT",
EVHTTP_REQ_DELETE: "DELETE",
EVHTTP_REQ_OPTIONS: "OPTIONS",
EVHTTP_REQ_TRACE: "TRACE",
EVHTTP_REQ_CONNECT: "CONNECT",
EVHTTP_REQ_PATCH: "PATCH"
}
emit_else()
EVHTTP_REQ_GET = 0
EVHTTP_REQ_POST = 1
EVHTTP_REQ_HEAD = 2
HTTP_method2name = {
EVHTTP_REQ_GET: "GET",
EVHTTP_REQ_POST: "POST",
EVHTTP_REQ_HEAD: "HEAD",
}
emit_endif()
cdef extern from *:
ctypedef char* const_char_ptr "const char*"
cdef extern from "libevent.h":
ctypedef unsigned short ev_uint16_t
struct tailq_entry:
void* tqe_next
struct evkeyval:
tailq_entry next
char* key
char* value
struct evkeyvalq:
pass
evkeyval* TAILQ_FIRST(evkeyvalq* x)
evkeyval* TAILQ_GET_NEXT(evkeyval* x)
# evhttp.h:
struct evhttp:
pass
struct evhttp_connection:
pass
struct evhttp_request:
evhttp_connection* evcon
evkeyvalq *input_headers
evkeyvalq *output_headers
char *remote_host
short remote_port
int kind
int type
char *uri
char major
char minor
int response_code
char *response_code_line
evbuffer *input_buffer
int chunked
evbuffer *output_buffer
# evhttp
ctypedef void (*evhttp_handler)(evhttp_request *, void *arg)
evhttp* evhttp_new(void *base)
int evhttp_bind_socket(evhttp *http, char* address, int port)
int evhttp_accept_socket(evhttp *http, int fd)
void evhttp_free(evhttp* http)
int EVHTTP_SET_CB(evhttp *http, char *uri, evhttp_handler handler, void *arg)
void evhttp_set_gencb(evhttp *http, evhttp_handler handler, void *arg)
void evhttp_del_cb(evhttp *http, char *uri)
# request
ctypedef void (*evhttp_request_cb)(evhttp_request *r, void *arg)
evhttp_request *evhttp_request_new(evhttp_request_cb reqcb, void *arg)
void evhttp_request_free(evhttp_request *r)
void evhttp_send_reply(evhttp_request *req, int status, char* reason, evbuffer* buf)
void evhttp_send_reply_start(evhttp_request *req, int status, char *reason)
void evhttp_send_reply_chunk(evhttp_request *req, evbuffer *buf)
void evhttp_send_reply_end(evhttp_request *req)
void evhttp_send_error(evhttp_request *req, int error, char *reason)
char* evhttp_find_header(evkeyvalq*, char*)
int evhttp_remove_header(evkeyvalq*, char*)
int evhttp_add_header(evkeyvalq*, char*, char*)
void evhttp_clear_headers(evkeyvalq*)
# connection
ctypedef void (*conn_closecb)(evhttp_connection *c, void *arg)
evhttp_connection *evhttp_connection_new(char *addr, short port)
evhttp_connection *evhttp_connection_base_new(void*, void*, char *addr, short port)
void evhttp_connection_free(evhttp_connection *c)
void evhttp_connection_set_local_address(evhttp_connection *c, char *addr)
void evhttp_connection_set_timeout(evhttp_connection *c, int secs)
void evhttp_connection_set_retries(evhttp_connection *c, int retry_max)
void evhttp_connection_set_closecb(evhttp_connection *c, conn_closecb closecb, void *arg)
void evhttp_connection_get_peer(evhttp_connection *evcon, char **address, ev_uint16_t *port)
int evhttp_make_request(evhttp_connection *c, evhttp_request *req, int cmd_type, char *uri)
class ObjectDeleted(AttributeError):
pass
class HttpRequestDeleted(ObjectDeleted):
"""Raised when an attribute is accessed of http_request instance whose _obj is 0"""
class HttpConnectionDeleted(ObjectDeleted):
"""Raised when an attribute is accessed of http_connection instance whose _obj is 0"""
cdef class http_request_base:
"""Wrapper around libevent's :class:`evhttp_request` structure."""
# It is possible to crash the process by using it directly.
# prefer gevent.http and gevent.wsgi which should be safe
cdef object __weakref__
cdef evhttp_request* __obj
cdef public object _input_buffer
cdef public object _output_buffer
def __init__(self, size_t obj):
self.__obj = <evhttp_request *>obj
property _obj:
def __get__(self):
return <size_t>(self.__obj)
def __nonzero__(self):
if self.__obj:
return True
else:
return False
def detach(self):
self.__obj = NULL
if self._input_buffer is not None:
self._input_buffer.detach()
if self._output_buffer is not None:
self._output_buffer.detach()
def _format(self):
args = (self.typestr, self.uri, self.major, self.minor,
self.remote_host, self.remote_port)
res = '"%s %s HTTP/%s.%s" %s:%s' % args
if self.response_code:
res += ' response=%s' % self.response_code
if self.input_buffer:
res += ' input=%s' % len(self.input_buffer)
if self.output_buffer:
res += ' output=%s' % len(self.output_buffer)
return res
def __str__(self):
try:
info = self._format()
except HttpRequestDeleted:
info = 'deleted'
except Exception, ex:
info = str(ex) or repr(ex) or '<Error>'
return '<%s %s>' % (self.__class__.__name__, info)
def __repr__(self):
try:
info = ' ' + self._format()
except HttpRequestDeleted:
info = ''
except Exception, ex:
info = ' ' + (str(ex) or repr(ex) or '<Error>')
return '<%s _obj=0x%x %s>' % (self.__class__.__name__, self._obj, info)
def get_input_headers(self):
if not self.__obj:
raise HttpRequestDeleted
cdef evkeyvalq* headers = self.__obj.input_headers
cdef evkeyval* p = TAILQ_FIRST(headers)
cdef char *key, *value
result = []
while p:
key = p.key
value = p.value
if key == NULL or value == NULL:
break
result.append((key.lower(), value))
p = TAILQ_GET_NEXT(p)
return result
property connection:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
return http_connection(<size_t>self.__obj.evcon)
property remote_host:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
if self.__obj.remote_host:
return self.__obj.remote_host
property remote_port:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
return self.__obj.remote_port
property remote:
def __get__(self):
return (self.remote_host, self.remote_port)
property kind:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
return self.__obj.kind
property type:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
return self.__obj.type
property typestr:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
return HTTP_method2name.get(self.__obj.type) or str(self.__obj.type)
property uri:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
if self.__obj.uri:
return self.__obj.uri
property major:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
return self.__obj.major
property minor:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
return self.__obj.minor
property version:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
return (self.__obj.major, self.__obj.minor)
property response_code:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
return self.__obj.response_code
property response_code_line:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
if self.__obj.response_code_line:
return self.__obj.response_code_line
property response:
def __get__(self):
return (self.response_code, self.response_code_line)
property chunked:
def __get__(self):
if not self.__obj:
raise HttpRequestDeleted
return self.__obj.chunked
property input_buffer:
def __get__(self):
if self._input_buffer is not None:
return self._input_buffer
if not self.__obj:
raise HttpRequestDeleted
self._input_buffer = buffer(<size_t>self.__obj.input_buffer)
return self._input_buffer
property output_buffer:
def __get__(self):
if self._output_buffer is not None:
return self._output_buffer
if not self.__obj:
raise HttpRequestDeleted
self._output_buffer = buffer(<size_t>self.__obj.output_buffer)
return self._output_buffer
def find_input_header(self, char* key):
if not self.__obj:
raise HttpRequestDeleted
cdef const_char_ptr val = evhttp_find_header(self.__obj.input_headers, key)
if val:
return val
def find_output_header(self, char* key):
if not self.__obj:
raise HttpRequestDeleted
cdef const_char_ptr val = evhttp_find_header(self.__obj.output_headers, key)
if val:
return val
def add_input_header(self, char* key, char* value):
if not self.__obj:
raise HttpRequestDeleted
if evhttp_add_header(self.__obj.input_headers, key, value):
raise RuntimeError('Internal error in evhttp_add_header')
def add_output_header(self, char* key, char* value):
if not self.__obj:
raise HttpRequestDeleted
if evhttp_add_header(self.__obj.output_headers, key, value):
raise RuntimeError('Internal error in evhttp_add_header')
def remove_input_header(self, char* key):
"""Return True if header was found and removed"""
if not self.__obj:
raise HttpRequestDeleted
return True if 0 == evhttp_remove_header(self.__obj.input_headers, key) else False
def remove_output_header(self, char* key):
"""Return True if header was found and removed"""
if not self.__obj:
raise HttpRequestDeleted
return True if 0 == evhttp_remove_header(self.__obj.output_headers, key) else False
def clear_input_headers(self):
if not self.__obj:
raise HttpRequestDeleted
evhttp_clear_headers(self.__obj.input_headers)
def clear_output_headers(self):
if not self.__obj:
raise HttpRequestDeleted
evhttp_clear_headers(self.__obj.output_headers)
cdef class http_request(http_request_base):
"""Wrapper around libevent's :class:`evhttp_request` structure."""
# It is possible to crash the process by using it directly.
# prefer gevent.http and gevent.wsgi which should be safe
cdef public object default_response_headers
def __init__(self, size_t obj, object default_response_headers=[]):
http_request_base.__init__(self, obj)
self.default_response_headers = default_response_headers
def __dealloc__(self):
cdef evhttp_request* obj = self.__obj
if obj != NULL:
self.detach()
report_internal_error(obj)
def _add_default_response_headers(self):
for key, value in self.default_response_headers:
if not self.find_output_header(key):
self.add_output_header(key, value)
def send_reply(self, int code, char *reason, object buf):
if not self.__obj:
raise HttpRequestDeleted
cdef evbuffer* c_buf
if isinstance(buf, buffer):
self._add_default_response_headers()
evhttp_send_reply(self.__obj, code, reason, (<buffer>buf).__obj)
elif isinstance(buf, str):
self._add_default_response_headers()
c_buf = evbuffer_new()
evbuffer_add(c_buf, <char *>buf, len(buf))
evhttp_send_reply(self.__obj, code, reason, c_buf)
evbuffer_free(c_buf)
else:
raise TypeError('Expected str or buffer: %r' % (buf, ))
def send_reply_start(self, int code, char *reason):
if not self.__obj:
raise HttpRequestDeleted
self._add_default_response_headers()
evhttp_send_reply_start(self.__obj, code, reason)
def send_reply_chunk(self, object buf):
if not self.__obj:
raise HttpRequestDeleted
cdef evbuffer* c_buf
if isinstance(buf, buffer):
evhttp_send_reply_chunk(self.__obj, (<buffer>buf).__obj)
elif isinstance(buf, str):
c_buf = evbuffer_new()
evbuffer_add(c_buf, <char *>buf, len(buf))
evhttp_send_reply_chunk(self.__obj, c_buf)
evbuffer_free(c_buf)
else:
raise TypeError('Expected str or buffer: %r' % (buf, ))
def send_reply_end(self):
if not self.__obj:
raise HttpRequestDeleted
evhttp_send_reply_end(self.__obj)
def send_error(self, int code, char* reason):
if not self.__obj:
raise HttpRequestDeleted
self._add_default_response_headers()
evhttp_send_error(self.__obj, code, reason)
cdef class http_request_client(http_request_base):
"""Wrapper around libevent's :class:`evhttp_request` structure."""
cdef public int _owned
cdef public callback
cdef int _incref
def __init__(self, object callback=None, size_t obj=0):
self._incref = 0
self.callback = callback
if obj:
self.__obj = <evhttp_request*>obj
self._owned = 0
else:
self.__obj = evhttp_request_new(_http_request_cb_handler, <void*>self)
if not self.__obj:
raise IOError('evhttp_request_new() failed')
self._owned = 1
self._addref()
cdef _addref(self):
if self._incref <= 0:
Py_INCREF(self)
self._incref += 1
cdef _delref(self):
if self._incref > 0:
Py_DECREF(self)
self._incref -= 1
self.callback = None
def __dealloc__(self):
cdef evhttp_request* obj = self.__obj
if obj != NULL:
self.detach()
if self._owned:
evhttp_request_free(obj)
cdef class http_connection:
cdef evhttp_connection* __obj
cdef public int _owned
def __init__(self, size_t obj, owned=0):
self.__obj = <evhttp_connection*>obj
self._owned = owned
@classmethod
def new(cls, char* address, unsigned short port, event_base base):
cdef void* ptr = evhttp_connection_base_new(base._ptr, NULL, address, port)
if ptr != NULL:
return cls(<size_t>ptr, 1)
def __dealloc__(self):
cdef evhttp_connection* obj = self.__obj
if obj != NULL:
self.__obj = NULL
if self._owned:
evhttp_connection_free(obj)
property _obj:
def __get__(self):
return <size_t>(self.__obj)
def __nonzero__(self):
if self.__obj:
return True
else:
return False
def __str__(self):
try:
peer = self.peer
except HttpConnectionDeleted:
peer = 'deleted'
return '<%s %s>' % (self.__class__.__name__, peer)
def __repr__(self):
try:
peer = ' %s' % (self.peer, )
except HttpConnectionDeleted:
peer = ''
return '<%s _obj=0x%x%s>' % (self.__class__.__name__, self._obj, peer)
property peer:
def __get__(self):
if not self.__obj:
raise HttpConnectionDeleted
cdef char* address = NULL
cdef ev_uint16_t port = 0
evhttp_connection_get_peer(self.__obj, &address, &port)
if address:
addr = <str>address
else:
addr = None
return (addr, port)
def set_local_address(self, char *addr):
if not self.__obj:
raise HttpConnectionDeleted
evhttp_connection_set_local_address(self.__obj, addr)
def set_timeout(self, int secs):
if not self.__obj:
raise HttpConnectionDeleted
evhttp_connection_set_timeout(self.__obj, secs)
def set_retries(self, int retry_max):
if not self.__obj:
raise HttpConnectionDeleted
evhttp_connection_set_retries(self.__obj, retry_max)
def make_request(self, http_request_client req, int type, char* uri):
req._owned = 0
cdef int result = evhttp_make_request(self.__obj, req.__obj, type, uri)
if result != 0:
req.detach()
return result
cdef void _http_request_cb_handler(evhttp_request* c_request, void *arg) with gil:
if arg == NULL:
return
cdef http_request_client obj = <http_request_client>(arg)
try:
if obj.__obj != NULL:
if obj.__obj != c_request:
# sometimes this happens, don't know why
sys.stderr.write("Internal error in evhttp\n")
if obj.callback is not None:
# preferring c_request to obj.__obj because the latter sometimes causes crashes
obj.callback(http_request_client(obj=<size_t>c_request))
obj.detach()
except:
traceback.print_exc()
try:
sys.stderr.write('Failed to execute callback for evhttp request.\n')
except:
pass
finally:
obj._delref()
cdef void _http_cb_handler(evhttp_request* request, void *arg) with gil:
cdef http server = <object>arg
cdef http_request req = http_request(<size_t>request, server.default_response_headers)
cdef evhttp_connection* conn = request.evcon
cdef object requests
try:
evhttp_connection_set_closecb(conn, _http_closecb_handler, arg)
requests = server._requests.pop(<size_t>conn, None)
if requests is None:
requests = weakref.WeakKeyDictionary()
server._requests[<size_t>conn] = requests
requests[req] = True
server.handle(req)
except:
traceback.print_exc()
try:
sys.stderr.write('%s: Failed to handle request: %s\n\n' % (server, req, ))
except:
traceback.print_exc()
# without clearing exc_info a reference to the request is somehow leaked
sys.exc_clear()
cdef void _http_closecb_handler(evhttp_connection* connection, void *arg) with gil:
cdef http server = <object>arg
cdef object requests
for request in server._requests.pop(<size_t>connection, {}).keys():
request.detach()
cdef void _http_cb_reply_error(evhttp_request* request, void *arg):
report_internal_error(request)
cdef void report_internal_error(evhttp_request* request):
cdef evbuffer* c_buf
if request != NULL and request.response_code == 0:
evhttp_add_header(request.output_headers, "Connection", "close")
evhttp_add_header(request.output_headers, "Content-type", "text/plain")
c_buf = evbuffer_new()
evhttp_add_header(request.output_headers, "Content-length", "21")
evbuffer_add(c_buf, "Internal Server Error", 21)
evhttp_send_reply(request, 500, "Internal Server Error", c_buf)
evbuffer_free(c_buf)
cdef class http:
cdef evhttp* __obj
cdef public object handle
cdef public object default_response_headers
cdef public dict _requests
def __init__(self, object handle, object default_response_headers=None, event_base base=None):
self.handle = handle
if default_response_headers is None:
self.default_response_headers = []
else:
self.default_response_headers = default_response_headers
self._requests = {} # maps connection id to WeakKeyDictionary which holds requests
if base is None:
if levent.current_base:
self.__obj = evhttp_new(levent.current_base)
else:
raise ValueError('Please provide event_base')
else:
self.__obj = evhttp_new(base._ptr)
evhttp_set_gencb(self.__obj, _http_cb_handler, <void *>self)
def __dealloc__(self):
if self.__obj != NULL:
evhttp_set_gencb(self.__obj, _http_cb_reply_error, NULL)
evhttp_free(self.__obj)
self.__obj = NULL
property _obj:
def __get__(self):
return <size_t>(self.__obj)
def __nonzero__(self):
if self.__obj:
return True
else:
return False
def bind(self, char* address='127.0.0.1', int port=80):
cdef int res = evhttp_bind_socket(self.__obj, address, port)
if res:
raise RuntimeError('evhttp_bind_socket(%r, %r) returned %r' % (address, port, res))
def accept(self, int fd):
cdef res = evhttp_accept_socket(self.__obj, fd)
if res:
raise RuntimeError("evhttp_accept_socket(%r) returned %r" % (fd, res))
/* Copyright (c) 2009-2010 Denis Bilenko. See LICENSE for details. */
#ifdef WIN32
#include "winsock2.h" // for timeval
#endif
#include "sys/queue.h"
#include "event.h"
#if defined(_EVENT_NUMERIC_VERSION) && _EVENT_NUMERIC_VERSION >= 0x2000000
#if _EVENT_NUMERIC_VERSION >= 0x02000900
#define LIBEVENT_HTTP_MODERN
#endif
#include "event2/event.h"
#include "event2/event_struct.h"
#include "event2/event_compat.h"
#include "event2/http.h"
#include "event2/http_compat.h"
#include "event2/http_struct.h"
#include "event2/buffer.h"
#include "event2/buffer_compat.h"
#include "event2/dns.h"
#include "event2/dns_compat.h"
#include "event2/util.h"
#define EVBUFFER_DRAIN evbuffer_drain
#define EVHTTP_SET_CB evhttp_set_cb
#define EVBUFFER_PULLUP(BUF, SIZE) evbuffer_pullup(BUF, SIZE)
#if _EVENT_NUMERIC_VERSION >= 0x02000500
#define current_base event_global_current_base_
#endif
#else
#include "evhttp.h"
#include "evdns.h"
/* compatibility */
#define evbuffer_get_length EVBUFFER_LENGTH
#define EVBUFFER_PULLUP(BUF, SIZE) EVBUFFER_DATA(BUF)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
/* functions that return int in libeven2 but void in libevent1 */
#define EVBUFFER_DRAIN(A, B) (evbuffer_drain((A), (B)), 0)
#define EVHTTP_SET_CB(A, B, C, D) (evhttp_set_cb((A), (B), (C), (D)), 0)
#endif
#define TAILQ_GET_NEXT(X) TAILQ_NEXT((X), next)
extern void *current_base;
/* XXX Remove unnecessary #defines and #includes
* XXX MAke sure we don't export symbols we don't want to export (check with ldd) */
/* This code is lifted from Python 2.7 */
#include "Python.h"
/* ubuntu 10.10 has HAVE_BLUETOOTH_* defined, but doesn't have the headers installed */
#ifndef USE_BLUETOOTH
#undef HAVE_BLUETOOTH_H
#undef HAVE_BLUETOOTH_BLUETOOTH_H
#endif
/* XXX This is a terrible mess of platform-dependent preprocessor hacks.
I hope some day someone can clean this up please... */
/* Hacks for gethostbyname_r(). On some non-Linux platforms, the configure
script doesn't get this right, so we hardcode some platform checks below.
On the other hand, not all Linux versions agree, so there the settings
computed by the configure script are needed! */
#ifndef linux
# undef HAVE_GETHOSTBYNAME_R_3_ARG
# undef HAVE_GETHOSTBYNAME_R_5_ARG
# undef HAVE_GETHOSTBYNAME_R_6_ARG
#endif
#ifndef WITH_THREAD
# undef HAVE_GETHOSTBYNAME_R
#endif
#ifdef HAVE_GETHOSTBYNAME_R
# if defined(_AIX) || defined(__osf__)
# define HAVE_GETHOSTBYNAME_R_3_ARG
# elif defined(__sun) || defined(__sgi)
# define HAVE_GETHOSTBYNAME_R_5_ARG
# elif defined(linux)
/* Rely on the configure script */
# else
# undef HAVE_GETHOSTBYNAME_R
# endif
#endif
#if !defined(HAVE_GETHOSTBYNAME_R) && defined(WITH_THREAD) && \
!defined(MS_WINDOWS)
# define USE_GETHOSTBYNAME_LOCK
#endif
/* To use __FreeBSD_version */
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
/* On systems on which getaddrinfo() is believed to not be thread-safe,
(this includes the getaddrinfo emulation) protect access with a lock. */
#if defined(WITH_THREAD) && (defined(__APPLE__) || \
(defined(__FreeBSD__) && __FreeBSD_version+0 < 503000) || \
defined(__OpenBSD__) || defined(__NetBSD__) || \
defined(__VMS) || !defined(HAVE_GETADDRINFO))
#define USE_GETADDRINFO_LOCK
#endif
#ifdef USE_GETADDRINFO_LOCK
#define ACQUIRE_GETADDRINFO_LOCK PyThread_acquire_lock(netdb_lock, 1);
#define RELEASE_GETADDRINFO_LOCK PyThread_release_lock(netdb_lock);
#else
#define ACQUIRE_GETADDRINFO_LOCK
#define RELEASE_GETADDRINFO_LOCK
#endif
#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK)
# include "pythread.h"
#endif
#if defined(PYCC_VACPP)
# include <types.h>
# include <io.h>
# include <sys/ioctl.h>
# include <utils.h>
# include <ctype.h>
#endif
#if defined(__VMS)
# include <ioctl.h>
#endif
#if defined(PYOS_OS2)
# define INCL_DOS
# define INCL_DOSERRORS
# define INCL_NOPMAPI
# include <os2.h>
#endif
#if defined(__sgi) && _COMPILER_VERSION>700 && !_SGIAPI
/* make sure that the reentrant (gethostbyaddr_r etc)
functions are declared correctly if compiling with
MIPSPro 7.x in ANSI C mode (default) */
/* XXX Using _SGIAPI is the wrong thing,
but I don't know what the right thing is. */
#undef _SGIAPI /* to avoid warning */
#define _SGIAPI 1
#undef _XOPEN_SOURCE
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#ifdef _SS_ALIGNSIZE
#define HAVE_GETADDRINFO 1
#define HAVE_GETNAMEINFO 1
#endif
#define HAVE_INET_PTON
#include <netdb.h>
#endif
/* Irix 6.5 fails to define this variable at all. This is needed
for both GCC and SGI's compiler. I'd say that the SGI headers
are just busted. Same thing for Solaris. */
#if (defined(__sgi) || defined(sun)) && !defined(INET_ADDRSTRLEN)
#define INET_ADDRSTRLEN 16
#endif
/* Generic includes */
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
/* Generic socket object definitions and includes */
#define PySocket_BUILDING_SOCKET
/* Socket module header file */
/* Includes needed for the sockaddr_* symbols below */
#ifndef MS_WINDOWS
#ifdef __VMS
# include <socket.h>
# else
# include <sys/socket.h>
# endif
# include <netinet/in.h>
# if !(defined(__BEOS__) || defined(__CYGWIN__) || (defined(PYOS_OS2) && defined(PYCC_VACPP)))
# include <netinet/tcp.h>
# endif
#else /* MS_WINDOWS */
# include <winsock2.h>
# include <ws2tcpip.h>
/* VC6 is shipped with old platform headers, and does not have MSTcpIP.h
* Separate SDKs have all the functions we want, but older ones don't have
* any version information.
* I use SIO_GET_MULTICAST_FILTER to detect a decent SDK.
*/
# ifdef SIO_GET_MULTICAST_FILTER
# include <MSTcpIP.h> /* for SIO_RCVALL */
# define HAVE_ADDRINFO
# define HAVE_SOCKADDR_STORAGE
# define HAVE_GETADDRINFO
# define HAVE_GETNAMEINFO
# define ENABLE_IPV6
# else
typedef int socklen_t;
# endif /* IPPROTO_IPV6 */
#endif /* MS_WINDOWS */
#ifdef HAVE_SYS_UN_H
# include <sys/un.h>
#else
# undef AF_UNIX
#endif
#ifdef HAVE_LINUX_NETLINK_H
# ifdef HAVE_ASM_TYPES_H
# include <asm/types.h>
# endif
# include <linux/netlink.h>
#else
# undef AF_NETLINK
#endif
#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/sco.h>
#include <bluetooth/hci.h>
#endif
#ifdef HAVE_BLUETOOTH_H
#include <bluetooth.h>
#endif
#ifdef HAVE_NETPACKET_PACKET_H
# include <sys/ioctl.h>
# include <net/if.h>
# include <netpacket/packet.h>
#endif
#ifdef HAVE_LINUX_TIPC_H
# include <linux/tipc.h>
#endif
/* Python module and C API name */
#define PySocket_MODULE_NAME "_socket"
#define PySocket_CAPI_NAME "CAPI"
#define PySocket_CAPSULE_NAME (PySocket_MODULE_NAME "." PySocket_CAPI_NAME)
/* Abstract the socket file descriptor type */
#ifdef MS_WINDOWS
typedef SOCKET SOCKET_T;
# ifdef MS_WIN64
# define SIZEOF_SOCKET_T 8
# else
# define SIZEOF_SOCKET_T 4
# endif
#else
typedef int SOCKET_T;
# define SIZEOF_SOCKET_T SIZEOF_INT
#endif
/* Socket address */
typedef union sock_addr {
struct sockaddr_in in;
#ifdef AF_UNIX
struct sockaddr_un un;
#endif
#ifdef AF_NETLINK
struct sockaddr_nl nl;
#endif
#ifdef ENABLE_IPV6
struct sockaddr_in6 in6;
struct sockaddr_storage storage;
#endif
#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
struct sockaddr_l2 bt_l2;
struct sockaddr_rc bt_rc;
struct sockaddr_sco bt_sco;
struct sockaddr_hci bt_hci;
#endif
#ifdef HAVE_NETPACKET_PACKET_H
struct sockaddr_ll ll;
#endif
} sock_addr_t;
/* Addressing includes */
#ifndef MS_WINDOWS
/* Non-MS WINDOWS includes */
# include <netdb.h>
/* Headers needed for inet_ntoa() and inet_addr() */
# ifdef __BEOS__
# include <net/netdb.h>
# elif defined(PYOS_OS2) && defined(PYCC_VACPP)
# include <netdb.h>
typedef size_t socklen_t;
# else
# include <arpa/inet.h>
# endif
# ifndef RISCOS
# include <fcntl.h>
# else
# include <sys/ioctl.h>
# include <socklib.h>
# define NO_DUP
int h_errno; /* not used */
# define INET_ADDRSTRLEN 16
# endif
#else
/* MS_WINDOWS includes */
# ifdef HAVE_FCNTL_H
# include <fcntl.h>
# endif
#endif
#include <stddef.h>
#ifndef offsetof
# define offsetof(type, member) ((size_t)(&((type *)0)->member))
#endif
#ifndef O_NONBLOCK
# define O_NONBLOCK O_NDELAY
#endif
#ifndef HAVE_INET_PTON
#if !defined(NTDDI_VERSION) || (NTDDI_VERSION < NTDDI_LONGHORN)
int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
#endif
#endif
#ifdef __APPLE__
/* On OS X, getaddrinfo returns no error indication of lookup
failure, so we must use the emulation instead of the libinfo
implementation. Unfortunately, performing an autoconf test
for this bug would require DNS access for the machine performing
the configuration, which is not acceptable. Therefore, we
determine the bug just by checking for __APPLE__. If this bug
gets ever fixed, perhaps checking for sys/version.h would be
appropriate, which is 10/0 on the system with the bug. */
#ifndef HAVE_GETNAMEINFO
/* This bug seems to be fixed in Jaguar. Ths easiest way I could
Find to check for Jaguar is that it has getnameinfo(), which
older releases don't have */
#undef HAVE_GETADDRINFO
#endif
#ifdef HAVE_INET_ATON
#define USE_INET_ATON_WEAKLINK
#endif
#endif
/* Convenience function to raise an error according to errno
and return a NULL pointer from a function. */
static PyObject *
set_error(void)
{
#ifdef MS_WINDOWS
int err_no = WSAGetLastError();
/* PyErr_SetExcFromWindowsErr() invokes FormatMessage() which
recognizes the error codes used by both GetLastError() and
WSAGetLastError */
if (err_no)
return PyErr_SetExcFromWindowsErr(PyExc_IOError, err_no);
#endif
#if defined(PYOS_OS2) && !defined(PYCC_GCC)
if (sock_errno() != NO_ERROR) {
APIRET rc;
ULONG msglen;
char outbuf[100];
int myerrorcode = sock_errno();
/* Retrieve socket-related error message from MPTN.MSG file */
rc = DosGetMessage(NULL, 0, outbuf, sizeof(outbuf),
myerrorcode - SOCBASEERR + 26,
"mptn.msg",
&msglen);
if (rc == NO_ERROR) {
PyObject *v;
/* OS/2 doesn't guarantee a terminator */
outbuf[msglen] = '\0';
if (strlen(outbuf) > 0) {
/* If non-empty msg, trim CRLF */
char *lastc = &outbuf[ strlen(outbuf)-1 ];
while (lastc > outbuf &&
isspace(Py_CHARMASK(*lastc))) {
/* Trim trailing whitespace (CRLF) */
*lastc-- = '\0';
}
}
v = Py_BuildValue("(is)", myerrorcode, outbuf);
if (v != NULL) {
PyErr_SetObject(PyExc_IOError, v);
Py_DECREF(v);
}
return NULL;
}
}
#endif
#if defined(RISCOS)
if (_inet_error.errnum != NULL) {
PyObject *v;
v = Py_BuildValue("(is)", errno, _inet_err());
if (v != NULL) {
PyErr_SetObject(PyExc_IOError, v);
Py_DECREF(v);
}
return NULL;
}
#endif
return PyErr_SetFromErrno(PyExc_IOError);
}
char* get_gaierror(int error)
{
#ifdef HAVE_GAI_STRERROR
return gai_strerror(error);
#else
return "getaddrinfo failed";
#endif
}
static PyObject *
set_gaierror(int error)
{
PyObject *v;
#ifdef EAI_SYSTEM
/* EAI_SYSTEM is not available on Windows XP. */
if (error == EAI_SYSTEM)
return set_error();
#endif
#ifdef HAVE_GAI_STRERROR
v = Py_BuildValue("(is)", error, gai_strerror(error));
#else
v = Py_BuildValue("(is)", error, "getaddrinfo failed");
#endif
if (v != NULL) {
PyErr_SetObject(PyExc_IOError, v);
Py_DECREF(v);
}
return NULL;
}
/* Create a string object representing an IP address.
This is always a string of the form 'dd.dd.dd.dd' (with variable
size numbers). */
static PyObject *
makeipaddr(struct sockaddr *addr, int addrlen)
{
char buf[NI_MAXHOST];
int error;
error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
NI_NUMERICHOST);
if (error) {
set_gaierror(error);
return NULL;
}
return PyString_FromString(buf);
}
/* Create an object representing the given socket address,
suitable for passing it back to bind(), connect() etc.
The family field of the sockaddr structure is inspected
to determine what kind of address it really is. */
/*ARGSUSED*/
PyObject* makesockaddr(int sockfd, struct sockaddr *addr, int addrlen, int proto)
{
if (addrlen == 0) {
/* No address -- may be recvfrom() from known socket */
Py_INCREF(Py_None);
return Py_None;
}
#ifdef __BEOS__
/* XXX: BeOS version of accept() doesn't set family correctly */
addr->sa_family = AF_INET;
#endif
switch (addr->sa_family) {
case AF_INET:
{
struct sockaddr_in *a;
PyObject *addrobj = makeipaddr(addr, sizeof(*a));
PyObject *ret = NULL;
if (addrobj) {
a = (struct sockaddr_in *)addr;
ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
Py_DECREF(addrobj);
}
return ret;
}
#if defined(AF_UNIX)
case AF_UNIX:
{
struct sockaddr_un *a = (struct sockaddr_un *) addr;
#ifdef linux
if (a->sun_path[0] == 0) { /* Linux abstract namespace */
addrlen -= offsetof(struct sockaddr_un, sun_path);
return PyString_FromStringAndSize(a->sun_path,
addrlen);
}
else
#endif /* linux */
{
/* regular NULL-terminated string */
return PyString_FromString(a->sun_path);
}
}
#endif /* AF_UNIX */
#if defined(AF_NETLINK)
case AF_NETLINK:
{
struct sockaddr_nl *a = (struct sockaddr_nl *) addr;
return Py_BuildValue("II", a->nl_pid, a->nl_groups);
}
#endif /* AF_NETLINK */
#ifdef ENABLE_IPV6
case AF_INET6:
{
struct sockaddr_in6 *a;
PyObject *addrobj = makeipaddr(addr, sizeof(*a));
PyObject *ret = NULL;
if (addrobj) {
a = (struct sockaddr_in6 *)addr;
ret = Py_BuildValue("Oiii",
addrobj,
ntohs(a->sin6_port),
a->sin6_flowinfo,
a->sin6_scope_id);
Py_DECREF(addrobj);
}
return ret;
}
#endif
#ifdef USE_BLUETOOTH
case AF_BLUETOOTH:
switch (proto) {
case BTPROTO_L2CAP:
{
struct sockaddr_l2 *a = (struct sockaddr_l2 *) addr;
PyObject *addrobj = makebdaddr(&_BT_L2_MEMB(a, bdaddr));
PyObject *ret = NULL;
if (addrobj) {
ret = Py_BuildValue("Oi",
addrobj,
_BT_L2_MEMB(a, psm));
Py_DECREF(addrobj);
}
return ret;
}
case BTPROTO_RFCOMM:
{
struct sockaddr_rc *a = (struct sockaddr_rc *) addr;
PyObject *addrobj = makebdaddr(&_BT_RC_MEMB(a, bdaddr));
PyObject *ret = NULL;
if (addrobj) {
ret = Py_BuildValue("Oi",
addrobj,
_BT_RC_MEMB(a, channel));
Py_DECREF(addrobj);
}
return ret;
}
case BTPROTO_HCI:
{
struct sockaddr_hci *a = (struct sockaddr_hci *) addr;
PyObject *ret = NULL;
ret = Py_BuildValue("i", _BT_HCI_MEMB(a, dev));
return ret;
}
#if !defined(__FreeBSD__)
case BTPROTO_SCO:
{
struct sockaddr_sco *a = (struct sockaddr_sco *) addr;
return makebdaddr(&_BT_SCO_MEMB(a, bdaddr));
}
#endif
default:
PyErr_SetString(PyExc_ValueError,
"Unknown Bluetooth protocol");
return NULL;
}
#endif
#ifdef HAVE_NETPACKET_PACKET_H
case AF_PACKET:
{
struct sockaddr_ll *a = (struct sockaddr_ll *)addr;
char *ifname = "";
struct ifreq ifr;
/* need to look up interface name give index */
if (a->sll_ifindex) {
ifr.ifr_ifindex = a->sll_ifindex;
if (ioctl(sockfd, SIOCGIFNAME, &ifr) == 0)
ifname = ifr.ifr_name;
}
return Py_BuildValue("shbhs#",
ifname,
ntohs(a->sll_protocol),
a->sll_pkttype,
a->sll_hatype,
a->sll_addr,
a->sll_halen);
}
#endif
#ifdef HAVE_LINUX_TIPC_H
case AF_TIPC:
{
struct sockaddr_tipc *a = (struct sockaddr_tipc *) addr;
if (a->addrtype == TIPC_ADDR_NAMESEQ) {
return Py_BuildValue("IIIII",
a->addrtype,
a->addr.nameseq.type,
a->addr.nameseq.lower,
a->addr.nameseq.upper,
a->scope);
} else if (a->addrtype == TIPC_ADDR_NAME) {
return Py_BuildValue("IIIII",
a->addrtype,
a->addr.name.name.type,
a->addr.name.name.instance,
a->addr.name.name.instance,
a->scope);
} else if (a->addrtype == TIPC_ADDR_ID) {
return Py_BuildValue("IIIII",
a->addrtype,
a->addr.id.node,
a->addr.id.ref,
0,
a->scope);
} else {
PyErr_SetString(PyExc_ValueError,
"Invalid address type");
return NULL;
}
}
#endif
/* More cases here... */
default:
/* If we don't know the address family, don't raise an
exception -- return it as a tuple. */
return Py_BuildValue("is#",
addr->sa_family,
addr->sa_data,
sizeof(addr->sa_data));
}
}
char* get_gaierror(int);
PyObject* makesockaddr(int sockfd, void* addr, int addrlen, int proto);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment