ronantakizawa/codereview-bench huggingface dataset:
Repository: bitcoin/bitcoin
File: src/common/url.cpp (C++)

Code before:
// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <common/url.h>

#include <event2/http.h>

#include <cstdlib>
#include <string>

std::string urlDecode(const std::string &urlEncoded) {
    std::string res;
    if (!urlEncoded.empty()) {
        char *decoded = evhttp_uridecode(urlEncoded.c_str(), false, nullptr);
        if (decoded) {
            res = std::string(decoded);
            free(decoded);
        }
    }
    return res;
}


Review comment (suggestion):
The hex checking is done inside of from_chars (locale independent), so you can re-use that. Something like this may work:

```suggestion
        if (c == '%' && i + 2 < url_encoded.size()  
                 
                ) {
            int decoded_value{0};
            auto [p, ec] = std::from_chars(url_encoded.data() + i + 1, url_encoded.data() + i + 3, decoded_value, 16);

            if(ec == std::errc{} && p==url_encoded.data() + i + 3) { // hex

            res += static_cast<char>(decoded_value);
            // Next two characters are part of the percent encoding
            i += 2;
            continue;
            }
        }  
        res += c;
```

Code after:
#include <string_view>
#include <system_error>

std::string UrlDecode(std::string_view url_encoded)
{
    std::string res;
    res.reserve(url_encoded.size());

    for (size_t i = 0; i < url_encoded.size(); ++i) {
        char c = url_encoded[i];
        // Special handling for percent which should be followed by two hex digits
        // representing an octet values, see RFC 3986, Section 2.1 Percent-Encoding
        if (c == '%' && i + 2 < url_encoded.size()) {
            unsigned int decoded_value{0};
            auto [p, ec] = std::from_chars(url_encoded.data() + i + 1, url_encoded.data() + i + 3, decoded_value, 16);

            // Only if there is no error and the pointer is set to the end of
            // the string, we can be sure both characters were valid hex
            if (ec == std::errc{} && p == url_encoded.data() + i + 3) {
                res += static_cast<char>(decoded_value);
                // Next two characters are part of the percent encoding
                i += 2;
                continue;
            }
            // In case of invalid percent encoding, add the '%' and continue
        }
        res += c;
    }

    return res;
}
Repository: bitcoin/bitcoin
File: src/common/url.cpp (C++)

Code before:
// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <common/url.h>

#include <event2/http.h>

#include <cstdlib>
#include <string>

std::string urlDecode(const std::string &urlEncoded) {
    std::string res;
    if (!urlEncoded.empty()) {
        char *decoded = evhttp_uridecode(urlEncoded.c_str(), false, nullptr);
        if (decoded) {
            res = std::string(decoded);
            free(decoded);
        }
    }
    return res;
}


Review comment (security):
I'm curious about the discrepancy between this and https://github.com/bitcoin/bitcoin/pull/27468. They relate to libevent decode uri and parse uri methods respectively and the latter is more sensitive to invalid `%` sequences (ie that aren't exactly two hexadecimal characters). 

I believe it's an example of lenient acceptance from users but strict sending to other machines. However in both of our use cases (wallet init args, and the REST interface) strict RFC3689 adherence doesn't seem necessary. 

As I'm reimplementing HTTP without libevent it seems like this is better way to go, and relax the test added by #27468.

Thoughts ?

Code after:
#include <string>
#include <string_view>
#include <system_error>

std::string UrlDecode(std::string_view url_encoded)
{
    std::string res;
    res.reserve(url_encoded.size());

    for (size_t i = 0; i < url_encoded.size(); ++i) {
        char c = url_encoded[i];
        // Special handling for percent which should be followed by two hex digits
        // representing an octet values, see RFC 3986, Section 2.1 Percent-Encoding
        if (c == '%' && i + 2 < url_encoded.size()) {
            unsigned int decoded_value{0};
            auto [p, ec] = std::from_chars(url_encoded.data() + i + 1, url_encoded.data() + i + 3, decoded_value, 16);

            // Only if there is no error and the pointer is set to the end of
            // the string, we can be sure both characters were valid hex
            if (ec == std::errc{} && p == url_encoded.data() + i + 3) {
                res += static_cast<char>(decoded_value);
                // Next two characters are part of the percent encoding
                i += 2;
                continue;
            }
            // In case of invalid percent encoding, add the '%' and continue
        }
        res += c;
    }

    return res;
}
Repository: bitcoin/bitcoin
File: src/util/subprocess.h (C/C++)

