X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=shared%2Fhttpd.cpp;h=006ba6599cf7fc7af46a36c4203c19ac1649a5b2;hb=f9219370ce1f5ba37e716d50d41115bb672c4244;hp=a881919cace1abd5e2399a192f60416f39ac6dc7;hpb=bcd177e1daf5a63d7bf877bc5d30d8803dfd472c;p=nageru diff --git a/shared/httpd.cpp b/shared/httpd.cpp index a881919..006ba65 100644 --- a/shared/httpd.cpp +++ b/shared/httpd.cpp @@ -45,7 +45,6 @@ void HTTPD::start(int port) port, nullptr, nullptr, &answer_to_connection_thunk, this, - MHD_OPTION_NOTIFY_COMPLETED, nullptr, this, MHD_OPTION_END); if (mhd == nullptr) { fprintf(stderr, "Warning: Could not open HTTP server. (Port already in use?)\n"); @@ -86,19 +85,19 @@ void HTTPD::add_data_locked(StreamID stream_id, const char *buf, size_t size, St } } -int HTTPD::answer_to_connection_thunk(void *cls, MHD_Connection *connection, - const char *url, const char *method, - const char *version, const char *upload_data, - size_t *upload_data_size, void **con_cls) +HTTPD::MHD_Result HTTPD::answer_to_connection_thunk(void *cls, MHD_Connection *connection, + const char *url, const char *method, + const char *version, const char *upload_data, + size_t *upload_data_size, void **con_cls) { HTTPD *httpd = (HTTPD *)cls; return httpd->answer_to_connection(connection, url, method, version, upload_data, upload_data_size, con_cls); } -int HTTPD::answer_to_connection(MHD_Connection *connection, - const char *url, const char *method, - const char *version, const char *upload_data, - size_t *upload_data_size, void **con_cls) +HTTPD::MHD_Result HTTPD::answer_to_connection(MHD_Connection *connection, + const char *url, const char *method, + const char *version, const char *upload_data, + size_t *upload_data_size, void **con_cls) { // See if the URL ends in “.metacube”. HTTPD::Stream::Framing framing; @@ -124,7 +123,7 @@ int HTTPD::answer_to_connection(MHD_Connection *connection, MHD_Response *response = MHD_create_response_from_buffer( contents.size(), &contents[0], MHD_RESPMEM_MUST_COPY); MHD_add_response_header(response, "Content-type", "text/plain"); - int ret = MHD_queue_response(connection, MHD_HTTP_OK, response); + MHD_Result ret = MHD_queue_response(connection, MHD_HTTP_OK, response); MHD_destroy_response(response); // Only decreases the refcount; actual free is after the request is done. return ret; } @@ -136,7 +135,7 @@ int HTTPD::answer_to_connection(MHD_Connection *connection, if (endpoints[url].cors_policy == ALLOW_ALL_ORIGINS) { MHD_add_response_header(response, "Access-Control-Allow-Origin", "*"); } - int ret = MHD_queue_response(connection, MHD_HTTP_OK, response); + MHD_Result ret = MHD_queue_response(connection, MHD_HTTP_OK, response); MHD_destroy_response(response); // Only decreases the refcount; actual free is after the request is done. return ret; } @@ -147,7 +146,7 @@ int HTTPD::answer_to_connection(MHD_Connection *connection, MHD_Response *response = MHD_create_response_from_buffer( contents.size(), &contents[0], MHD_RESPMEM_MUST_COPY); MHD_add_response_header(response, "Content-type", "text/plain"); - int ret = MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, response); + MHD_Result ret = MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, response); MHD_destroy_response(response); // Only decreases the refcount; actual free is after the request is done. return ret; } @@ -176,7 +175,7 @@ int HTTPD::answer_to_connection(MHD_Connection *connection, MHD_add_response_header(response, "Content-encoding", "metacube"); } - int ret = MHD_queue_response(connection, MHD_HTTP_OK, response); + MHD_Result ret = MHD_queue_response(connection, MHD_HTTP_OK, response); MHD_destroy_response(response); // Only decreases the refcount; actual free is after the request is done. return ret; @@ -209,10 +208,23 @@ ssize_t HTTPD::Stream::reader_callback_thunk(void *cls, uint64_t pos, char *buf, ssize_t HTTPD::Stream::reader_callback(uint64_t pos, char *buf, size_t max) { unique_lock lock(buffer_mutex); - has_buffered_data.wait(lock, [this] { return should_quit || !buffered_data.empty(); }); + bool has_data = has_buffered_data.wait_for(lock, std::chrono::seconds(60), [this] { return should_quit || !buffered_data.empty(); }); if (should_quit) { return -1; } + if (!has_data) { + // The wait timed out, so tell microhttpd to clean out the socket; + // it's not unlikely that the client has given up anyway. + // This is seemingly the only way to actually reap sockets if we + // do not get any data; returning 0 does nothing, and + // MHD_OPTION_NOTIFY_CONNECTION does not trigger for these cases. + // If not, an instance that has no data to send (typically an instance + // of kaeru connected to a nonfunctional backend) would get a steadily + // increasing amount of sockets in CLOSE_WAIT (ie., the other end has + // hung up, but we haven't called close() yet, as our thread is stuck + // in this callback). + return -1; + } ssize_t ret = 0; while (max > 0 && !buffered_data.empty()) { @@ -260,6 +272,7 @@ void HTTPD::Stream::add_data(const char *buf, size_t buf_size, HTTPD::Stream::Da // so kill it instead of going out of memory. Note that this // won't kill the client immediately, but will cause the next callback // to kill the client. + fprintf(stderr, "HTTP client had more than 1 GB backlog; killing.\n"); should_quit = true; buffered_data.clear(); has_buffered_data.notify_all();