mirror of
https://github.com/jamesroberts/fastwsgi.git
synced 2025-12-19 05:09:38 -06:00
Added "Date" field into response headers (#30)
* Added "Date" field into response headers * Added multi process running (fork process)
This commit is contained in:
85
fastwsgi.py
85
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()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "common.h"
|
||||
#include "llhttp.h"
|
||||
#include <time.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user