Code before:
  Popen(std::vector<std::string> vargs_, Args &&... args) : vargs_(vargs_)
  {
    init_args(std::forward<Args>(args)...);

    // Setup the communication channels of the Popen class
    stream_.setup_comm_channels();

    execute_process();
  }

/*
  ~Popen()
  {
#ifdef __USING_WINDOWS__
    CloseHandle(this->process_handle_);
#endif
  }
*/

  int pid() const noexcept { return child_pid_; }

  int retcode() const noexcept { return retcode_; }

  int wait() noexcept(false);

  int poll() noexcept(false);

  // Does not fail, Caller is expected to recheck the
  // status with a call to poll()
  void kill(int sig_num = 9);

  void set_out_buf_cap(size_t cap) { stream_.set_out_buf_cap(cap); }

  void set_err_buf_cap(size_t cap) { stream_.set_err_buf_cap(cap); }

  int send(const char* msg, size_t length)
  { return stream_.send(msg, length); }

  int send(const std::string& msg)
  { return send(msg.c_str(), msg.size()); }

  int send(const std::vector<char>& msg)
  { return stream_.send(msg); }

  std::pair<OutBuffer, ErrBuffer> communicate(const char* msg, size_t length)
  {
    auto res = stream_.communicate(msg, length);
    retcode_ = wait();
    return res;
  }


Review comment (suggestion):
ed39d261dc056e700b79da769e085c8af389451d:

The `Popen::poll()` function is used in #29868. I hope that an improved/fixed Windows implementation of the `Popen::retcode()`, which I don't have now, will allow to drop it.

Code after:
  }

  FILE* input()  { return stream_.input(); }
  FILE* output() { return stream_.output();}
  FILE* error()  { return stream_.error(); }

  /// Stream close APIs
  void close_input()  { stream_.input_.reset();  }
  void close_output() { stream_.output_.reset(); }
  void close_error()  { stream_.error_.reset();  }

private:
  template <typename F, typename... Args>
  void init_args(F&& farg, Args&&... args);
  void init_args();
  void populate_c_argv();
  void execute_process() noexcept(false);

private:
  detail::Streams stream_;

#ifdef __USING_WINDOWS__
  HANDLE process_handle_;
  std::future<void> cleanup_future_;
#endif

  std::string exe_name_;

  // Command in string format
  std::string args_;
  // Command provided as sequence
  std::vector<std::string> vargs_;
  std::vector<char*> cargv_;

  bool child_created_ = false;
  // Pid of the child process
  int child_pid_ = -1;

  int retcode_ = -1;
};

inline void Popen::init_args() {
  populate_c_argv();
}

template <typename F, typename... Args>
inline void Popen::init_args(F&& farg, Args&&... args)
{
  detail::ArgumentDeducer argd(this);
  argd.set_option(std::forward<F>(farg));
  init_args(std::forward<Args>(args)...);
Repository: bitcoin/bitcoin
File: src/wallet/wallet.cpp (C++)

Code before:
        WalletDescriptor w_desc = desc_spkm->GetWalletDescriptor();

        std::set<CPubKey> desc_pubkeys;
        std::set<CExtPubKey> desc_xpubs;
        w_desc.descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
        active_xpubs.merge(std::move(desc_xpubs));
    }
    return active_xpubs;
}

std::optional<CKey> CWallet::GetKey(const CKeyID& keyid) const
{
    Assert(IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));

    for (const auto& spkm : GetAllScriptPubKeyMans()) {
        const DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
        assert(desc_spkm);
        LOCK(desc_spkm->cs_desc_man);
        if (std::optional<CKey> key = desc_spkm->GetKey(keyid)) {
            return key;
        }
    }
    return std::nullopt;
}

size_t GetSerializeSizeForRecipient(const CRecipient& recipient)
{
    return std::visit([&recipient](auto&& dest) -> size_t {
        return ::GetSerializeSize(CTxOut(recipient.nAmount, GetScriptForDestination(dest)));
    }, recipient.dest);
}

bool IsDust(const CRecipient& recipient, const CFeeRate& dustRelayFee)
{
    return std::visit([&recipient, &dustRelayFee](auto&& dest) -> bool {
        return ::IsDust(CTxOut(recipient.nAmount, GetScriptForDestination(dest)), dustRelayFee);
    }, recipient.dest);
}
} // namespace wallet


Review comment (suggestion):
nit: I think the visitor pattern in `GetSerializeSizeForRecipient` and `IsDust` in this case makes the code less clear, but I could be missing something

