]> git.sesse.net Git - nageru/blobdiff - shared/httpd.cpp
Fix a Clang 19 warning.
[nageru] / shared / httpd.cpp
index a881919cace1abd5e2399a192f60416f39ac6dc7..006ba6599cf7fc7af46a36c4203c19ac1649a5b2 100644 (file)
@@ -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<mutex> 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();