void http_server_request_submit_response(struct http_server_request *req) { struct http_server_connection *conn = req->conn; i_assert(conn != NULL && req->response != NULL && req->response->submitted); http_server_request_ref(req); if (conn->payload_handler != NULL && conn->payload_handler->req == req) http_server_payload_handler_destroy(&conn->payload_handler); switch (req->state) { case HTTP_SERVER_REQUEST_STATE_NEW: case HTTP_SERVER_REQUEST_STATE_QUEUED: case HTTP_SERVER_REQUEST_STATE_PAYLOAD_IN: case HTTP_SERVER_REQUEST_STATE_PROCESSING: if (!http_server_request_is_complete(req)) { http_server_request_debug(req, "Not ready to respond"); req->state = HTTP_SERVER_REQUEST_STATE_SUBMITTED_RESPONSE; break; } http_server_request_ready_to_respond(req); break; case HTTP_SERVER_REQUEST_STATE_READY_TO_RESPOND: http_server_connection_trigger_responses(req->conn); break; case HTTP_SERVER_REQUEST_STATE_ABORTED: break; default: i_unreached(); } http_server_request_unref(&req); }
bool http_server_request_unref(struct http_server_request **_req) { struct http_server_request *req = *_req; struct http_server_connection *conn = req->conn; i_assert(req->refcount > 0); *_req = NULL; if (--req->refcount > 0) return TRUE; http_server_request_debug(req, "Free"); if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) { req->state = HTTP_SERVER_REQUEST_STATE_ABORTED; http_server_connection_remove_request(conn, req); } if (req->destroy_callback != NULL) { req->destroy_callback(req->destroy_context); req->destroy_callback = NULL; } if (req->response != NULL) http_server_response_free(req->response); pool_unref(&req->pool); return FALSE; }
void http_server_request_ready_to_respond(struct http_server_request *req) { http_server_request_debug(req, "Ready to respond"); req->state = HTTP_SERVER_REQUEST_STATE_READY_TO_RESPOND; http_server_connection_trigger_responses(req->conn); }
void http_server_request_abort(struct http_server_request **_req, const char *reason) { struct http_server_request *req = *_req; struct http_server_connection *conn = req->conn; if (req->state >= HTTP_SERVER_REQUEST_STATE_FINISHED) return; http_server_request_debug(req, "Abort"); req->conn = NULL; if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) { if (conn != NULL) { http_server_connection_remove_request(conn, req); if (!conn->closed) { /* send best-effort response if appropriate */ if (!conn->output_locked && req->state >= HTTP_SERVER_REQUEST_STATE_PROCESSING && req->state < HTTP_SERVER_REQUEST_STATE_SENT_RESPONSE) { static const char *response = "HTTP/1.1 500 Internal Server Error\r\n" "Content-Length: 0\r\n" "\r\n"; (void)o_stream_send(conn->conn.output, response, strlen(response)); } /* close the connection */ http_server_connection_close(&conn, reason); } } req->state = HTTP_SERVER_REQUEST_STATE_ABORTED; } if (req->response != NULL && !req->response->payload_blocking) { http_server_response_free(req->response); req->response = NULL; } http_server_request_destroy(_req); }
void http_server_request_finished(struct http_server_request *req) { struct http_server_connection *conn = req->conn; struct http_server_response *resp = req->response; http_server_tunnel_callback_t tunnel_callback = resp->tunnel_callback; void *tunnel_context = resp->tunnel_context; http_server_request_debug(req, "Finished"); i_assert(req->state < HTTP_SERVER_REQUEST_STATE_FINISHED); req->state = HTTP_SERVER_REQUEST_STATE_FINISHED; http_server_connection_remove_request(conn, req); conn->stats.response_count++; if (tunnel_callback == NULL) { if (req->connection_close) { http_server_connection_close(&conn, t_strdup_printf("Server closed connection: %u %s", resp->status, resp->reason)); http_server_request_destroy(&req); return; } else if (req->conn->input_broken) { http_server_connection_close(&conn, "Connection input is broken"); http_server_request_destroy(&req); return; } else if (req->req.connection_close) { http_server_connection_close(&conn, "Client requested connection close"); http_server_request_destroy(&req); return; } } http_server_request_destroy(&req); if (tunnel_callback != NULL) { http_server_connection_tunnel(&conn, tunnel_callback, tunnel_context); return; } http_server_connection_trigger_responses(conn); }
void http_server_request_destroy(struct http_server_request **_req) { struct http_server_request *req = *_req; struct http_server *server = req->server; http_server_request_debug(req, "Destroy"); /* just make sure the request ends in a proper state */ if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED) req->state = HTTP_SERVER_REQUEST_STATE_ABORTED; if (server->ioloop != NULL) io_loop_stop(server->ioloop); if (req->delay_destroy) { req->destroy_pending = TRUE; } else if (req->destroy_callback != NULL) { void (*callback)(void *) = req->destroy_callback; req->destroy_callback = NULL; callback(req->destroy_context); } http_server_request_unref(_req); }
void http_server_request_submit_response(struct http_server_request *req) { struct http_server_connection *conn = req->conn; i_assert(conn != NULL && req->response != NULL && req->response->submitted); switch (req->state) { case HTTP_SERVER_REQUEST_STATE_NEW: case HTTP_SERVER_REQUEST_STATE_QUEUED: case HTTP_SERVER_REQUEST_STATE_PAYLOAD_IN: case HTTP_SERVER_REQUEST_STATE_PROCESSING: if (!http_server_request_is_complete(req)) { http_server_request_debug(req, "Not ready to respond"); req->state = HTTP_SERVER_REQUEST_STATE_SUBMITTED_RESPONSE; break; } http_server_request_ready_to_respond(req); break; case HTTP_SERVER_REQUEST_STATE_ABORTED: break; default: i_unreached(); } }