Code after:

    std::set<CExtPubKey> active_xpubs;
    for (const auto& spkm : GetActiveScriptPubKeyMans()) {
        const DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
        assert(desc_spkm);
        LOCK(desc_spkm->cs_desc_man);
        WalletDescriptor w_desc = desc_spkm->GetWalletDescriptor();

        std::set<CPubKey> desc_pubkeys;
        std::set<CExtPubKey> desc_xpubs;
        w_desc.descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
        active_xpubs.merge(std::move(desc_xpubs));
    }
    return active_xpubs;
}

std::optional<CKey> CWallet::GetKey(const CKeyID& keyid) const
{
    Assert(IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));

    for (const auto& spkm : GetAllScriptPubKeyMans()) {
        const DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
        assert(desc_spkm);
        LOCK(desc_spkm->cs_desc_man);
        if (std::optional<CKey> key = desc_spkm->GetKey(keyid)) {
            return key;
        }
    }
    return std::nullopt;
}
} // namespace wallet
Repository: bitcoin/bitcoin
File: src/wallet/spend.cpp (C++)

Code before:
// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <algorithm>
#include <common/args.h>
#include <common/system.h>
#include <consensus/amount.h>
#include <consensus/validation.h>
#include <interfaces/chain.h>
#include <numeric>
#include <primitives/transaction.h>
#include <script/script.h>
#include <script/signingprovider.h>
#include <script/solver.h>
#include <util/check.h>
#include <util/fees.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/trace.h>
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/fees.h>
#include <wallet/receive.h>
#include <wallet/spend.h>
#include <wallet/transaction.h>
#include <wallet/wallet.h>

#include <cmath>

using interfaces::FoundBlock;

namespace wallet {
static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100};

/** Whether the descriptor represents, directly or not, a witness program. */
static bool IsSegwit(const Descriptor& desc) {
    if (const auto typ = desc.GetOutputType()) return *typ != OutputType::LEGACY;
    return false;

Review comment (suggestion):
This include should still be needed. The `CreateTransactionInternal` still calls `GetDustThreshold`.

Code after:
// Copyright (c) 2021-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <algorithm>
#include <common/args.h>
#include <common/messages.h>
#include <common/system.h>
#include <consensus/amount.h>
#include <consensus/validation.h>
#include <interfaces/chain.h>
#include <node/types.h>
#include <numeric>
#include <policy/policy.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <script/signingprovider.h>
#include <script/solver.h>
#include <util/check.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/trace.h>
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/fees.h>
#include <wallet/receive.h>
#include <wallet/spend.h>
#include <wallet/transaction.h>
#include <wallet/wallet.h>

#include <cmath>

using common::StringForFeeReason;
using common::TransactionErrorString;
using interfaces::FoundBlock;
using node::TransactionError;

namespace wallet {
static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100};
Repository: bitcoin/bitcoin
File: src/key.h (C/C++)

Code before:
    KeyPair& operator=(KeyPair&&) noexcept = default;

    friend KeyPair CKey::ComputeKeyPair(const uint256* merkle_root) const;
    [[nodiscard]] bool GetKey(CKey& key) const;
    [[nodiscard]] bool SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256& aux) const;

    //! Simple read-only vector-like interface.
    unsigned int size() const { return m_keydata ? m_keydata->size() : 0; }
    const std::byte* data() const { return m_keydata ? reinterpret_cast<const std::byte*>(m_keydata->data()) : nullptr; }
    const std::byte* begin() const { return data(); }
    const std::byte* end() const { return data() + size(); }
private:
    KeyPair(const CKey& key, const uint256* merkle_root);

    using KeyType = std::array<unsigned char, 96>;
    secure_unique_ptr<KeyType> m_keydata;
};

/** Check that required EC support is available at runtime. */
bool ECC_InitSanityCheck();

/**
 * RAII class initializing and deinitializing global state for elliptic curve support.
 * Only one instance may be initialized at a time.
 *
 * In the future global ECC state could be removed, and this class could contain
 * state and be passed as an argument to ECC key functions.
 */
class ECC_Context
{
public:
    ECC_Context();
    ~ECC_Context();
};

#endif // BITCOIN_KEY_H


Review comment (refactor):
nit: would it make sense to extract the `96` to a const?
```C++
constexpr size_t SECP256K1_KEYPAIR_SIZE = 96;
using KeyType = std::array<unsigned char, SECP256K1_KEYPAIR_SIZE>;
```

Code after:
    KeyPair& operator=(KeyPair&&) noexcept = default;
    KeyPair& operator=(const KeyPair& other)
    {
        if (this != &other) {
            if (other.m_keypair) {
                MakeKeyPairData();
                *m_keypair = *other.m_keypair;
            } else {
                ClearKeyPairData();
            }
        }
        return *this;
    }

    KeyPair(const KeyPair& other) { *this = other; }

    friend KeyPair CKey::ComputeKeyPair(const uint256* merkle_root) const;
    [[nodiscard]] bool SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256& aux) const;

    //! Check whether this keypair is valid.
    bool IsValid() const { return !!m_keypair; }

