Commit b3b4e30a authored by Denis Bilenko's avatar Denis Bilenko

core: make http_request reply with 500 in __dealloc__ if no reply was sent;...

core: make http_request reply with 500 in __dealloc__ if no reply was sent; make http class responsible for detaching http_requests on connection close;

- make http_request weak-referencable
- remove set_closecb() method from http_connection (it is used internally now, to detach http_requests)
- remove set_gencb() from http class; pass the callback to the constructor instead
- remove set_cb() from http class: it does not fit very well with the current design and is not used by gevent itself; use issue tracker if you need this back
parent 14ad42d6
......@@ -43,6 +43,7 @@ __all__ = ['event', 'read_event', 'write_event', 'timer', 'signal', 'active_even
import sys
import traceback
from pprint import pformat
import weakref
DEF EVENT_INTERNAL_AVAILABLE = False
......
......@@ -109,6 +109,7 @@ cdef class http_request:
# 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 object _input_buffer
cdef object _output_buffer
......@@ -116,6 +117,10 @@ cdef class http_request:
def __init__(self, size_t _obj):
self.__obj = <evhttp_request*>_obj
def __dealloc__(self):
if self.__obj:
report_internal_error(self.__obj)
property _obj:
def __get__(self):
......@@ -394,19 +399,6 @@ cdef class http_request:
evhttp_clear_headers(self.__obj.output_headers)
cdef void _http_connection_closecb_handler(evhttp_connection* connection, void *arg) with gil:
try:
server = <object>arg
conn = http_connection(<size_t>connection)
server._cb_connection_close(conn)
except:
traceback.print_exc()
try:
sys.stderr.write('Failed to execute callback for evhttp connection:\n connection = %s\n server = %s\n\n' % (conn, server))
except:
pass
cdef class http_connection:
cdef evhttp_connection* __obj
......@@ -453,25 +445,37 @@ cdef class http_connection:
addr = None
return (addr, port)
def set_closecb(self, callback):
if not self.__obj:
raise HttpConnectionDeleted
evhttp_connection_set_closecb(self.__obj, _http_connection_closecb_handler, <void *>callback)
cdef void _http_cb_handler(evhttp_request* request, void *arg) with gil:
cdef object callback = <object>arg
cdef http server = <object>arg
cdef http_request req = http_request(<size_t>request)
cdef evhttp_connection* conn = request.evcon
cdef object requests
try:
r = http_request(<size_t>request)
callback(r)
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('Failed to execute callback for evhttp request:\n request = %s\n callback = %s\n\n' % (r, callback))
sys.stderr.write('Failed to handle request: %s\n\n' % (req, ))
except:
pass
if request.response_code == 0:
report_internal_error(request)
traceback.print_exc()
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):
......@@ -488,15 +492,19 @@ cdef void report_internal_error(evhttp_request* request):
cdef class http:
cdef evhttp* __obj
cdef object _gencb
cdef list _cbs
cdef object handle
cdef dict _requests
def __init__(self):
self.__obj = evhttp_new(current_base)
def __init__(self, handle):
self.handle = handle
self._gencb = None
self._cbs = []
self._requests = {}
self.__obj = evhttp_new(current_base)
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
......@@ -521,17 +529,3 @@ cdef class http:
if res:
raise RuntimeError("evhttp_accept_socket(%s) returned %s" % (fd, res))
def set_cb(self, char* path, object callback):
cdef res = EVHTTP_SET_CB(self.__obj, path, _http_cb_handler, <void *>callback)
if res == 0:
self._cbs.append(callback)
return
elif res == -1:
raise RuntimeError('evhttp_set_cb(%r, %r) returned %s: callback already exists' % (path, callback, res))
else:
raise RuntimeError('evhttp_set_cb(%r, %r) returned %s' % (path, callback, res))
def set_gencb(self, callback):
self._gencb = callback
evhttp_set_gencb(self.__obj, _http_cb_handler, <void *>callback)
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