Repository: bitcoin/bitcoin
File: src/httpserver.cpp (C++)

Code before:

        auto item = [req = hreq, in_path = std::move(path), fn = i->handler]() {
            std::string err_msg;
            try {
                fn(req.get(), in_path);
                return;
            } catch (const std::exception& e) {
                LogWarning("Unexpected error while processing request for '%s'. Error msg: '%s'", req->GetURI(), e.what());
                err_msg = e.what();
            } catch (...) {
                LogWarning("Unknown error while processing request for '%s'", req->GetURI());
                err_msg = "unknown error";
            }
            // Reply so the client doesn't hang waiting for the response.
            req->WriteHeader("Connection", "close");
            // TODO: Implement specific error formatting for the REST and JSON-RPC servers responses.
            req->WriteReply(HTTP_INTERNAL_SERVER_ERROR, err_msg);
        };

        if (auto res = g_threadpool_http.Submit(std::move(item)); !res.has_value()) {
            LogWarning("Request rejected during server shutdown");
            hreq->WriteReply(HTTP_SERVICE_UNAVAILABLE, "Request rejected during server shutdown");
            return;
        }
    } else {
        hreq->WriteReply(HTTP_NOT_FOUND);
    }
}

/** Callback to reject HTTP requests after shutdown. */
static void http_reject_request_cb(struct evhttp_request* req, void*)
{
    LogDebug(BCLog::HTTP, "Rejecting request while shutting down\n");
    evhttp_send_error(req, HTTP_SERVUNAVAIL, nullptr);
}

/** Event dispatcher thread */
static void ThreadHTTP(struct event_base* base)
{
    util::ThreadRename("http");
    LogDebug(BCLog::HTTP, "Entering http event loop\n");
    event_base_dispatch(base);
    // Event loop will be interrupted by InterruptHTTPServer()
    LogDebug(BCLog::HTTP, "Exited http event loop\n");
}

/** Bind HTTP server to specified addresses */
static bool HTTPBindAddresses(struct evhttp* http)
{
    uint16_t http_port{static_cast<uint16_t>(gArgs.GetIntArg("-rpcport", BaseParams().RPCPort()))};
    std::vector<std::pair<std::string, uint16_t>> endpoints;

Review comment (bug):
1. Log the inner error string (currently it's never read).
2. Even though we know it in the context of this PR/issue - I think it's a bit overly presumptuous to claim we are shutting down. All this outer logic knows is that `Submit()` failed. Would go with more neutral language.
```suggestion
        if (auto res = g_threadpool_http.Submit(std::move(item)); !res.has_value()) {
            LogWarning("Request rejected by thread pool: %s", res.error());
            hreq->WriteReply(HTTP_SERVICE_UNAVAILABLE, "Request rejected by thread pool");
            return;
        }
```
(I was experimenting with changing `ThreadPool::Submit()` to enforce the queue depth by itself, which would be another potential reason for it to fail).

Code after:

        auto item = [req = hreq, in_path = std::move(path), fn = i->handler]() {
            std::string err_msg;
            try {
                fn(req.get(), in_path);
                return;
            } catch (const std::exception& e) {
                LogWarning("Unexpected error while processing request for '%s'. Error msg: '%s'", req->GetURI(), e.what());
                err_msg = e.what();
            } catch (...) {
                LogWarning("Unknown error while processing request for '%s'", req->GetURI());
                err_msg = "unknown error";
            }
            // Reply so the client doesn't hang waiting for the response.
            req->WriteHeader("Connection", "close");
            // TODO: Implement specific error formatting for the REST and JSON-RPC servers responses.
            req->WriteReply(HTTP_INTERNAL_SERVER_ERROR, err_msg);
        };

        if (auto res = g_threadpool_http.Submit(std::move(item)); !res.has_value()) {
            Assume(hreq.use_count() == 1); // ensure request will be deleted
            // Both SubmitError::Inactive and SubmitError::Interrupted mean shutdown
            LogWarning("HTTP request rejected during server shutdown: '%s'", SubmitErrorString(res.error()));
            hreq->WriteReply(HTTP_SERVICE_UNAVAILABLE, "Request rejected during server shutdown");
            return;
        }
    } else {
        hreq->WriteReply(HTTP_NOT_FOUND);
    }
}

/** Callback to reject HTTP requests after shutdown. */
static void http_reject_request_cb(struct evhttp_request* req, void*)
{
    LogDebug(BCLog::HTTP, "Rejecting request while shutting down\n");
    evhttp_send_error(req, HTTP_SERVUNAVAIL, nullptr);
}

/** Event dispatcher thread */
static void ThreadHTTP(struct event_base* base)
{
    util::ThreadRename("http");
    LogDebug(BCLog::HTTP, "Entering http event loop\n");
    event_base_dispatch(base);
    // Event loop will be interrupted by InterruptHTTPServer()
    LogDebug(BCLog::HTTP, "Exited http event loop\n");
}

/** Bind HTTP server to specified addresses */
static bool HTTPBindAddresses(struct evhttp* http)
{