private:
    KeyPair(const CKey& key, const uint256* merkle_root);

    using KeyType = std::array<unsigned char, 96>;
    secure_unique_ptr<KeyType> m_keypair;

    void MakeKeyPairData()
    {
        if (!m_keypair) m_keypair = make_secure_unique<KeyType>();
    }

    void ClearKeyPairData()
    {
        m_keypair.reset();
    }
};

/** Check that required EC support is available at runtime. */
bool ECC_InitSanityCheck();

/**
 * RAII class initializing and deinitializing global state for elliptic curve support.
 * Only one instance may be initialized at a time.
 *
 * In the future global ECC state could be removed, and this class could contain
 * state and be passed as an argument to ECC key functions.
 */
class ECC_Context
{
Repository: bitcoin/bitcoin
File: src/test/util_threadnames_tests.cpp (C++)

Code before:
{
    std::vector<std::thread> threads;
    std::set<std::string> names;
    std::mutex lock;

    auto RenameThisThread = [&](int i) {
        util::ThreadRename(TEST_THREAD_NAME_BASE + ToString(i));
        std::lock_guard<std::mutex> guard(lock);
        names.insert(util::ThreadGetInternalName());
    };

    threads.reserve(num_threads);
    for (int i = 0; i < num_threads; ++i) {
        threads.emplace_back(RenameThisThread, i);
    }

    for (std::thread& thread : threads) thread.join();

    return names;
}

/**
 * Rename a bunch of threads with the same basename (expect_multiple=true), ensuring suffixes are
 * applied properly.
 */
BOOST_AUTO_TEST_CASE(util_threadnames_test_rename_threaded)
{
#if !defined(HAVE_THREAD_LOCAL)
    // This test doesn't apply to platforms where we don't have thread_local.
    return;
#endif

    std::set<std::string> names = RenameEnMasse(100);

    BOOST_CHECK_EQUAL(names.size(), 100U);

    // Names "test_thread.[n]" should exist for n = [0, 99]
    for (int i = 0; i < 100; ++i) {
        BOOST_CHECK(names.find(TEST_THREAD_NAME_BASE + ToString(i)) != names.end());
    }

}

BOOST_AUTO_TEST_SUITE_END()


Review comment (suggestion):
With this it will be possible to remove `export NOWARN_CXXFLAGS="-Wno-error=unreachable-code"` from dev environment on FreeBSD, thanks!

Code after:
    std::set<std::string> names;
    std::mutex lock;

    auto RenameThisThread = [&](int i) {
        util::ThreadRename(TEST_THREAD_NAME_BASE + ToString(i));
        std::lock_guard<std::mutex> guard(lock);
        names.insert(util::ThreadGetInternalName());
    };

    threads.reserve(num_threads);
    for (int i = 0; i < num_threads; ++i) {
        threads.emplace_back(RenameThisThread, i);
    }

    for (std::thread& thread : threads) thread.join();

    return names;
}

/**
 * Rename a bunch of threads with the same basename (expect_multiple=true), ensuring suffixes are
 * applied properly.
 */
BOOST_AUTO_TEST_CASE(util_threadnames_test_rename_threaded)
{
    std::set<std::string> names = RenameEnMasse(100);

    BOOST_CHECK_EQUAL(names.size(), 100U);

    // Names "test_thread.[n]" should exist for n = [0, 99]
    for (int i = 0; i < 100; ++i) {
        BOOST_CHECK(names.find(TEST_THREAD_NAME_BASE + ToString(i)) != names.end());
    }

}

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

Code before:
    for (const auto& spkm : GetActiveScriptPubKeyMans()) {
        const DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
        assert(desc_spkm);
        LOCK(desc_spkm->cs_desc_man);
        WalletDescriptor w_desc = desc_spkm->GetWalletDescriptor();

        std::set<CPubKey> desc_pubkeys;
        std::set<CExtPubKey> desc_xpubs;
        w_desc.descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
        active_xpubs.merge(std::move(desc_xpubs));
    }
    return active_xpubs;
}

std::optional<CKey> CWallet::GetKey(const CKeyID& keyid) const
{
    Assert(IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));

    for (const auto& spkm : GetAllScriptPubKeyMans()) {
        const DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
        assert(desc_spkm);
        LOCK(desc_spkm->cs_desc_man);
        if (std::optional<CKey> key = desc_spkm->GetKey(keyid)) {
            return key;
        }
    }
    return std::nullopt;
}

