#ifndef HTTP_SERVER_PRIVATE_H #define HTTP_SERVER_PRIVATE_H #include "connection.h" #include "iostream-pump.h" #include "http-server.h" #include "llist.h" struct http_server_ostream; struct http_server_payload_handler; struct http_server_request; struct http_server_connection; /* * Defaults */ #define HTTP_SERVER_REQUEST_MAX_TARGET_LENGTH 4096 /* * Types */ enum http_server_request_state { /* New request; request header is still being parsed. */ HTTP_SERVER_REQUEST_STATE_NEW = 0, /* Queued request; callback to request handler executing. */ HTTP_SERVER_REQUEST_STATE_QUEUED, /* Reading request payload; request handler still needs to read more payload. */ HTTP_SERVER_REQUEST_STATE_PAYLOAD_IN, /* This request is being processed; request payload is fully read, but no response is yet submitted */ HTTP_SERVER_REQUEST_STATE_PROCESSING, /* A response is submitted for this request. If not all request payload was read by the handler, it is first skipped on the input. */ HTTP_SERVER_REQUEST_STATE_SUBMITTED_RESPONSE, /* Request is ready for response; a response is submitted and the request payload is fully read */ HTTP_SERVER_REQUEST_STATE_READY_TO_RESPOND, /* The response for the request is sent (apart from payload) */ HTTP_SERVER_REQUEST_STATE_SENT_RESPONSE, /* Sending response payload to client */ HTTP_SERVER_REQUEST_STATE_PAYLOAD_OUT, /* Request is finished; still lingering due to references */ HTTP_SERVER_REQUEST_STATE_FINISHED, /* Request is aborted; still lingering due to references */ HTTP_SERVER_REQUEST_STATE_ABORTED }; /* * Objects */ struct http_server_payload_handler { struct http_server_request *req; void (*switch_ioloop)(struct http_server_payload_handler *handler, struct ioloop *ioloop); void (*destroy)(struct http_server_payload_handler *handler); bool in_callback:1; }; struct http_server_response { struct http_server_request *request; struct event *event; unsigned int status; const char *reason; string_t *headers; ARRAY_TYPE(string) perm_headers; time_t date; ARRAY_TYPE(http_auth_challenge) auth_challenges; struct istream *payload_input; uoff_t payload_size, payload_offset; struct ostream *payload_output; struct http_server_ostream *payload_stream; http_server_tunnel_callback_t tunnel_callback; void *tunnel_context; bool have_hdr_connection:1; bool have_hdr_date:1; bool have_hdr_body_spec:1; bool payload_chunked:1; bool payload_finished:1; bool payload_corked:1; bool submitted:1; }; struct http_server_request { struct http_request req; pool_t pool; unsigned int refcount, immune_refcount; unsigned int id; int callback_refcount; struct event *event; uoff_t input_start_offset, output_start_offset; enum http_server_request_state state; struct http_server_request *prev, *next; struct http_server *server; struct http_server_connection *conn; struct istream *payload_input; struct http_server_response *response; void (*destroy_callback)(void *); void *destroy_context; bool payload_halted:1; bool sent_100_continue:1; bool destroy_pending:1; bool failed:1; bool connection_close:1; }; struct http_server_connection { struct connection conn; struct http_server *server; struct ioloop *ioloop, *ioloop_switching; struct event *event; unsigned int refcount; const struct http_server_callbacks *callbacks; void *context; struct timeout *to_input, *to_idle; struct ssl_iostream *ssl_iostream; struct http_request_parser *http_parser; struct http_server_request *request_queue_head, *request_queue_tail; unsigned int request_queue_count; struct istream *incoming_payload; struct http_server_payload_handler *payload_handler; struct io *io_resp_payload; char *disconnect_reason; struct http_server_stats stats; bool ssl:1; bool closed:1; bool close_indicated:1; bool input_broken:1; bool output_locked:1; bool output_halted:1; bool in_req_callback:1; /* performing request callback (busy) */ }; struct http_server_location { const char *path; struct http_server_resource *resource; }; struct http_server_resource { pool_t pool; struct http_server *server; struct event *event; http_server_resource_callback_t *callback; void *context; void (*destroy_callback)(void *); void *destroy_context; ARRAY(struct http_server_location *) locations; }; struct http_server { pool_t pool; struct http_server_settings set; struct ioloop *ioloop; struct event *event; struct ssl_iostream_context *ssl_ctx; struct connection_list *conn_list; ARRAY(struct http_server_resource *) resources; ARRAY(struct http_server_location *) locations; bool shutting_down:1; /* shutting down server */ }; /* * Response output stream */ struct ostream * http_server_ostream_create(struct http_server_response *resp, size_t max_buffer_size, bool blocking); bool http_server_ostream_get_size(struct http_server_ostream *hsostream, uoff_t *size_r); int http_server_ostream_continue(struct http_server_ostream *hsostream); void http_server_ostream_output_available( struct http_server_ostream *hsostream); void http_server_ostream_response_finished( struct http_server_ostream *hsostream); void http_server_ostream_response_destroyed( struct http_server_ostream *hsostream); struct ostream * http_server_ostream_get_output(struct http_server_ostream *hsostream); void http_server_ostream_set_error(struct http_server_ostream *hsostream, int stream_errno, const char *stream_error); /* * Response */ void http_server_response_request_free(struct http_server_response *resp); void http_server_response_request_destroy(struct http_server_response *resp); void http_server_response_request_abort(struct http_server_response *resp, const char *reason); void http_server_response_request_finished(struct http_server_response *resp); int http_server_response_send(struct http_server_response *resp); int http_server_response_send_more(struct http_server_response *resp); int http_server_response_finish_payload_out(struct http_server_response *resp); /* * Request */ static inline bool http_server_request_is_new(struct http_server_request *req) { return (req->state == HTTP_SERVER_REQUEST_STATE_NEW); } static inline bool http_server_request_version_equals(struct http_server_request *req, unsigned int major, unsigned int minor) { return (req->req.version_major == major && req->req.version_minor == minor); } const char *http_server_request_label(struct http_server_request *req); void http_server_request_update_event(struct http_server_request *req); struct http_server_request * http_server_request_new(struct http_server_connection *conn); void http_server_request_destroy(struct http_server_request **_req); void http_server_request_abort(struct http_server_request **_req, const char *reason) ATTR_NULL(2); void http_server_request_immune_ref(struct http_server_request *req); void http_server_request_immune_unref(struct http_server_request **_req); bool http_server_request_is_complete(struct http_server_request *req); void http_server_request_received(struct http_server_request *req); void http_server_request_callback(struct http_server_request *req); void http_server_request_halt_payload(struct http_server_request *req); void http_server_request_continue_payload(struct http_server_request *req); void http_server_request_submit_response(struct http_server_request *req); void http_server_request_ready_to_respond(struct http_server_request *req); void http_server_request_finished(struct http_server_request *req); /* Payload handler */ void http_server_payload_handler_destroy( struct http_server_payload_handler **_handler); void http_server_payload_handler_switch_ioloop( struct http_server_payload_handler *handler, struct ioloop *ioloop); /* * Connection */ static inline void http_server_connection_add_request(struct http_server_connection *conn, struct http_server_request *sreq) { DLLIST2_APPEND(&conn->request_queue_head, &conn->request_queue_tail, sreq); conn->request_queue_count++; } static inline void http_server_connection_remove_request(struct http_server_connection *conn, struct http_server_request *sreq) { DLLIST2_REMOVE(&conn->request_queue_head, &conn->request_queue_tail, sreq); conn->request_queue_count--; } struct connection_list *http_server_connection_list_init(void); bool http_server_connection_shut_down(struct http_server_connection *conn); void http_server_connection_input_set_pending( struct http_server_connection *conn); void http_server_connection_input_halt(struct http_server_connection *conn); void http_server_connection_input_resume(struct http_server_connection *conn); void http_server_connection_start_idle_timeout( struct http_server_connection *conn); void http_server_connection_reset_idle_timeout( struct http_server_connection *conn); void http_server_connection_stop_idle_timeout( struct http_server_connection *conn); void http_server_connection_handle_output_error( struct http_server_connection *conn); void http_server_connection_output_trigger(struct http_server_connection *conn); void http_server_connection_output_halt(struct http_server_connection *conn); void http_server_connection_output_resume(struct http_server_connection *conn); int http_server_connection_flush(struct http_server_connection *conn); int http_server_connection_output(struct http_server_connection *conn); void http_server_connection_tunnel(struct http_server_connection **_conn, http_server_tunnel_callback_t callback, void *context); bool http_server_connection_pending_payload( struct http_server_connection *conn); /* * Resource */ int http_server_resource_find(struct http_server *server, const char *path, struct http_server_resource **res_r, const char **sub_path_r) ATTR_NULL(2); bool http_server_resource_callback(struct http_server_request *req); /* * Server */ int http_server_init_ssl_ctx(struct http_server *server, const char **error_r); #endif