Example #1
0
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);
}
Example #2
0
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;
}
Example #3
0
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);
}
Example #4
0
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);
}
Example #5
0
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);
}
Example #6
0
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);
}
Example #7
0
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();
	}
}