FastCGI: make it work at least in theory

This commit is contained in:
Přemysl Eric Janouch 2018-10-17 02:57:08 +02:00
parent 272145ace2
commit 83363e6383
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 75 additions and 29 deletions

View File

@ -123,18 +123,32 @@ struct fcgi_request
void *handler_data; ///< Handler data void *handler_data; ///< Handler data
}; };
/// Handles a single FastCGI connection, de/multiplexing requests and responses
struct fcgi_muxer struct fcgi_muxer
{ {
struct fcgi_parser parser; ///< FastCGI message parser struct fcgi_parser parser; ///< FastCGI message parser
uint32_t active_requests; ///< The number of active requests
bool in_shutdown; ///< Rejecting new requests
// TODO: bool quitting; that causes us to reject all requests? // Virtual method callbacks:
/// Write data to the underlying transport
void (*write_cb) (struct fcgi_muxer *, const void *data, size_t len); void (*write_cb) (struct fcgi_muxer *, const void *data, size_t len);
/// Close the underlying transport
// TODO: consider half-close and the subsequent handling
void (*close_cb) (struct fcgi_muxer *); void (*close_cb) (struct fcgi_muxer *);
void *(*request_start_cb) (struct fcgi_muxer *, struct fcgi_request *); /// Start processing a request. Return false if no further action is
void (*request_push_cb) (void *handler_data, const void *data, size_t len); /// to be done and the request should be finished.
void (*request_destroy_cb) (void *handler_data); bool (*request_start_cb) (struct fcgi_muxer *, struct fcgi_request *);
/// Handle incoming data. "len == 0" means EOF.
void (*request_push_cb)
(struct fcgi_request *, const void *data, size_t len);
/// Destroy the handler's data stored in the request object
void (*request_destroy_cb) (struct fcgi_request *);
/// Requests assigned to request IDs (may not be FCGI_NULL_REQUEST_ID) /// Requests assigned to request IDs (may not be FCGI_NULL_REQUEST_ID)
struct fcgi_request *requests[1 << 8]; struct fcgi_request *requests[1 << 8];
@ -177,22 +191,27 @@ fcgi_muxer_send_end_request (struct fcgi_muxer *self, uint16_t request_id,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void static struct fcgi_request *
fcgi_request_init (struct fcgi_request *self) fcgi_request_new (void)
{ {
memset (self, 0, sizeof *self); struct fcgi_request *self = xcalloc (1, sizeof *self);
self->headers = str_map_make (free); self->headers = str_map_make (free);
self->hdr_parser = fcgi_nv_parser_make (); self->hdr_parser = fcgi_nv_parser_make ();
self->hdr_parser.output = &self->headers; self->hdr_parser.output = &self->headers;
return self;
} }
static void static void
fcgi_request_free (struct fcgi_request *self) fcgi_request_destroy (struct fcgi_request *self)
{ {
// TODO: consider the case where it hasn't been started yet
self->muxer->request_destroy_cb (self);
str_map_free (&self->headers); str_map_free (&self->headers);
fcgi_nv_parser_free (&self->hdr_parser); fcgi_nv_parser_free (&self->hdr_parser);
free (self);
} }
static void static void
@ -211,7 +230,7 @@ fcgi_request_push_params
{ {
// TODO: probably check the state of the header parser // TODO: probably check the state of the header parser
// TODO: request_start() can return false, end the request here? // TODO: request_start() can return false, end the request here?
self->handler_data = self->muxer->request_start_cb (self->muxer, self); (void) self->muxer->request_start_cb (self->muxer, self);
self->state = FCGI_REQUEST_STDIN; self->state = FCGI_REQUEST_STDIN;
} }
} }
@ -226,7 +245,7 @@ fcgi_request_push_stdin
return; return;
} }
self->muxer->request_push_cb (self->handler_data, data, len); self->muxer->request_push_cb (self, data, len);
} }
static void static void
@ -266,7 +285,21 @@ fcgi_request_write (struct fcgi_request *self, const void *data, size_t len)
static void static void
fcgi_request_finish (struct fcgi_request *self) fcgi_request_finish (struct fcgi_request *self)
{ {
// TODO: flush(), end_request(), delete self, muxer->request_destroy_cb()? fcgi_request_flush (self);
fcgi_muxer_send (self->muxer, FCGI_STDOUT, self->request_id, NULL, 0);
fcgi_muxer_send_end_request (self->muxer, self->request_id,
0 /* TODO app_status, although ignored */,
FCGI_REQUEST_COMPLETE /* TODO protocol_status, may be different */);
if (!(self->flags & FCGI_KEEP_CONN))
{
// TODO: tear down (shut down) the connection
}
self->muxer->active_requests--;
self->muxer->requests[self->request_id] = NULL;
fcgi_request_destroy (self);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -354,21 +387,21 @@ fcgi_muxer_on_begin_request
return; return;
} }
// TODO: also send OVERLOADED when shutting down? if (parser->request_id >= N_ELEMENTS (self->requests)
if (parser->request_id >= N_ELEMENTS (self->requests)) || self->in_shutdown)
{ {
fcgi_muxer_send_end_request (self, fcgi_muxer_send_end_request (self,
parser->request_id, 0, FCGI_OVERLOADED); parser->request_id, 0, FCGI_OVERLOADED);
return; return;
} }
request = xcalloc (1, sizeof *request); request = fcgi_request_new ();
fcgi_request_init (request);
request->muxer = self; request->muxer = self;
request->request_id = parser->request_id; request->request_id = parser->request_id;
request->flags = flags; request->flags = flags;
self->requests[parser->request_id] = request; self->requests[parser->request_id] = request;
self->active_requests++;
} }
static void static void
@ -464,6 +497,17 @@ fcgi_muxer_init (struct fcgi_muxer *self)
static void static void
fcgi_muxer_free (struct fcgi_muxer *self) fcgi_muxer_free (struct fcgi_muxer *self)
{ {
for (size_t i = 0; i < N_ELEMENTS (self->requests); i++)
{
if (!self->active_requests)
break;
if (self->requests[i])
{
fcgi_request_destroy (self->requests[i]);
self->active_requests--;
}
}
fcgi_parser_free (&self->parser); fcgi_parser_free (&self->parser);
} }
@ -1977,33 +2021,35 @@ client_fcgi_request_close_cb (struct request *req)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void * static bool
client_fcgi_request_start client_fcgi_request_start
(struct fcgi_muxer *mux, struct fcgi_request *fcgi_request) (struct fcgi_muxer *mux, struct fcgi_request *fcgi_request)
{ {
FIND_CONTAINER (self, mux, struct client_fcgi, muxer); FIND_CONTAINER (self, mux, struct client_fcgi, muxer);
// TODO: what if the request is aborted by ; struct client_fcgi_request *request =
struct client_fcgi_request *request = xcalloc (1, sizeof *request); fcgi_request->handler_data = xcalloc (1, sizeof *request);
request->fcgi_request = fcgi_request; request->fcgi_request = fcgi_request;
request_init (&request->request); request_init (&request->request);
request->request.ctx = self->client.ctx; request->request.ctx = self->client.ctx;
request->request.write_cb = client_fcgi_request_write_cb; request->request.write_cb = client_fcgi_request_write_cb;
request->request.close_cb = client_fcgi_request_close_cb; request->request.close_cb = client_fcgi_request_close_cb;
return request;
return request_start (&request->request, &fcgi_request->headers);
} }
static void static void
client_fcgi_request_push (void *handler_data, const void *data, size_t len) client_fcgi_request_push
(struct fcgi_request *req, const void *data, size_t len)
{ {
struct client_fcgi_request *request = handler_data; struct client_fcgi_request *request = req->handler_data;
request_push (&request->request, data, len); request_push (&request->request, data, len);
} }
static void static void
client_fcgi_request_destroy (void *handler_data) client_fcgi_request_destroy (struct fcgi_request *req)
{ {
struct client_fcgi_request *request = handler_data; struct client_fcgi_request *request = req->handler_data;
request_free (&request->request); request_free (&request->request);
free (request); free (request);
} }
@ -2031,7 +2077,7 @@ client_fcgi_close_cb (struct fcgi_muxer *mux)
static bool static bool
client_fcgi_push (struct client *client, const void *data, size_t len) client_fcgi_push (struct client *client, const void *data, size_t len)
{ {
struct client_fcgi *self = (struct client_fcgi *) client; FIND_CONTAINER (self, client, struct client_fcgi, client);
fcgi_muxer_push (&self->muxer, data, len); fcgi_muxer_push (&self->muxer, data, len);
return true; return true;
} }
@ -2039,17 +2085,17 @@ client_fcgi_push (struct client *client, const void *data, size_t len)
static void static void
client_fcgi_shutdown (struct client *client) client_fcgi_shutdown (struct client *client)
{ {
struct client_fcgi *self = (struct client_fcgi *) client; FIND_CONTAINER (self, client, struct client_fcgi, client);
self->muxer.in_shutdown = true;
// TODO: respond with FCGI_END_REQUEST: FCGI_REQUEST_COMPLETE to everything, // TODO: respond with FCGI_END_REQUEST: FCGI_REQUEST_COMPLETE to everything?
// and start sending out FCGI_OVERLOADED to all incoming requests. The // The FastCGI specification isn't very clear about what we should do.
// FastCGI specification isn't very clear about what we should do.
} }
static void static void
client_fcgi_finalize (struct client *client) client_fcgi_finalize (struct client *client)
{ {
struct client_fcgi *self = (struct client_fcgi *) client; FIND_CONTAINER (self, client, struct client_fcgi, client);
fcgi_muxer_free (&self->muxer); fcgi_muxer_free (&self->muxer);
} }