From ee8031687b65ac7a9f0cb0e9264f75bd389a7c63 Mon Sep 17 00:00:00 2001 From: Andrei Vasiliu Date: Sun, 21 May 2023 16:37:51 +0300 Subject: [PATCH] Improved documentation comments for nxt_unit.h --- src/nxt_unit.h | 141 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 120 insertions(+), 21 deletions(-) diff --git a/src/nxt_unit.h b/src/nxt_unit.h index 35f9fa551..1bec10941 100644 --- a/src/nxt_unit.h +++ b/src/nxt_unit.h @@ -40,7 +40,7 @@ enum { /* * Mostly opaque structure with library state. * - * Only user defined 'data' pointer exposed here. The rest is unit + * Only the user defined 'data' pointer is exposed here. The rest is unit * implementation specific and hidden. */ struct nxt_unit_s { @@ -51,8 +51,8 @@ struct nxt_unit_s { * Thread context. * * First (main) context is provided 'for free'. To receive and process - * requests in other thread, one need to allocate context and use it - * further in this thread. + * requests in other threads, one needs to allocate a new context and use it + * further in that thread. */ struct nxt_unit_ctx_s { void *data; /* User context-specific data. */ @@ -72,7 +72,7 @@ struct nxt_unit_port_id_s { }; /* - * unit provides port storage which is able to store and find the following + * Unit provides port storage which is able to store and find the following * data structures. */ struct nxt_unit_port_s { @@ -114,22 +114,46 @@ struct nxt_unit_request_info_s { /* - * Set of application-specific callbacks. Application may leave all optional - * callbacks as NULL. + * Set of application-specific callbacks. The application may leave all + * optional callbacks as NULL. */ struct nxt_unit_callbacks_s { /* - * Process request. Unlike all other callback, this callback - * need to be defined by application. + * Process request. Unlike all other callbacks, this callback is required + * and needs to be defined by the application. + * + * This callback will be called when all request header and body data is + * available. If the data_handler callback is not NULL, then the + * request_handler callback may also sometimes be called without body data. */ void (*request_handler)(nxt_unit_request_info_t *req); + /* + * Data handler. Optional. + * + * If this is NULL, then the request_handler() callback will only be called + * once all the request body data has been received. + * + * If this is not NULL, then the request workflow is changed such that the + * request_handler() callback may sometimes be called with just the request + * header data, before the body content data is available. + * + * The data_handler() callback will be called only if in request_handler() + * the available data was less than the request's content_length and the + * nxt_unit_request_done() function was not yet called. + * + * This callback will be called at most once, when all data becomes + * available. + */ void (*data_handler)(nxt_unit_request_info_t *req); - /* Process websocket frame. */ + /* Process websocket frame. Optional. */ void (*websocket_handler)(nxt_unit_websocket_frame_t *ws); - /* Connection closed. */ + /* + * Connection closed. Optional. Called only for websockets that were closed + * or requests that were aborted. + */ void (*close_handler)(nxt_unit_request_info_t *req); /* Add new Unit port to communicate with process pid. Optional. */ @@ -201,15 +225,15 @@ struct nxt_unit_read_info_s { nxt_unit_ctx_t *nxt_unit_init(nxt_unit_init_t *); /* - * Main function useful in case when application does not have it's own - * event loop. nxt_unit_run() starts infinite message wait and process loop. + * Main function, useful in case the application does not have its own event + * loop. nxt_unit_run() starts an infinite message wait and process loop. * * for (;;) { * app_lib->port_recv(...); * nxt_unit_process_msg(...); * } * - * The normally function returns when QUIT message received from Unit. + * The function returns normally when a QUIT message is received from Unit. */ int nxt_unit_run(nxt_unit_ctx_t *); @@ -220,10 +244,10 @@ int nxt_unit_run_shared(nxt_unit_ctx_t *ctx); nxt_unit_request_info_t *nxt_unit_dequeue_request(nxt_unit_ctx_t *ctx); /* - * Receive and process one message, invoke configured callbacks. + * Receive and process one message, and invoke configured callbacks. * - * If application implements it's own event loop, each datagram received - * from port socket should be initially processed by unit. This function + * If the application implements its own event loop, each datagram received + * from the port socket should be initially processed by unit. This function * may invoke other application-defined callback for message processing. */ int nxt_unit_run_once(nxt_unit_ctx_t *ctx); @@ -234,8 +258,11 @@ int nxt_unit_process_port_msg(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port); void nxt_unit_done(nxt_unit_ctx_t *); /* - * Allocate and initialize new execution context with new listen port to - * process requests in other thread. + * Allocate and initialize a new execution context with a new listen port to + * process requests in another thread. + * + * The new context must be deallocated with nxt_unit_done before the old context + * is deallocated. */ nxt_unit_ctx_t *nxt_unit_ctx_alloc(nxt_unit_ctx_t *, void *); @@ -253,7 +280,7 @@ void nxt_unit_split_host(char *host_start, uint32_t host_length, void nxt_unit_request_group_dup_fields(nxt_unit_request_info_t *req); /* - * Allocate response structure capable to store limited numer of fields. + * Allocate response structure capable of storing a limited numer of fields. * The structure may be accessed directly via req->response pointer or * filled step-by-step using functions add_field and add_content. */ @@ -273,13 +300,27 @@ int nxt_unit_response_add_content(nxt_unit_request_info_t *req, const void* src, uint32_t size); /* - * Send prepared response to Unit server. Response structure destroyed during - * this call. + * Send the prepared response to the Unit server. The Response structure is + * destroyed during this call. + * + * Asynchronously, the Unit server will attempt to send the data to the client + * as soon as it can, using the "Transfer-Encoding: chunked" method, and may + * combine chunks for slow-reading clients. The connection will then remain + * open, and more chunks can be scheduled using using nxt_unit_buf_send() and/or + * nxt_unit_write_response(), or the connection can be closed with + * nxt_unit_request_done(). */ int nxt_unit_response_send(nxt_unit_request_info_t *req); int nxt_unit_response_is_sent(nxt_unit_request_info_t *req); +/* + * Allocate a buffer for an additional response chunk to be sent. Multiple + * buffers may be allocated at the same time, and they may be sent or dropped + * in any order. + * + * See nxt_unit_buf_max() for the maximum size that may be requested. + */ nxt_unit_buf_t *nxt_unit_response_buf_alloc(nxt_unit_request_info_t *req, uint32_t size); @@ -291,31 +332,89 @@ int nxt_unit_response_is_websocket(nxt_unit_request_info_t *req); nxt_unit_request_info_t *nxt_unit_get_request_info_from_data(void *data); +/* + * Send and deallocate a response data chunk. The data is immediately sent to + * the client as a chunk using the "Transfer-Encoding: chunked" method. + * + * If the initial response was not yet sent with nxt_unit_response_send(), this + * function will automatically call it. + */ int nxt_unit_buf_send(nxt_unit_buf_t *buf); +/* + * Deallocate a response data chunk without sending it. + */ void nxt_unit_buf_free(nxt_unit_buf_t *buf); nxt_unit_buf_t *nxt_unit_buf_next(nxt_unit_buf_t *buf); +/* + * The maximum size that can be requested with nxt_unit_response_buf_alloc(). + */ uint32_t nxt_unit_buf_max(void); +/* + * The minimum size that will be allocated by nxt_unit_response_buf_alloc(). + */ uint32_t nxt_unit_buf_min(void); +/* + * Schedule a response to be sent to the client. This will repeatedly call + * nxt_unit_response_write_nb with a min_size equal to the size, which will + * block until the Unit server has received the entire data. + * + * The Unit server will buffer the response data, and will attempt to send it to + * the client asynchronously, as soon as it can. + */ int nxt_unit_response_write(nxt_unit_request_info_t *req, const void *start, size_t size); +/* + * Schedule a response to be sent to the client, blocking until at least + * min_size bytes have been received by the Unit server. + */ ssize_t nxt_unit_response_write_nb(nxt_unit_request_info_t *req, const void *start, size_t size, size_t min_size); +/* + * Schedule a response to be sent to the client, using a user-provided callback + * that will be called repeatedly with buffers to write to. This function will + * return once the Unit server has received all the data. + */ int nxt_unit_response_write_cb(nxt_unit_request_info_t *req, nxt_unit_read_info_t *read_info); +/* + * Read bytes from the request body. This is non-blocking. This function will + * return 0 when no more data can be received from the Unit server in the + * current request handler callback. + * + * If the data_handler callback is NULL, then the Unit server will already have + * the entire request body data buffered, and this function can receive the + * whole request. + * + * If the data_handler callback is not NULL, then: + * + * 1. Inside request_handler(), this function may sometimes return 0 before the + * amount of received data reaches the request's content_length. In this + * case, Unit will call the data_handler() callback once the entire request + * body is available. + * 2. Inside data_handler(), the whole request body data is guaranteed to be + * buffered, and this function can receive the whole request. + */ ssize_t nxt_unit_request_read(nxt_unit_request_info_t *req, void *dst, size_t size); +/* Read bytes until (and including) the next "\n" byte. */ ssize_t nxt_unit_request_readline_size(nxt_unit_request_info_t *req, size_t max_size); +/* + * Close the request. This function must be called, or the request will hang. + * + * With NXT_UNIT_ERROR, if no parts of a response have been sent yet, Unit will + * send a default "503 Service Unavailable" response. + */ void nxt_unit_request_done(nxt_unit_request_info_t *req, int rc);