From 3f98f85f54b781674d9a89d0acb387fd960f9ef5 Mon Sep 17 00:00:00 2001 From: Mark Reed Date: Fri, 22 Mar 2024 12:05:26 -0700 Subject: [PATCH 1/4] Starting dynamic caching --- dotests.py | 1 + src/mrhttp/internals/protocol.c | 5 ++++- tests/s_bench.py | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dotests.py b/dotests.py index e6bb305..17486e8 100644 --- a/dotests.py +++ b/dotests.py @@ -114,6 +114,7 @@ async def run_benchmarks(): print(" Pipelined") print (" Hello ", await run_wrk(loop, 'http://localhost:8080/',lua='tests/lua/pipeline.lua'), "Requests/second" ) + print (" Hello ", await run_wrk(loop, 'http://localhost:8080/',lua='tests/lua/pipeline.lua'), "Requests/second" ) print (" More hdrs ", await run_wrk(loop, 'http://localhost:8080/',options=more_headers,lua='tests/lua/pipeline.lua'), "Requests/second" ) print (" Sessions ", await run_wrk(loop, 'http://localhost:8080/s',lua='tests/lua/q-session.lua'), "Requests/second" ) print (" File Upload ", await run_wrk(loop, 'http://localhost:8080/upload',lua='tests/lua/q-upload.lua'), "Requests/second" ) diff --git a/src/mrhttp/internals/protocol.c b/src/mrhttp/internals/protocol.c index 379e432..682bf0b 100644 --- a/src/mrhttp/internals/protocol.c +++ b/src/mrhttp/internals/protocol.c @@ -541,7 +541,10 @@ Protocol* Protocol_handle_request(Protocol* self, Request* request, Route* r) { // If we have cached bytes if ( r->cached ) { - if(!protocol_write_response(self, request, r->cached)) goto error; + if ( PyBytes_Check( r->cached ) ) { + if(!protocol_write_response(self, request, r->cached)) goto error; + } + // Else dynamic cache } if(!(result = protocol_callPageHandler(self, r->func, request)) ) { diff --git a/tests/s_bench.py b/tests/s_bench.py index 63d1fbf..0a6b6c5 100755 --- a/tests/s_bench.py +++ b/tests/s_bench.py @@ -38,6 +38,9 @@ @app.route('/') def index(r): return 'Hello World!' +@app.route('/cached', options=['cache']) +def cached_index(r): + return 'Hello World!' @app.route('/print/{}') def pr(r,foo): From 597bedfd422186618f729674bdcd3bb30b365375 Mon Sep 17 00:00:00 2001 From: Mark Reed Date: Fri, 22 Mar 2024 13:11:26 -0700 Subject: [PATCH 2/4] Error if caching wrong type --- dotests.py | 6 ++-- src/mrhttp/app.py | 1 - src/mrhttp/internals/protocol.c | 7 ++-- src/mrhttp/internals/router.c | 13 +++++-- src/mrhttp/internals/router.h | 1 + tests/lua/pipeline.lua | 63 ++++++++++++++++----------------- tests/lua/q-cached.lua | 43 ++++++++++++++++++++++ tst.py | 6 ++-- 8 files changed, 95 insertions(+), 45 deletions(-) create mode 100755 tests/lua/q-cached.lua diff --git a/dotests.py b/dotests.py index 17486e8..c0215ff 100644 --- a/dotests.py +++ b/dotests.py @@ -113,13 +113,13 @@ async def run_benchmarks(): opts = ('-H','Cookie: mrsession=43709dd361cc443e976b05714581a7fb; foo=fdsfdasdfasdfdsfasdfsdfsdfasdfas; short=fazc;') print(" Pipelined") - print (" Hello ", await run_wrk(loop, 'http://localhost:8080/',lua='tests/lua/pipeline.lua'), "Requests/second" ) + print (" Hello (cached) ", await run_wrk(loop, 'http://localhost:8080/cached',lua='tests/lua/q-cached.lua'), "Requests/second" ) print (" Hello ", await run_wrk(loop, 'http://localhost:8080/',lua='tests/lua/pipeline.lua'), "Requests/second" ) print (" More hdrs ", await run_wrk(loop, 'http://localhost:8080/',options=more_headers,lua='tests/lua/pipeline.lua'), "Requests/second" ) print (" Sessions ", await run_wrk(loop, 'http://localhost:8080/s',lua='tests/lua/q-session.lua'), "Requests/second" ) print (" File Upload ", await run_wrk(loop, 'http://localhost:8080/upload',lua='tests/lua/q-upload.lua'), "Requests/second" ) - print (" mrpacker ", await run_wrk(loop, 'http://localhost:8080/mrpacker',lua='tests/lua/q-mrp.lua'), "Requests/second" ) - print (" Form ", await run_wrk(loop, 'http://localhost:8080/form',lua='tests/lua/q-form.lua'), "Requests/second" ) + #print (" mrpacker ", await run_wrk(loop, 'http://localhost:8080/mrpacker',lua='tests/lua/q-mrp.lua'), "Requests/second" ) + #print (" Form ", await run_wrk(loop, 'http://localhost:8080/form',lua='tests/lua/q-form.lua'), "Requests/second" ) if 1: print("") diff --git a/src/mrhttp/app.py b/src/mrhttp/app.py index 0007fad..456c939 100644 --- a/src/mrhttp/app.py +++ b/src/mrhttp/app.py @@ -145,7 +145,6 @@ def static_cached_timer(self): for item in self.static_cached_files: fn = item[1] if os.path.getmtime(fn) > self.static_cached_timestamp: - print("DELME timer updating cache of ",fn) with open(fn, 'rb') as f: b = f.read() self.router.update_cached_route( [item[0], b] ) diff --git a/src/mrhttp/internals/protocol.c b/src/mrhttp/internals/protocol.c index 682bf0b..620ddb0 100644 --- a/src/mrhttp/internals/protocol.c +++ b/src/mrhttp/internals/protocol.c @@ -539,12 +539,11 @@ Protocol* Protocol_handle_request(Protocol* self, Request* request, Route* r) { if ( self->request == request ) self->request = (Request*)MrhttpApp_get_request( self->app ); } + //if ( r->dyncache ) { // Lookup path in dict + //} // If we have cached bytes if ( r->cached ) { - if ( PyBytes_Check( r->cached ) ) { - if(!protocol_write_response(self, request, r->cached)) goto error; - } - // Else dynamic cache + if(!protocol_write_response(self, request, r->cached)) goto error; } if(!(result = protocol_callPageHandler(self, r->func, request)) ) { diff --git a/src/mrhttp/internals/router.c b/src/mrhttp/internals/router.c index 05dc136..eb44486 100644 --- a/src/mrhttp/internals/router.c +++ b/src/mrhttp/internals/router.c @@ -64,7 +64,9 @@ PyObject* Router_update_cached_route(Router* self, PyObject* item) { //DBG printf("request path len %d - %.*s\n", (int)request->path_len, (int)request->path_len, request->path); //DBG printf("route path %.*s \n", (int)r->len, r->path); if ( plen == r->len && !memcmp(r->path, p, plen) ) { + if ( r->cached ) { Py_DECREF(b); } r->cached = b; + Py_INCREF(b); Py_RETURN_NONE; } } @@ -103,9 +105,16 @@ PyObject *Router_setupRoutes (Router* self) { o = PyDict_GetItemString( r, "type" ); if (o) rte->mtype = PyLong_AsLong(o); rte->user_key = PyDict_GetItemString( r, "user_key" ); - rte->cached = PyDict_GetItemString( r, "cached" ); + PyObject *b = PyDict_GetItemString( r, "cached" ); + rte->cached = b; if (b) Py_INCREF(b); if ( Py_True == PyDict_GetItemString( r, "cache" ) ) { - rte->cached = PyObject_CallFunctionObjArgs(handler, r, NULL); + b = PyObject_CallFunctionObjArgs(handler, r, NULL); + rte->cached = b; Py_INCREF(b); + if ( !( PyBytes_Check(b) || PyUnicode_Check(b) ) ) { + printf(" ERROR - cached route must return a unicode or bytes object\n"); + printf(" path: "); PyObject_Print(PyDict_GetItemString(r,"path"),stdout,0); printf("\n"); + Py_DECREF(rte->cached); rte->cached = 0; + } } DBG printf(" path %.*s func ptr %p\n", (int)rte->len, rte->path, rte->func); diff --git a/src/mrhttp/internals/router.h b/src/mrhttp/internals/router.h index 25887f2..f857f8d 100644 --- a/src/mrhttp/internals/router.h +++ b/src/mrhttp/internals/router.h @@ -21,6 +21,7 @@ typedef struct { int max_byte_size; PyObject *cached; + PyObject *dyncache; PyObject *user_key; //char *user_key; //long user_key_len; diff --git a/tests/lua/pipeline.lua b/tests/lua/pipeline.lua index bc37741..2a2530b 100755 --- a/tests/lua/pipeline.lua +++ b/tests/lua/pipeline.lua @@ -2,38 +2,37 @@ init = function(args) local r = {} - r[1] = wrk.format(nil, "/") - r[2] = wrk.format(nil, "/") - r[3] = wrk.format(nil, "/") - r[4] = wrk.format(nil, "/") - r[5] = wrk.format(nil, "/") - r[6] = wrk.format(nil, "/") - r[7] = wrk.format(nil, "/") - r[8] = wrk.format(nil, "/") - r[9] = wrk.format(nil, "/") - r[10] = wrk.format(nil, "/") - r[11] = wrk.format(nil, "/") - r[12] = wrk.format(nil, "/") - r[13] = wrk.format(nil, "/") - r[14] = wrk.format(nil, "/") - r[15] = wrk.format(nil, "/") - r[16] = wrk.format(nil, "/") - r[17] = wrk.format(nil, "/") - r[18] = wrk.format(nil, "/") - r[19] = wrk.format(nil, "/") - r[20] = wrk.format(nil, "/") - r[21] = wrk.format(nil, "/") - r[22] = wrk.format(nil, "/") - r[23] = wrk.format(nil, "/") - r[24] = wrk.format(nil, "/") - r[25] = wrk.format(nil, "/") - r[26] = wrk.format(nil, "/") - r[27] = wrk.format(nil, "/") - r[28] = wrk.format(nil, "/") - r[29] = wrk.format(nil, "/") - r[30] = wrk.format(nil, "/") - r[31] = wrk.format(nil, "/") - r[32] = wrk.format(nil, "/") + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) + table.insert( r, wrk.format(nil, "/") ) req = table.concat(r) end diff --git a/tests/lua/q-cached.lua b/tests/lua/q-cached.lua new file mode 100755 index 0000000..95e3736 --- /dev/null +++ b/tests/lua/q-cached.lua @@ -0,0 +1,43 @@ +-- example script demonstrating HTTP pipelining + +init = function(args) + local r = {} + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + table.insert( r, wrk.format(nil, "/cached") ) + req = table.concat(r) +end + +request = function() + return req +end diff --git a/tst.py b/tst.py index 6c2cb56..c140b13 100755 --- a/tst.py +++ b/tst.py @@ -12,8 +12,8 @@ #app.c = asyncmrq.Client() #await app.c.connect(servers=[("127.0.0.1",7100)]) -#@app.route('/',options=['cache']) -@app.route('/') +#@app.route('/') +@app.route('/',options=['cache']) def index(r): return "hello world" @@ -35,7 +35,7 @@ def firstarg(r,a): try: - app.run(cores=1) + app.run(cores=4) except Exception as e: print("YAY",e) From 58217fa7bed865414b0c4d91dc718176872159bb Mon Sep 17 00:00:00 2001 From: Mark Reed Date: Fri, 22 Mar 2024 13:25:10 -0700 Subject: [PATCH 3/4] version 0.11 --- setup.py | 2 +- src/mrhttp/__init__.py | 2 +- src/mrhttp/internals/app.c | 4 ++-- src/mrhttp/internals/response.c | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index 52a76bc..1b2771a 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ setup( name="mrhttp", - version="0.10", + version="0.11", license='MIT', description='A python web framework written in C', long_description=open('README.md').read(), diff --git a/src/mrhttp/__init__.py b/src/mrhttp/__init__.py index 9f91411..09c5286 100644 --- a/src/mrhttp/__init__.py +++ b/src/mrhttp/__init__.py @@ -21,5 +21,5 @@ from .app import * from .internals import randint, escape, to64, from64, timesince -__version__=0.10 +__version__=0.11 diff --git a/src/mrhttp/internals/app.c b/src/mrhttp/internals/app.c index c5c0501..7d0c576 100644 --- a/src/mrhttp/internals/app.c +++ b/src/mrhttp/internals/app.c @@ -213,7 +213,7 @@ void MrhttpApp_setup_error_pages(MrhttpApp* self) { char *body = PyUnicode_AsUTF8AndSize( u, &l ); char *resp = malloc( l + 1024 ); - sprintf(resp, "HTTP/1.1 404 Not Found\r\nServer: MrHTTP/0.8\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %zu\r\n\r\n", l); + sprintf(resp, "HTTP/1.1 404 Not Found\r\nServer: MrHTTP/0.11\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %zu\r\n\r\n", l); char *p = resp + strlen(resp); memcpy(p, body, l); @@ -225,7 +225,7 @@ void MrhttpApp_setup_error_pages(MrhttpApp* self) { body = PyUnicode_AsUTF8AndSize( u, &l ); resp = malloc( l + 1024 ); - sprintf(resp, "HTTP/1.1 400 Bad Request\r\nServer: MrHTTP/0.8\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %zu\r\n\r\n", l); + sprintf(resp, "HTTP/1.1 400 Bad Request\r\nServer: MrHTTP/0.11\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %zu\r\n\r\n", l); p = resp + strlen(resp); memcpy(p, body, l); diff --git a/src/mrhttp/internals/response.c b/src/mrhttp/internals/response.c index 5413ecb..ece656a 100644 --- a/src/mrhttp/internals/response.c +++ b/src/mrhttp/internals/response.c @@ -36,7 +36,7 @@ void response_setupResponseBuffer(void) { // Also all 115 and 143s ( updateHeaders ) s = "HTTP/1.1 200 OK\r\n"; memcpy(p, s, strlen(s)); p += strlen(s); s = "Content-Length: 1 \r\n"; memcpy(p, s, strlen(s)); p += strlen(s); - s = "Server: MrHTTP/0.10\r\n"; memcpy(p, s, strlen(s)); p += strlen(s); + s = "Server: MrHTTP/0.11\r\n"; memcpy(p, s, strlen(s)); p += strlen(s); s = "Date: Thu, 05 Apr 2018 22:54:19 GMT\r\n"; memcpy(p, s, strlen(s)); p += strlen(s); s = "Content-Type: text/html; charset=utf-8\r\n\r\n"; memcpy(p, s, strlen(s)); p += strlen(s); DBG_RESP printf("Init resp buffer:\n%.*s", (int)(p-rbuf), rbuf); @@ -74,7 +74,7 @@ PyObject *response_updateDate(PyObject *date) { Py_ssize_t l; char *d = PyUnicode_AsUTF8AndSize( date, &l ); char *p = rbuf; - p += strlen("HTTP/1.1 200 OK\r\n") + strlen("Server: MrHTTP/0.10\r\n") + strlen("Content-Length: 1 \r\n"); + p += strlen("HTTP/1.1 200 OK\r\n") + strlen("Server: MrHTTP/0.11\r\n") + strlen("Content-Length: 1 \r\n"); p += 6; memcpy(p, d, l); Py_RETURN_NONE; @@ -234,10 +234,10 @@ PyObject *response_getErrorResponse(int code, char *reason, char *msg) { sprintf( body, "%d %s

%s

%s

", code, reason, reason, msg ); int blen = strlen(body); - sprintf(p, "HTTP/1.1 %d %s\r\nServer: MrHTTP/0.10\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %d\r\n", code, reason, blen); + sprintf(p, "HTTP/1.1 %d %s\r\nServer: MrHTTP/0.11\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %d\r\n", code, reason, blen); p += strlen(p); memcpy(p, - rbuf + strlen("HTTP/1.1 200 OK\r\n") + strlen("Server: MrHTTP/0.10\r\n") + strlen("Content-Length: 17 \r\n"), + rbuf + strlen("HTTP/1.1 200 OK\r\n") + strlen("Server: MrHTTP/0.11\r\n") + strlen("Content-Length: 17 \r\n"), strlen("Date: Thu, 05 Apr 2018 22:54:19 GMT\r\n")); p += strlen("Date: Thu, 05 Apr 2018 22:54:19 GMT\r\n"); From ffcf267b142518a60a1484b34537ea9e21bc9c99 Mon Sep 17 00:00:00 2001 From: Mark Reed Date: Fri, 22 Mar 2024 14:19:18 -0700 Subject: [PATCH 4/4] Fix mime type for cached --- src/mrhttp/internals/protocol.c | 2 ++ tst.py | 17 +++-------------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/mrhttp/internals/protocol.c b/src/mrhttp/internals/protocol.c index a917f3f..feb856f 100644 --- a/src/mrhttp/internals/protocol.c +++ b/src/mrhttp/internals/protocol.c @@ -541,7 +541,9 @@ Protocol* Protocol_handle_request(Protocol* self, Request* request, Route* r) { //} // If we have cached bytes if ( r->cached ) { + response_setMimeType(r->mtype); if(!protocol_write_response(self, request, r->cached)) goto error; + return self; } if(!(result = protocol_callPageHandler(self, r->func, request)) ) { diff --git a/tst.py b/tst.py index c140b13..5cb5746 100755 --- a/tst.py +++ b/tst.py @@ -12,30 +12,19 @@ #app.c = asyncmrq.Client() #await app.c.connect(servers=[("127.0.0.1",7100)]) -#@app.route('/') -@app.route('/',options=['cache']) +@app.route('/',_type='text',options=['cache']) +#@app.route('/',_type='text') def index(r): return "hello world" -@app.route('/123456789123456789') -async def long(r): - return "long" - @app.route('/json') def json(r): return mrjson.dumps({'message': 'Hello, world!'}) -@app.route('/mrp',_type="mrp") -def mrp(r): - return mrpacker.pack("hello") - -@app.route('/{}/tst') -def firstarg(r,a): - return a try: - app.run(cores=4) + app.run(cores=1) except Exception as e: print("YAY",e)