diff --git a/fastwsgi.py b/fastwsgi.py index a909023..12a4a4d 100644 --- a/fastwsgi.py +++ b/fastwsgi.py @@ -29,13 +29,17 @@ class _Server(): self.max_chunk_size = None # def value: 256 KiB self.read_buffer_size = None # def value: 64 KiB self.nowait = 0 + self.num_workers = 1 + self.worker_list = [ ] - def init(self, app, host = None, port = None, backlog = None, loglevel = None): + def init(self, app, host = None, port = None, loglevel = None, workers = None): self.app = app self.host = host if host else self.host self.port = port if port else self.port - self.backlog = backlog if backlog else self.backlog self.loglevel = loglevel if loglevel is not None else self.loglevel + self.num_workers = workers if workers is not None else self.num_workers + if self.num_workers > 1: + return 0 return _fastwsgi.init_server(self) def set_allow_keepalive(self, value): @@ -44,7 +48,11 @@ class _Server(): def run(self): if self.nowait: + if self.num_workers > 1: + raise Exception('Incorrect server options') return _fastwsgi.run_nowait(self) + if self.num_workers > 1: + return self.multi_run() ret = _fastwsgi.run_server(self) self.close() return ret @@ -52,35 +60,34 @@ class _Server(): def close(self): return _fastwsgi.close_server(self) + def multi_run(self, num_workers = None): + if num_workers is not None: + self.num_workers = num_workers + for _ in range(self.num_workers): + pid = os.fork() + if pid > 0: + self.worker_list.append(pid) + print(f"Worker process added with PID: {pid}") + continue + try: + _fastwsgi.init_server(self) + _fastwsgi.run_server(self) + except KeyboardInterrupt: + pass + sys.exit(0) + try: + for _ in range(self.num_workers): + os.wait() + except KeyboardInterrupt: + print("\n" + "Stopping all workers") + for worker in self.worker_list: + os.kill(worker, signal.SIGINT) + return 0 + server = _Server() # ------------------------------------------------------------------------------------- -NUM_WORKERS = 4 - -def run_multi_process_server(app): - workers = [] - for _ in range(NUM_WORKERS): - pid = os.fork() - if pid > 0: - workers.append(pid) - print(f"Worker process added with PID: {pid}") - else: - try: - server.init(app) - server.run() - except KeyboardInterrupt: - sys.exit(0) - - try: - for _ in range(NUM_WORKERS): - os.wait() - except KeyboardInterrupt: - print("\nStopping all workers") - for worker in workers: - os.kill(worker, signal.SIGINT) - - def import_from_string(import_str): module_str, _, attrs_str = import_str.partition(":") if not module_str or not attrs_str: @@ -103,12 +110,6 @@ def import_from_string(import_str): return module - -def print_server_details(host, port): - print(f"\n==== FastWSGI ==== ") - print(f"Host: {host}\nPort: {port}") - print("==================\n") - # ------------------------------------------------------------------------------------- @click.command() @@ -131,17 +132,15 @@ def run_from_cli(host, port, wsgi_app_import_string, loglevel): print(f"Error importing WSGI app: {e}") sys.exit(1) - print_server_details(host, port) - server.init(wsgi_app, host, port, loglevel = loglevel) - print(f"Server listening at http://{host}:{port}") + server.init(wsgi_app, host, port, loglevel) + print(f"FastWSGI server listening at http://{server.host}:{server.port}") server.run() # ------------------------------------------------------------------------------------- -def run(wsgi_app, host = server.host, port = server.port, backlog = server.backlog, loglevel = server.loglevel): - print_server_details(host, port) - print(f"Running on PID:", os.getpid()) - server.init(wsgi_app, host, port, backlog, loglevel) - print(f"Server listening at http://{host}:{port}") - server.run() - # run_multi_process_server(wsgi_app) +def run(wsgi_app, host = None, port = None, loglevel = None, workers = None): + print("FastWSGI server running on PID:", os.getpid()) + server.init(wsgi_app, host, port, loglevel, workers) + addon = " multiple workers" if server.num_workers > 1 else "" + print(f"FastWSGI server{addon} listening at http://{server.host}:{server.port}") + server.run() diff --git a/fastwsgi/common.c b/fastwsgi/common.c index 809e354..db2d0a0 100644 --- a/fastwsgi/common.c +++ b/fastwsgi/common.c @@ -1,5 +1,6 @@ #include "common.h" #include "llhttp.h" +#include void logrepr(int level, PyObject* obj) { @@ -63,3 +64,33 @@ const char * get_obj_attr_str(PyObject * obj, const char * name) } return PyUnicode_AsUTF8(attr); } + +static const char weekDays[7][4] = { "Sun", "Mon", "Tue", "Wen", "Thu", "Fri", "Sat" }; +static const char monthList[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +time_t g_actual_time = 0; +char g_actual_asctime[32] = { 0 }; +int g_actual_asctime_len = 0; + +int get_asctime(char ** asc_time) +{ + time_t curr_time = time(NULL); + if (curr_time == g_actual_time) { + *asc_time = g_actual_asctime; + return g_actual_asctime_len; + } + struct tm * tv = gmtime(&curr_time); + char buf[64]; + int len = sprintf(buf, "%s, %d %s %04d %02d:%02d:%02d GMT", + weekDays[tv->tm_wday], tv->tm_mday, monthList[tv->tm_mon], + 1900 + tv->tm_year, tv->tm_hour, tv->tm_min, tv->tm_sec); + if (len > 0 && len < 32) { + g_actual_time = curr_time; + g_actual_asctime_len = len; + memcpy(g_actual_asctime, buf, 32); + *asc_time = g_actual_asctime; + return len; + } + *asc_time = ""; + return 0; +} diff --git a/fastwsgi/common.h b/fastwsgi/common.h index cab9e2c..d748202 100644 --- a/fastwsgi/common.h +++ b/fastwsgi/common.h @@ -54,4 +54,6 @@ const char * get_http_status_name(int status); int64_t get_obj_attr_int(PyObject * obj, const char * name); const char * get_obj_attr_str(PyObject * obj, const char * name); +int get_asctime(char ** asc_time); + #endif diff --git a/fastwsgi/request.c b/fastwsgi/request.c index e1a6956..ccb2756 100644 --- a/fastwsgi/request.c +++ b/fastwsgi/request.c @@ -592,6 +592,7 @@ int build_response(client_t * client, int flags, int status, const void * header PyObject** body = client->response.body; StartResponse * response = NULL; int64_t body_size = _body_size; + int resp_date_present = 0; if (flags & RF_HEADERS_PYLIST) { response = (StartResponse *)headers; @@ -635,6 +636,10 @@ int build_response(client_t * client, int flags, int status, const void * header if (strcasecmp(key, "Connection") == 0) continue; // skip "Connection" header + if (key_len == 4) + if (strcasecmp(key, "Date") == 0) + resp_date_present = 1; + size_t value_len = 0; const char * value = PyUnicode_AsUTF8AndSize(PyTuple_GET_ITEM(tuple, 1), &value_len); @@ -650,6 +655,14 @@ int build_response(client_t * client, int flags, int status, const void * header xbuf_add_str(head, (const char *)headers); } + if (!resp_date_present) { + char * date_str; + int date_len = get_asctime(&date_str); + xbuf_add(head, "Date: ", 6); + xbuf_add(head, date_str, date_len); + xbuf_add(head, "\r\n", 2); + } + if ((flags & RF_SET_KEEP_ALIVE) != 0 && client->srv->allow_keepalive) { xbuf_add_str(head, "Connection: keep-alive\r\n"); } else {