void CWallet::WriteBestBlock() const
{
    AssertLockHeld(cs_wallet);

    if (!m_last_block_processed.IsNull()) {
        CBlockLocator loc;
        chain().findBlock(m_last_block_processed, FoundBlock().locator(loc));

        WalletBatch batch(GetDatabase());
        batch.WriteBestBlock(loc);
    }
}
} // namespace wallet


Review comment (suggestion):
In commit "wallet: Update best block record after block dis/connect" (7bacabb204b6c34f9545f0b37e2c66296ad2c0de)

IMO would be good to assert `!loc.IsNull()` as a sanity check to ensure that doesn't happen. (It shouldn't, but node or wallet code could change in the future and invalidate current assumptions.)

Code after:
    }
    return active_xpubs;
}

std::optional<CKey> CWallet::GetKey(const CKeyID& keyid) const
{
    Assert(IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));

    for (const auto& spkm : GetAllScriptPubKeyMans()) {
        const DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
        assert(desc_spkm);
        LOCK(desc_spkm->cs_desc_man);
        if (std::optional<CKey> key = desc_spkm->GetKey(keyid)) {
            return key;
        }
    }
    return std::nullopt;
}

void CWallet::WriteBestBlock() const
{
    AssertLockHeld(cs_wallet);

    if (!m_last_block_processed.IsNull()) {
        CBlockLocator loc;
        chain().findBlock(m_last_block_processed, FoundBlock().locator(loc));

        WalletBatch batch(GetDatabase());
        batch.WriteBestBlock(loc);
    }
}
} // namespace wallet
Repository: bitcoin/bitcoin
File: src/httpserver.h (C/C++)

Code before:
// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_HTTPSERVER_H
#define BITCOIN_HTTPSERVER_H

#include <functional>
#include <optional>
#include <string>

namespace util {
class SignalInterrupt;
} // namespace util

static const int DEFAULT_HTTP_THREADS=4;
static const int DEFAULT_HTTP_WORKQUEUE=16;
static const int DEFAULT_HTTP_SERVER_TIMEOUT=30;

struct evhttp_request;
struct event_base;
class CService;
class HTTPRequest;

/** Initialize HTTP server.
 * Call this before RegisterHTTPHandler or EventBase().
 */
bool InitHTTPServer(const util::SignalInterrupt& interrupt);
/** Start HTTP server.
 * This is separate from InitHTTPServer to give users race-condition-free time
 * to register their handlers between InitHTTPServer and StartHTTPServer.
 */
void StartHTTPServer();
/** Interrupt HTTP server threads */
void InterruptHTTPServer();
/** Stop HTTP server */
void StopHTTPServer();

Review comment (suggestion):
nit: we typically include our own headers first, and include in `httpserver.cpp` is missing

<details>
<summary>git diff</summary>

```diff
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index adc6040d08..6ba8754485 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -13,6 +13,7 @@
 #include <netbase.h>
 #include <node/interface_ui.h>
 #include <rpc/protocol.h> // For HTTP status codes
+#include <span.h>
 #include <sync.h>
 #include <util/check.h>
 #include <util/signalinterrupt.h>
diff --git a/src/httpserver.h b/src/httpserver.h
index c193cf2a7f..ffba4864aa 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -5,12 +5,12 @@
 #ifndef BITCOIN_HTTPSERVER_H
 #define BITCOIN_HTTPSERVER_H
 
+#include <span.h>
+
 #include <functional>
 #include <optional>
 #include <string>
 
-#include <span.h>
-
 namespace util {
 class SignalInterrupt;
 } // namespace util

```
</details>


Code after:
// Copyright (c) 2015-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_HTTPSERVER_H
#define BITCOIN_HTTPSERVER_H

#include <functional>
#include <optional>
#include <span>
#include <string>

namespace util {
class SignalInterrupt;
} // namespace util

static const int DEFAULT_HTTP_THREADS=4;
static const int DEFAULT_HTTP_WORKQUEUE=16;
static const int DEFAULT_HTTP_SERVER_TIMEOUT=30;

struct evhttp_request;
struct event_base;
class CService;
class HTTPRequest;

/** Initialize HTTP server.
 * Call this before RegisterHTTPHandler or EventBase().
 */
bool InitHTTPServer(const util::SignalInterrupt& interrupt);
/** Start HTTP server.
 * This is separate from InitHTTPServer to give users race-condition-free time
 * to register their handlers between InitHTTPServer and StartHTTPServer.
 */
void StartHTTPServer();
/** Interrupt HTTP server threads */
void InterruptHTTPServer();
/** Stop HTTP server */