fix several bugs, segfault and memory leak

pull/122/head
Ciro 2023-03-19 13:18:29 -03:00
rodzic e0e28263f5
commit 3afb7ec2f2
15 zmienionych plików z 325 dodań i 216 usunięć

Wyświetl plik

@ -19,4 +19,4 @@ async def app(scope, receive, send):
if __name__ == "__main__":
ASGI(app, lifespan=False).listen(8000, lambda config: print(f"Listening on port http://localhost:{config.port} now\n")).run(8)
ASGI(app, lifespan=False).listen(8000, lambda config: print(f"Listening on port http://localhost:{config.port} now\n")).run(1)

Wyświetl plik

@ -24,14 +24,24 @@ def app(environ, start_response):
yield payload[sended:end]
sended = end
# import gc
# gc.collect()
# gc.set_threshold(50, 3, 3)
# import tracemalloc
# tracemalloc.start()
def app_hello(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain'), ('Content-Length', '13')])
yield b'Hello, World!'
# start_response('200 OK', [('Content-Type', 'text/plain'), ('Content-Length', '13')])
start_response('200 OK', [('Content-Type', 'text/plain')])
return [ b'Hello, World!']
if __name__ == "__main__":
# import fastwsgi
# fastwsgi.run(wsgi_app=app_hello, host='127.0.0.1', port=8000)
# fastwsgi.run(wsgi_app=app_hello, host='127.0.0.1', port=8000, loglevel=0)
# from meinheld import server
# server.listen(("0.0.0.0", 8000))
# server.run(app_hello)

Wyświetl plik

@ -0,0 +1,4 @@
while true
do
wrk -t1 -c200 -d1 -H 'Connection: keep-alive' http://127.0.0.1:8000 > /dev/null
done

Wyświetl plik

@ -0,0 +1,83 @@
import sys
import io
import time
import datetime
import socket
import optparse
parser = optparse.OptionParser("usage: %prog [options]", add_help_option=False)
parser.add_option("-h", "--host", dest="host", default='127.0.0.1', type="string")
parser.add_option("-p", "--port", dest="port", default=3000, type="int")
(opt, args) = parser.parse_args()
def get_request(path = r'/', host = '127.0.0.1', port = 3000):
req = f'GET {path}' + r' HTTP/1.1' + '\r\n'
req += f'Host: {host}:{port}\r\n'
req += r'User-Agent: curl/7.66.0' + '\r\n'
req += r'Accept: */*' + '\r\n'
req += '\r\n'
return req
payload_tiny = get_request(host = opt.host, port = opt.port)
payload_tiny = payload_tiny.encode('utf-8')
def create_sock(timeout = 0.001):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
sock.connect((opt.host, opt.port))
return sock
sock = create_sock()
sock.sendall(payload_tiny)
time.sleep(0.020)
resp = sock.recv(4096)
print('====== response ========')
print(resp.decode('utf-8'))
print('========================')
sock.close()
start_time = datetime.datetime.now()
test1_limit = start_time + datetime.timedelta(seconds = 1)
test2_limit = test1_limit + datetime.timedelta(seconds = 10)
sock = create_sock()
while True:
if datetime.datetime.now() >= test1_limit:
break
sock.sendall(payload_tiny)
try:
resp = sock.recv(4096)
except socket.timeout:
pass
print(f'Test 1 completed!')
sock.close()
req_num = 1000*1000
payload_huge = payload_tiny * req_num
#print(len(payload_huge))
print(f'Run test 2 ...')
totalsent = 0
totalresp = b''
sock = create_sock()
while True:
if datetime.datetime.now() >= test2_limit:
print(f'Test 2: Timeout exceeded!')
break
try:
rc = sock.send(payload_huge[totalsent:])
if rc == 0:
#raise RuntimeError("socket connection broken")
pass
totalsent += rc
resp = sock.recv(65*1024)
totalresp += resp
except socket.timeout:
pass
except ConnectionResetError:
print(f'totalsent = {totalsent}, totalrecv = {len(totalresp)}')
print(f'LastResp: {totalresp[-256:]}')
raise
sock.close()
print("==== Test Finish =====")

Wyświetl plik

@ -8,7 +8,7 @@ def run_app():
router = app.router()
@router.get("/")
def home(res, req):
async def home(res, req):
res.send(b"Hello, World!")
app.listen(

Wyświetl plik

@ -27,11 +27,12 @@ def graphiql_from(Query, Mutation=None):
async def graph_ql(res, body, context_value):
query = body["query"]
variables = body.get("variables", None)
root_value = body.get("rootValue", None)
operation_name = body.get("operationName", None)
data = await schema.execute(
query,
variables,

Wyświetl plik

@ -1,7 +1,7 @@
import asyncio
from .dataclasses import AppListenOptions, AppOptions
from .tasks import TaskFactory, create_task, RequestTask
from .socketify import (
App,
OpCode,

Wyświetl plik

@ -10,7 +10,13 @@ import uuid
import asyncio
is_pypy = platform.python_implementation() == "PyPy"
@ffi.callback("void(uws_res_t*, void*)")
def asgi_on_abort_handler(res, user_data):
ctx = ffi.from_handle(user_data)
ctx.aborted = True
if ctx.abort_future is not None:
ctx.abort_future.set_result(True)
ctx.abort_future = None
async def task_wrapper(task):
try:
@ -49,9 +55,9 @@ def ws_open(ws, user_data):
@ffi.callback(
"void(int, uws_res_t*, socketify_asgi_ws_data, uws_socket_context_t* socket, void*, bool*)"
"void(int, uws_res_t*, socketify_asgi_ws_data, uws_socket_context_t* socket, void*)"
)
def ws_upgrade(ssl, response, info, socket_context, user_data, aborted):
def ws_upgrade(ssl, response, info, socket_context, user_data):
app = ffi.from_handle(user_data)
headers = []
next_header = info.header_list
@ -82,6 +88,7 @@ def ws_upgrade(ssl, response, info, socket_context, user_data, aborted):
extensions = ffi.unpack(info.extensions, info.extensions_size).decode("utf8")
compress = app.ws_compression
ws = ASGIWebSocket(app.server.loop)
lib.uws_res_on_aborted(ssl, response, asgi_on_abort_handler, ws._ptr)
scope = {
"type": "websocket",
@ -108,7 +115,7 @@ def ws_upgrade(ssl, response, info, socket_context, user_data, aborted):
}
async def send(options):
if bool(aborted[0]):
if ws.aborted:
return False
type = options["type"]
if type == "websocket.send":
@ -258,6 +265,22 @@ class ASGIDataQueue:
self.is_end = False
self.next_data_future = loop.create_future()
class ASGIContext:
def __init__(self, ssl, response, loop):
self._ptr = ffi.new_handle(self)
self.aborted = False
self.sended_empty = False
self.data_queue = None
self.ssl = ssl
self.response = response
self.loop = loop
self.abort_future = None
async def wait_disconnect(self):
if not self.aborted:
if self.abort_future is None:
self.abort_future = self.loop.create_future()
await self.abort_future
class ASGIWebSocket:
def __init__(self, loop):
@ -272,6 +295,14 @@ class ASGIWebSocket:
self._message = None
self._ptr = ffi.new_handle(self)
self.unregister = None
self.aborted = False
self.abort_future = None
async def wait_disconnect(self):
if not self.aborted:
if self.abort_future is None:
self.abort_future = self.loop.create_future()
await self.abort_future
def accept(self):
self.accept_future = self.loop.create_future()
@ -404,8 +435,8 @@ def uws_asgi_corked_403_handler(res, user_data):
lib.uws_res_end_without_body(ssl, res, 0)
@ffi.callback("void(int, uws_res_t*, socketify_asgi_data, void*, bool*)")
def asgi(ssl, response, info, user_data, aborted):
@ffi.callback("void(int, uws_res_t*, socketify_asgi_data, void*)")
def asgi(ssl, response, info, user_data):
app = ffi.from_handle(user_data)
headers = []
@ -436,18 +467,21 @@ def asgi(ssl, response, info, user_data, aborted):
"raw_path": url,
"query_string": ffi.unpack(info.query_string, info.query_string_size),
"headers": headers,
}
loop = app.server.loop
ctx = ASGIContext(ssl, response, loop)
if bool(info.has_content):
data_queue = ASGIDataQueue(app.server.loop)
data_queue = ASGIDataQueue(loop)
lib.uws_res_on_data(ssl, response, asgi_on_data_handler, data_queue._ptr)
else:
data_queue = None
ctx.data_queue = data_queue
lib.uws_res_on_aborted(ssl, response, asgi_on_abort_handler, ctx._ptr)
sended_empty = False
async def receive():
nonlocal sended_empty
if bool(aborted[0]):
if ctx.aborted:
return {"type": "http.disconnect"}
data_queue = ctx.data_queue
if data_queue:
if data_queue.queue.empty():
if not data_queue.is_end:
@ -460,19 +494,21 @@ def asgi(ssl, response, info, user_data, aborted):
return data_queue.queue.get(False) # consume queue
# no more body, just EMPTY RESPONSE
if not sended_empty:
sended_empty = True
if not ctx.sended_empty:
ctx.sended_empty = True
return EMPTY_RESPONSE
# already sended empty body so wait for aborted request
while not bool(aborted[0]):
await asyncio.sleep(0.01) #10ms is good enought
if not ctx.aborted:
await ctx.wait_disconnect()
return {"type": "http.disconnect"}
async def send(options):
if bool(aborted[0]):
if ctx.aborted:
return False
type = options["type"]
ssl = ctx.ssl
response = ctx.response
if type == "http.response.start":
# can also be more native optimized to do it in one GIL call
# try socketify_res_write_int_status_with_headers and create and socketify_res_cork_write_int_status_with_headers
@ -501,6 +537,12 @@ def asgi(ssl, response, info, user_data, aborted):
elif isinstance(message, str):
data = message.encode("utf-8")
lib.socketify_res_cork_end(ssl, response, data, len(data), 0)
if ctx.abort_future is not None:
ctx.aborted = True
ctx.abort_future.set_result(False)
ctx.abort_future = None
return True
return False
@ -546,14 +588,6 @@ class _ASGI:
self._run_task = run_task
else:
if sys.version_info >= (3, 8): # name fixed to avoid dynamic name
def run_task(task):
future = create_task(loop, task_wrapper(task))
future._log_destroy_pending = False
self._run_task = run_task
else:
def run_task(task):
future = create_task(loop, task_wrapper(task))

Wyświetl plik

@ -78,8 +78,12 @@ class Loop:
def _keep_alive(self):
if self.started:
self.uv_loop.run_nowait()
self.loop.call_soon(self._keep_alive)
if int(self.uv_loop.run_nowait()) > 1:
# be more agressive when needed
self.loop.call_soon(self._keep_alive)
else:
# this will relax CPU usage a lot when idle
self.loop.call_later(0.001, self._keep_alive)
def create_task(self, *args, **kwargs):
# this is not using optimized create_task yet

Wyświetl plik

@ -352,21 +352,21 @@ typedef struct {
socketify_header* header_list;
} socketify_asgi_ws_data;
typedef void (*socketify_asgi_method_handler)(int ssl, uws_res_t *response, socketify_asgi_data request, void *user_data, bool* aborted);
typedef void (*socketify_asgi_method_handler)(int ssl, uws_res_t *response, socketify_asgi_data request, void *user_data);
typedef struct {
int ssl;
uws_app_t* app;
socketify_asgi_method_handler handler;
void * user_data;
} socksocketify_asgi_app_info;
typedef void (*socketify_asgi_ws_method_handler)(int ssl, uws_res_t *response, socketify_asgi_ws_data request, uws_socket_context_t* socket, void *user_data, bool* aborted);
typedef void (*socketify_asgi_ws_method_handler)(int ssl, uws_res_t *response, socketify_asgi_ws_data request, uws_socket_context_t* socket, void *user_data);
typedef struct {
int ssl;
uws_app_t* app;
socketify_asgi_ws_method_handler handler;
uws_socket_behavior_t behavior;
void * user_data;
} socksocketify_asgi_ws_app_info;
} socketify_asgi_ws_app_info;
socketify_asgi_data socketify_asgi_request(int ssl, uws_req_t *req, uws_res_t *res);
void socketify_destroy_headers(socketify_header* headers);
@ -376,8 +376,8 @@ socketify_asgi_ws_data socketify_asgi_ws_request(int ssl, uws_req_t *req, uws_re
bool socketify_res_write_int_status(int ssl, uws_res_t* res, int code);
socksocketify_asgi_app_info* socketify_add_asgi_http_handler(int ssl, uws_app_t* app, socketify_asgi_method_handler handler, void* user_data);
void socketify_destroy_asgi_app_info(socksocketify_asgi_app_info* app);
socksocketify_asgi_ws_app_info* socketify_add_asgi_ws_handler(int ssl, uws_app_t* app, uws_socket_behavior_t behavior, socketify_asgi_ws_method_handler handler, void* user_data);
void socketify_destroy_asgi_ws_app_info(socksocketify_asgi_ws_app_info* app);
socketify_asgi_ws_app_info* socketify_add_asgi_ws_handler(int ssl, uws_app_t* app, uws_socket_behavior_t behavior, socketify_asgi_ws_method_handler handler, void* user_data);
void socketify_destroy_asgi_ws_app_info(socketify_asgi_ws_app_info* app);
void socketify_res_cork_write(int ssl, uws_res_t *response, const char* data, size_t length);
void socketify_res_cork_end(int ssl, uws_res_t *response, const char* data, size_t length, bool close_connection);

Wyświetl plik

@ -114,7 +114,8 @@ extern "C"
if (ssl)
{
uWS::HttpResponse<true> *uwsRes = (uWS::HttpResponse<true> *)res;
uwsRes->cork([=](){
uwsRes->cork([=]()
{
socketify_res_write_int_status(ssl, res, code);
if (content_type && content_type_size)
{
@ -128,13 +129,13 @@ extern "C"
else
{
uws_res_end_without_body(ssl, res, close_connection);
}
});
} });
}
else
{
uWS::HttpResponse<false> *uwsRes = (uWS::HttpResponse<false> *)res;
uwsRes->cork([=](){
uwsRes->cork([=]()
{
socketify_res_write_int_status(ssl, res, code);
@ -150,8 +151,7 @@ extern "C"
else
{
uws_res_end_without_body(ssl, res, close_connection);
}
});
} });
}
}
@ -161,7 +161,8 @@ extern "C"
if (ssl)
{
uWS::HttpResponse<true> *uwsRes = (uWS::HttpResponse<true> *)res;
uwsRes->cork([=](){
uwsRes->cork([=]()
{
uws_res_write_status(ssl, res, status_code, status_code_size);
@ -177,13 +178,13 @@ extern "C"
else
{
uws_res_end_without_body(ssl, res, close_connection);
}
});
} });
}
else
{
uWS::HttpResponse<false> *uwsRes = (uWS::HttpResponse<false> *)res;
uwsRes->cork([=](){
uwsRes->cork([=]()
{
uws_res_write_status(ssl, res, status_code, status_code_size);
@ -199,8 +200,7 @@ extern "C"
else
{
uws_res_end_without_body(ssl, res, close_connection);
}
});
} });
}
}
@ -415,15 +415,7 @@ extern "C"
{
socksocketify_asgi_app_info *info = ((socksocketify_asgi_app_info *)user_data);
socketify_asgi_data data = socketify_asgi_request(info->ssl, request, response);
bool *aborted = (bool *)malloc(sizeof(aborted));
*aborted = false;
uws_res_on_aborted(
info->ssl, response, [](uws_res_t *res, void *opcional_data)
{
bool* aborted = (bool*)opcional_data;
*aborted = true; },
aborted);
info->handler(info->ssl, response, data, info->user_data, aborted);
info->handler(info->ssl, response, data, info->user_data);
socketify_destroy_headers(data.header_list);
}
@ -490,9 +482,9 @@ extern "C"
}
}
socksocketify_asgi_ws_app_info *socketify_add_asgi_ws_handler(int ssl, uws_app_t *app, uws_socket_behavior_t behavior, socketify_asgi_ws_method_handler handler, void *user_data)
socketify_asgi_ws_app_info *socketify_add_asgi_ws_handler(int ssl, uws_app_t *app, uws_socket_behavior_t behavior, socketify_asgi_ws_method_handler handler, void *user_data)
{
socksocketify_asgi_ws_app_info *info = (socksocketify_asgi_ws_app_info *)malloc(sizeof(socksocketify_asgi_ws_app_info));
socketify_asgi_ws_app_info *info = (socketify_asgi_ws_app_info *)malloc(sizeof(socketify_asgi_ws_app_info));
info->ssl = ssl;
info->app = app;
info->handler = handler;
@ -505,35 +497,27 @@ extern "C"
ws_behavior.upgrade = [](uws_res_t *response, uws_req_t *request, uws_socket_context_t *context, void *user_data)
{
socksocketify_asgi_ws_app_info *info = ((socksocketify_asgi_ws_app_info *)user_data);
socketify_asgi_ws_app_info *info = ((socketify_asgi_ws_app_info *)user_data);
socketify_asgi_ws_data data = socketify_asgi_ws_request(info->ssl, request, response);
bool *aborted = (bool *)malloc(sizeof(aborted));
*aborted = false;
uws_res_on_aborted(
info->ssl, response, [](uws_res_t *res, void *opcional_data)
{
bool* aborted = (bool*)opcional_data;
*aborted = true; },
aborted);
info->handler(info->ssl, response, data, context, info->user_data, aborted);
info->handler(info->ssl, response, data, context, info->user_data);
socketify_destroy_headers(data.header_list);
};
ws_behavior.open = [](uws_websocket_t *ws, void *user_data)
{
socksocketify_asgi_ws_app_info *info = ((socksocketify_asgi_ws_app_info *)user_data);
socketify_asgi_ws_app_info *info = ((socketify_asgi_ws_app_info *)user_data);
auto socket_data = uws_ws_get_user_data(info->ssl, ws);
info->behavior.open(ws, socket_data);
};
ws_behavior.message = [](uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode, void *user_data)
{
socksocketify_asgi_ws_app_info *info = ((socksocketify_asgi_ws_app_info *)user_data);
socketify_asgi_ws_app_info *info = ((socketify_asgi_ws_app_info *)user_data);
auto socket_data = uws_ws_get_user_data(info->ssl, ws);
info->behavior.message(ws, message, length, opcode, socket_data);
};
ws_behavior.close = [](uws_websocket_t *ws, int code, const char *message, size_t length, void *user_data)
{
socksocketify_asgi_ws_app_info *info = ((socksocketify_asgi_ws_app_info *)user_data);
socketify_asgi_ws_app_info *info = ((socketify_asgi_ws_app_info *)user_data);
auto socket_data = uws_ws_get_user_data(info->ssl, ws);
info->behavior.close(ws, code, message, length, socket_data);
};
@ -559,7 +543,7 @@ extern "C"
{
free(app);
}
void socketify_destroy_asgi_ws_app_info(socksocketify_asgi_ws_app_info *app)
void socketify_destroy_asgi_ws_app_info(socketify_asgi_ws_app_info *app)
{
free(app);
}

Wyświetl plik

@ -8,140 +8,144 @@
extern "C"
{
#endif
DLL_EXPORT typedef void (*socketify_prepare_handler)(void* user_data);
DLL_EXPORT typedef void (*socketify_timer_handler)(void* user_data);
DLL_EXPORT typedef void (*socketify_prepare_handler)(void *user_data);
DLL_EXPORT typedef void (*socketify_timer_handler)(void *user_data);
DLL_EXPORT typedef enum {
SOCKETIFY_RUN_DEFAULT = 0,
SOCKETIFY_RUN_ONCE,
SOCKETIFY_RUN_NOWAIT
} socketify_run_mode;
DLL_EXPORT typedef enum {
SOCKETIFY_RUN_DEFAULT = 0,
SOCKETIFY_RUN_ONCE,
SOCKETIFY_RUN_NOWAIT
} socketify_run_mode;
DLL_EXPORT typedef struct {
void* uv_prepare_ptr;
DLL_EXPORT typedef struct
{
void *uv_prepare_ptr;
socketify_prepare_handler on_prepare_handler;
void* on_prepare_data;
void* uv_loop;
} socketify_loop;
void *on_prepare_data;
void *uv_loop;
} socketify_loop;
DLL_EXPORT typedef struct{
void* uv_timer_ptr;
DLL_EXPORT typedef struct
{
void *uv_timer_ptr;
socketify_timer_handler handler;
void* user_data;
} socketify_timer;
void *user_data;
} socketify_timer;
DLL_EXPORT typedef struct
{
DLL_EXPORT typedef struct {
const char *name;
const char *value;
const char* name;
const char* value;
size_t name_size;
size_t value_size;
void* next;
} socketify_header;
size_t name_size;
size_t value_size;
void *next;
} socketify_header;
DLL_EXPORT typedef struct {
DLL_EXPORT typedef struct
{
const char* full_url;
const char* url;
const char* query_string;
const char* method;
const char* remote_address;
const char *full_url;
const char *url;
const char *query_string;
const char *method;
const char *remote_address;
size_t full_url_size;
size_t url_size;
size_t query_string_size;
size_t method_size;
size_t remote_address_size;
size_t full_url_size;
size_t url_size;
size_t query_string_size;
size_t method_size;
size_t remote_address_size;
socketify_header* header_list;
socketify_header *header_list;
bool has_content;
} socketify_asgi_data;
bool has_content;
} socketify_asgi_data;
DLL_EXPORT typedef struct {
DLL_EXPORT typedef struct
{
const char* full_url;
const char* url;
const char* query_string;
const char* method;
const char* remote_address;
const char *full_url;
const char *url;
const char *query_string;
const char *method;
const char *remote_address;
size_t full_url_size;
size_t url_size;
size_t query_string_size;
size_t method_size;
size_t remote_address_size;
size_t full_url_size;
size_t url_size;
size_t query_string_size;
size_t method_size;
size_t remote_address_size;
const char* protocol;
const char* key;
const char* extensions;
size_t protocol_size;
size_t key_size;
size_t extensions_size;
const char *protocol;
const char *key;
const char *extensions;
size_t protocol_size;
size_t key_size;
size_t extensions_size;
socketify_header* header_list;
} socketify_asgi_ws_data;
socketify_header *header_list;
} socketify_asgi_ws_data;
DLL_EXPORT typedef void (*socketify_asgi_method_handler)(int ssl, uws_res_t *response, socketify_asgi_data request, void *user_data, bool* aborted);
DLL_EXPORT typedef void (*socketify_asgi_ws_method_handler)(int ssl, uws_res_t *response, socketify_asgi_ws_data request, uws_socket_context_t* socket, void *user_data, bool* aborted);
DLL_EXPORT typedef struct {
int ssl;
uws_app_t* app;
socketify_asgi_method_handler handler;
void * user_data;
} socksocketify_asgi_app_info;
DLL_EXPORT typedef void (*socketify_asgi_method_handler)(int ssl, uws_res_t *response, socketify_asgi_data request, void *user_data);
DLL_EXPORT typedef void (*socketify_asgi_ws_method_handler)(int ssl, uws_res_t *response, socketify_asgi_ws_data request, uws_socket_context_t *socket, void *user_data);
DLL_EXPORT typedef struct
{
int ssl;
uws_app_t *app;
socketify_asgi_method_handler handler;
void *user_data;
} socksocketify_asgi_app_info;
DLL_EXPORT typedef struct {
int ssl;
uws_app_t* app;
socketify_asgi_ws_method_handler handler;
uws_socket_behavior_t behavior;
void * user_data;
} socksocketify_asgi_ws_app_info;
DLL_EXPORT typedef struct
{
int ssl;
uws_app_t *app;
socketify_asgi_ws_method_handler handler;
uws_socket_behavior_t behavior;
void *user_data;
} socketify_asgi_ws_app_info;
DLL_EXPORT socketify_loop *socketify_create_loop();
DLL_EXPORT bool socketify_constructor_failed(socketify_loop *loop);
DLL_EXPORT bool socketify_on_prepare(socketify_loop *loop, socketify_prepare_handler handler, void *user_data);
DLL_EXPORT bool socketify_prepare_unbind(socketify_loop *loop);
DLL_EXPORT void socketify_destroy_loop(socketify_loop *loop);
DLL_EXPORT void *socketify_get_native_loop(socketify_loop *loop);
DLL_EXPORT socketify_loop * socketify_create_loop();
DLL_EXPORT bool socketify_constructor_failed(socketify_loop* loop);
DLL_EXPORT bool socketify_on_prepare(socketify_loop* loop, socketify_prepare_handler handler, void* user_data);
DLL_EXPORT bool socketify_prepare_unbind(socketify_loop* loop);
DLL_EXPORT void socketify_destroy_loop(socketify_loop* loop);
DLL_EXPORT void* socketify_get_native_loop(socketify_loop* loop);
DLL_EXPORT int socketify_loop_run(socketify_loop *loop, socketify_run_mode mode);
DLL_EXPORT void socketify_loop_stop(socketify_loop *loop);
DLL_EXPORT int socketify_loop_run(socketify_loop* loop, socketify_run_mode mode);
DLL_EXPORT void socketify_loop_stop(socketify_loop* loop);
DLL_EXPORT socketify_timer *socketify_create_timer(socketify_loop *loop, uint64_t timeout, uint64_t repeat, socketify_timer_handler handler, void *user_data);
DLL_EXPORT void socketify_timer_destroy(socketify_timer *timer);
DLL_EXPORT void socketify_timer_set_repeat(socketify_timer *timer, uint64_t repeat);
DLL_EXPORT socketify_timer* socketify_create_timer(socketify_loop* loop, uint64_t timeout, uint64_t repeat, socketify_timer_handler handler, void* user_data);
DLL_EXPORT void socketify_timer_destroy(socketify_timer* timer);
DLL_EXPORT void socketify_timer_set_repeat(socketify_timer* timer, uint64_t repeat);
DLL_EXPORT socketify_timer *socketify_create_check(socketify_loop *loop, socketify_timer_handler handler, void *user_data);
DLL_EXPORT void socketify_check_destroy(socketify_timer *timer);
DLL_EXPORT socketify_timer* socketify_create_check(socketify_loop* loop, socketify_timer_handler handler, void* user_data);
DLL_EXPORT void socketify_check_destroy(socketify_timer* timer);
DLL_EXPORT socketify_asgi_data socketify_asgi_request(int ssl, uws_req_t *req, uws_res_t *res);
DLL_EXPORT void socketify_destroy_headers(socketify_header *headers);
DLL_EXPORT bool socketify_res_write_int_status_with_headers(int ssl, uws_res_t *res, int code, socketify_header *headers);
DLL_EXPORT void socketify_res_write_headers(int ssl, uws_res_t *res, socketify_header *headers);
DLL_EXPORT bool socketify_res_write_int_status(int ssl, uws_res_t *res, int code);
DLL_EXPORT socketify_asgi_ws_data socketify_asgi_ws_request(int ssl, uws_req_t *req, uws_res_t *res);
DLL_EXPORT socketify_asgi_data socketify_asgi_request(int ssl, uws_req_t *req, uws_res_t *res);
DLL_EXPORT void socketify_destroy_headers(socketify_header* headers);
DLL_EXPORT bool socketify_res_write_int_status_with_headers(int ssl, uws_res_t* res, int code, socketify_header* headers);
DLL_EXPORT void socketify_res_write_headers(int ssl, uws_res_t* res, socketify_header* headers);
DLL_EXPORT bool socketify_res_write_int_status(int ssl, uws_res_t* res, int code);
DLL_EXPORT socketify_asgi_ws_data socketify_asgi_ws_request(int ssl, uws_req_t *req, uws_res_t *res);
DLL_EXPORT socksocketify_asgi_app_info *socketify_add_asgi_http_handler(int ssl, uws_app_t *app, socketify_asgi_method_handler handler, void *user_data);
DLL_EXPORT void socketify_destroy_asgi_app_info(socksocketify_asgi_app_info *app);
DLL_EXPORT socksocketify_asgi_app_info* socketify_add_asgi_http_handler(int ssl, uws_app_t* app, socketify_asgi_method_handler handler, void* user_data);
DLL_EXPORT void socketify_destroy_asgi_app_info(socksocketify_asgi_app_info* app);
DLL_EXPORT void socketify_res_cork_write(int ssl, uws_res_t *response, const char *data, size_t length);
DLL_EXPORT void socketify_res_cork_end(int ssl, uws_res_t *response, const char *data, size_t length, bool close_connection);
DLL_EXPORT void socketify_res_cork_write(int ssl, uws_res_t *response, const char* data, size_t length);
DLL_EXPORT void socketify_res_cork_end(int ssl, uws_res_t *response, const char* data, size_t length, bool close_connection);
DLL_EXPORT socksocketify_asgi_ws_app_info* socketify_add_asgi_ws_handler(int ssl, uws_app_t* app, uws_socket_behavior_t behavior, socketify_asgi_ws_method_handler handler, void* user_data);
DLL_EXPORT void socketify_destroy_asgi_ws_app_info(socksocketify_asgi_ws_app_info* app);
DLL_EXPORT void socketify_ws_cork_send(int ssl, uws_websocket_t *ws, const char* data, size_t length, uws_opcode_t opcode);
DLL_EXPORT void socketify_ws_cork_send_with_options(int ssl, uws_websocket_t *ws, const char* data, size_t length, uws_opcode_t opcode, bool compress, bool fin);
DLL_EXPORT void socketify_res_send_int_code(int ssl, uws_res_t *res, const char* content_data, size_t content_data_size, int code, const char *content_type, size_t content_type_size, bool close_connection);
DLL_EXPORT void socketify_res_send(int ssl, uws_res_t *res, const char *content_data, size_t content_data_size, const char *status_code, size_t status_code_size, const char *content_type, size_t content_type_size, bool close_connection);
DLL_EXPORT void socketify_res_cork_send_int_code(int ssl, uws_res_t *res, const char* content_data, size_t content_data_size, int code, const char *content_type, size_t content_type_size, bool close_connection);
DLL_EXPORT void socketify_res_cork_send(int ssl, uws_res_t *res, const char *content_data, size_t content_data_size, const char *status_code, size_t status_code_size, const char *content_type, size_t content_type_size, bool close_connection);
DLL_EXPORT socketify_asgi_ws_app_info *socketify_add_asgi_ws_handler(int ssl, uws_app_t *app, uws_socket_behavior_t behavior, socketify_asgi_ws_method_handler handler, void *user_data);
DLL_EXPORT void socketify_destroy_asgi_ws_app_info(socketify_asgi_ws_app_info *app);
DLL_EXPORT void socketify_ws_cork_send(int ssl, uws_websocket_t *ws, const char *data, size_t length, uws_opcode_t opcode);
DLL_EXPORT void socketify_ws_cork_send_with_options(int ssl, uws_websocket_t *ws, const char *data, size_t length, uws_opcode_t opcode, bool compress, bool fin);
DLL_EXPORT void socketify_res_send_int_code(int ssl, uws_res_t *res, const char *content_data, size_t content_data_size, int code, const char *content_type, size_t content_type_size, bool close_connection);
DLL_EXPORT void socketify_res_send(int ssl, uws_res_t *res, const char *content_data, size_t content_data_size, const char *status_code, size_t status_code_size, const char *content_type, size_t content_type_size, bool close_connection);
DLL_EXPORT void socketify_res_cork_send_int_code(int ssl, uws_res_t *res, const char *content_data, size_t content_data_size, int code, const char *content_type, size_t content_type_size, bool close_connection);
DLL_EXPORT void socketify_res_cork_send(int ssl, uws_res_t *res, const char *content_data, size_t content_data_size, const char *status_code, size_t status_code_size, const char *content_type, size_t content_type_size, bool close_connection);
#endif
#ifdef __cplusplus
}

Wyświetl plik

@ -590,29 +590,6 @@ class RequestTask:
__iter__ = __await__ # make compatible with 'yield from'.
# def create_task_with_factory(task_factory_max_items=100_000):
# items = []
# for _ in range(0, task_factory_max_items):
# task = RequestTask(None, None, None, True)
# if task._source_traceback:
# del task._source_traceback[-1]
# items.append(task)
# def factory(loop, coro, default_done_callback=None):
# if len(items) == 0:
# return create_task(loop, coro, default_done_callback)
# task = items.pop()
# def done(f):
# if default_done_callback is not None:
# default_done_callback(f)
# items.append(f)
# task._reuse(coro, loop, done)
# return task
# return factory
async def factory_task_wrapper(task, dispose):
try:
await task

@ -1 +1 @@
Subproject commit 216c8b9ea20ec8719175b136cf86cb51b316382d
Subproject commit 623ee82841d32f85e54873135637e9a5ddf15618

Wyświetl plik

@ -221,9 +221,11 @@ def wsgi_corked_response_start_handler(res, user_data):
data_response.on_data(data_response, res)
@ffi.callback("void(int, uws_res_t*, socketify_asgi_data request, void*, bool*)")
def wsgi(ssl, response, info, user_data, aborted):
@ffi.callback("void(int, uws_res_t*, socketify_asgi_data request, void*)")
def wsgi(ssl, response, info, user_data):
app = ffi.from_handle(user_data)
# reusing the dict is slower than cloning because we need to clear HTTP headers
environ = dict(app.BASIC_ENVIRON)
@ -355,16 +357,19 @@ def wsgi(ssl, response, info, user_data, aborted):
return write
failed_chunks = None
last_offset = -1
data_retry = None
# check for body
if bool(info.has_content):
WSGI_INPUT = BytesIO()
environ["wsgi.input"] = WSGIBody(WSGI_INPUT)
def on_data(data_response, response):
nonlocal failed_chunks, last_offset, data_retry
last_offset = -1
data_retry = None
failed_chunks = None
if data_response.aborted:
return
@ -372,15 +377,18 @@ def wsgi(ssl, response, info, user_data, aborted):
data_response.environ["CONTENT_LENGTH"] = str(
data_response.buffer.getbuffer().nbytes
)
if data_response.id is not None:
data_response.app._data_refs.pop(data_response.id, None)
app_iter = data_response.app.wsgi(
data_response.environ, data_response.start_response
)
try:
for data in app_iter:
if data:
if not headers_written:
write_headers(headers_set)
content_length = ffi.cast("uintmax_t", content_length)
if is_chunked:
if isinstance(data, bytes):
@ -434,8 +442,6 @@ def wsgi(ssl, response, info, user_data, aborted):
ssl,
response
)
data_response = WSGIDataResponse(
app, environ, start_response, WSGI_INPUT, on_data
)
@ -445,6 +451,9 @@ def wsgi(ssl, response, info, user_data, aborted):
lib.uws_res_on_aborted(ssl, response, wsgi_on_data_ref_abort_handler, data_response._ptr)
lib.uws_res_on_data(ssl, response, wsgi_on_data_handler, data_response._ptr)
else:
failed_chunks = None
last_offset = -1
data_retry = None
environ["wsgi.input"] = None
app_iter = app.wsgi(environ, start_response)
result = None
@ -509,7 +518,6 @@ def wsgi(ssl, response, info, user_data, aborted):
)
def is_asgi(module):
return (
hasattr(module, "__call__") and len(inspect.signature(module).parameters) == 3