11 #include <boost/thread.hpp> 26 using namespace folly;
47 boost::barrier barrier_{2};
63 t_ = std::thread([&]() {
64 server_->start([&]() { barrier_.wait(); },
65 [&](std::exception_ptr ) {
76 TEST(MultiBind, HandlesListenFailures) {
84 socket->getAddress(&addr);
87 std::vector<HTTPServer::IPConfig> ips = {
90 HTTPServer::Protocol::HTTP
97 auto server = std::make_unique<HTTPServer>(
std::move(options));
106 socket->listen(1024);
107 }
catch (
const std::exception& ex) {
115 TEST(HttpServerStartStop, TestRepeatStopCalls) {
117 auto server = std::make_unique<HTTPServer>(
std::move(options));
118 auto st = std::make_unique<ServerThread>(server.get());
132 reusedSession =
sock_->getSSLSessionReused();
133 session.reset(
sock_->getSSLSession());
134 if (
sock_->getPeerCert()) {
136 peerCert_ =
sock_->getPeerCert();
148 bool reusedSession{
false};
157 HTTPServer::Protocol::HTTP};
161 kTestDir +
"certs/test_cert1.pem",
162 kTestDir +
"certs/test_key1.pem",
164 cfg.sslConfigs.push_back(sslCfg);
169 auto server = std::make_unique<HTTPServer>(
std::move(options));
171 std::vector<HTTPServer::IPConfig> ips{cfg};
178 auto ctx = std::make_shared<SSLContext>();
181 sock->connect(&cb, server->addresses().front().address, 1000);
215 auto txn = CHECK_NOTNULL(downstream_->getTransaction());
216 auto& transport = txn->getTransport();
217 if (
auto cert = transport.getUnderlyingTransport()->getPeerCert()) {
222 .
header(
"X-Client-CN", certHeader)
240 std::pair<std::unique_ptr<HTTPServer>, std::unique_ptr<ServerThread>>
244 HTTPServer::Protocol::HTTP};
248 kTestDir +
"certs/test_cert1.pem", kTestDir +
"certs/test_key1.pem",
"");
249 cfg.sslConfigs.push_back(sslCfg);
250 cfg.allowInsecureConnectionsOnSecureServer =
251 allowInsecureConnectionsOnSecureServer;
252 cfg.ticketSeeds = seeds;
259 auto server = std::make_unique<HTTPServer>(
std::move(options));
261 std::vector<HTTPServer::IPConfig> ips{cfg};
264 auto st = std::make_unique<ServerThread>(server.get());
269 TEST(SSL, TestAllowInsecureOnSecureServer) {
270 std::unique_ptr<HTTPServer> server;
271 std::unique_ptr<ServerThread> st;
275 URL url(folly::to<std::string>(
276 "http://localhost:", server->
addresses().front().address.getPort()));
278 CurlClient curl(&evb, HTTPMethod::GET, url,
nullptr, headers,
"");
285 std::chrono::milliseconds(1000))};
289 std::chrono::milliseconds(1000));
292 EXPECT_EQ(200, response->getStatusCode());
295 TEST(SSL, DisallowInsecureOnSecureServer) {
296 std::unique_ptr<HTTPServer> server;
297 std::unique_ptr<ServerThread> st;
301 URL url(folly::to<std::string>(
302 "http://localhost:", server->
addresses().front().address.getPort()));
304 CurlClient curl(&evb, HTTPMethod::GET, url,
nullptr, headers,
"");
311 std::chrono::milliseconds(1000))};
315 std::chrono::milliseconds(1000));
321 TEST(SSL, TestResumptionWithTickets) {
322 std::unique_ptr<HTTPServer> server;
323 std::unique_ptr<ServerThread> st;
329 auto ctx = std::make_shared<SSLContext>();
332 sock->connect(&cb, server->
addresses().front().address, 1000);
339 sock2->setSSLSession(cb.session.get());
341 sock2->connect(&cb2, server->
addresses().front().address, 1000);
348 TEST(SSL, TestResumptionAfterUpdateFails) {
349 std::unique_ptr<HTTPServer> server;
350 std::unique_ptr<ServerThread> st;
356 auto ctx = std::make_shared<SSLContext>();
359 sock->connect(&cb, server->
addresses().front().address, 1000);
370 sock2->setSSLSession(cb.session.get());
372 sock2->connect(&cb2, server->
addresses().front().address, 1000);
379 sock3->setSSLSession(cb2.session.get());
381 sock3->connect(&cb3, server->
addresses().front().address, 1000);
388 TEST(SSL, TestUpdateTLSCredentials) {
401 auto getCertDigest = [&](
const X509*
x) ->
std::string {
403 unsigned char md[EVP_MAX_MD_SIZE];
404 const EVP_MD* dig = EVP_sha256();
406 if (!X509_digest(
x, dig, md, &n)) {
407 throw std::runtime_error(
"Cannot calculate digest");
413 HTTPServer::Protocol::HTTP};
416 copyCreds(kTestDir +
"certs/test_cert1.pem",
417 kTestDir +
"certs/test_key1.pem");
419 cfg.sslConfigs.push_back(sslCfg);
422 HTTPServer::Protocol::HTTP};
427 auto server = std::make_unique<HTTPServer>(
std::move(options));
429 std::vector<HTTPServer::IPConfig> ips{cfg, insecureCfg};
437 auto ctx = std::make_shared<SSLContext>();
441 auto connectAndFetchServerCert = [&]() ->
std::string {
444 sock->connect(&cb, server->addresses().front().address, 1000);
448 auto x509 = cb.getPeerCert();
450 return getCertDigest(x509);
454 auto cert1 = connectAndFetchServerCert();
455 EXPECT_EQ(cert1.length(), SHA256_DIGEST_LENGTH);
458 copyCreds(kTestDir +
"certs/test_cert2.pem",
459 kTestDir +
"certs/test_key2.pem");
460 server->updateTLSCredentials();
464 auto cert2 = connectAndFetchServerCert();
465 EXPECT_EQ(cert2.length(), SHA256_DIGEST_LENGTH);
469 TEST(GetListenSocket, TestNoBootstrap) {
471 auto server = std::make_unique<HTTPServer>(
std::move(options));
472 auto st = std::make_unique<ServerThread>(server.get());
475 auto socketFd = server->getListenSocket();
479 TEST(GetListenSocket, TestBootstrapWithNoBinding) {
480 std::unique_ptr<HTTPServer> server;
481 std::unique_ptr<ServerThread> st;
493 TEST(GetListenSocket, TestBootstrapWithBinding) {
494 std::unique_ptr<HTTPServer> server;
495 std::unique_ptr<ServerThread> st;
504 TEST(UseExistingSocket, TestWithExistingAsyncServerSocket) {
506 serverSocket->bind(0);
509 HTTPServer::Protocol::HTTP};
510 std::vector<HTTPServer::IPConfig> ips{cfg};
516 auto existingFd = serverSocket->getSocket();
519 auto server = std::make_unique<HTTPServer>(
std::move(options));
520 auto st = std::make_unique<ServerThread>(server.get());
525 auto socketFd = server->getListenSocket();
529 TEST(UseExistingSocket, TestWithSocketFd) {
531 serverSocket->bind(0);
534 HTTPServer::Protocol::HTTP};
539 auto existingFd = serverSocket->getSocket();
542 auto server = std::make_unique<HTTPServer>(
std::move(options));
543 auto st = std::make_unique<ServerThread>(server.get());
544 std::vector<HTTPServer::IPConfig> ips{cfg};
550 auto socketFd = server->getListenSocket();
554 TEST(UseExistingSocket, TestWithMultipleSocketFds) {
556 serverSocket->bind(0);
558 serverSocket->bind(1024);
559 }
catch (
const std::exception& ex) {
564 HTTPServer::Protocol::HTTP};
569 auto existingFds = serverSocket->getSockets();
572 auto server = std::make_unique<HTTPServer>(
std::move(options));
573 auto st = std::make_unique<ServerThread>(server.get());
574 std::vector<HTTPServer::IPConfig> ips{cfg};
580 auto socketFd = server->getListenSocket();
591 std::chrono::milliseconds(1000)));
595 std::unique_ptr<ScopedHTTPServer>
597 auto opts = createDefaultOpts();
599 auto addresses = res->getAddresses();
600 address_ = addresses.front().address;
607 URL url(folly::to<std::string>(
"https://localhost:", address_.getPort()));
609 auto client = std::make_unique<CurlClient>(
610 &
evb_, HTTPMethod::GET, url,
nullptr, headers,
"");
611 client->setFlowControlSettings(64 * 1024);
612 client->setLogging(
false);
613 client->initializeSsl(caFile,
"http/1.1", certFile, keyFile);
618 client->getSSLContext(),
620 std::chrono::milliseconds(1000));
627 folly::to<std::string>(
"http://localhost:", address_.getPort()));
629 auto client = std::make_unique<CurlClient>(
630 &
evb_, HTTPMethod::GET, url,
nullptr, headers,
"");
631 client->setFlowControlSettings(64 * 1024);
632 client->setLogging(
false);
637 std::chrono::milliseconds(1000));
655 HTTPServer::Protocol::HTTP};
659 auto server = createScopedServer();
660 auto client = connectPlainText();
661 auto resp = client->getResponse();
669 "/path/should/not/exist",
670 "/path/should/not/exist",
672 cfg_.sslConfigs.push_back(sslCfg);
680 "/path/should/not/exist",
681 "/path/should/not/exist",
683 cfg_.strictSSL =
false;
684 cfg_.sslConfigs.push_back(sslCfg);
685 auto server = createScopedServer();
686 auto client = connectPlainText();
687 auto resp = client->getResponse();
695 kTestDir +
"certs/test_cert1.pem",
696 kTestDir +
"certs/test_key1.pem",
698 cfg_.sslConfigs.push_back(sslCfg);
699 cfg_.allowInsecureConnectionsOnSecureServer =
true;
700 auto server = createScopedServer();
701 auto client = connectPlainText();
702 auto resp = client->getResponse();
705 client = connectSSL();
706 resp = client->getResponse();
719 .addThen<TestHandlerFactory>()
730 throw std::runtime_error(
"Client cert is missing or invalid.");
741 kTestDir +
"certs/test_cert1.pem", kTestDir +
"certs/test_key1.pem",
"");
742 sslCfg.
clientCAFile = kTestDir +
"certs/client_ca_cert.pem";
745 cfg_.sslConfigs.push_back(sslCfg);
747 auto server = createScopedServer();
748 auto insecureClient = connectPlainText();
749 auto certlessClient = connectSSL();
750 auto certlessClient2 = connectSSL(kTestDir +
"certs/ca_cert.pem");
751 auto secureClient = connectSSL(kTestDir +
"certs/ca_cert.pem",
752 kTestDir +
"certs/client_cert.pem",
753 kTestDir +
"certs/client_key.pem");
756 EXPECT_EQ(
nullptr, insecureClient->getResponse());
757 EXPECT_EQ(
nullptr, certlessClient->getResponse());
758 EXPECT_EQ(
nullptr, certlessClient2->getResponse());
761 auto response = secureClient->getResponse();
762 EXPECT_EQ(200, response->getStatusCode());
765 auto headers = response->getHeaders();
766 EXPECT_EQ(
"testuser1", headers.getSingleOrEmpty(
"X-Client-CN"));
wangle::SSLSessionPtr session
void onServerStart(folly::EventBase *) noexceptoverride
RequestHandler * onRequest(RequestHandler *h, HTTPMessage *) noexceptoverride
std::vector< std::string > currentSeeds
bool readFile(int fd, Container &out, size_t num_bytes=std::numeric_limits< size_t >::max())
ResponseBuilder & status(uint16_t code, const std::string &message)
EventBase * getEventBase() const
#define EXPECT_THROW(statement, expected_exception)
HHWheelTimer::UniquePtr timer_
#define ASSERT_EQ(val1, val2)
std::unique_ptr< X509, X509Deleter > X509UniquePtr
void onServerStart(folly::EventBase *) noexceptoverride
void useExistingSocket(folly::AsyncServerSocket::UniquePtr socket)
void setFlowControlSettings(int32_t recvWindow)
#define EXPECT_EQ(val1, val2)
constexpr detail::Map< Move > move
RequestHandlerChain & addThen(Args &&...args)
NewConnectionFilter newConnectionFilter
void onServerStop() noexceptoverride
—— Concurrent Priority Queue Implementation ——
ResponseBuilder & body(std::unique_ptr< folly::IOBuf > bodyIn)
static int DEFAULT_TICK_INTERVAL
RequestHandler * onRequest(RequestHandler *, HTTPMessage *) noexceptoverride
requires E e noexcept(noexcept(s.error(std::move(e))))
stop_watch< std::chrono::milliseconds > timer_
void onServerStop() noexceptoverride
folly::SocketAddress address_
static EventBaseManager * get()
int getListenSocket() const
std::unique_ptr< SSL_SESSION, SessionDestructor > SSLSessionPtr
void requestComplete() noexceptoverride
std::unique_ptr< AsyncSSLSocket, Destructor > UniquePtr
folly::SSLContext::SSLVerifyPeerEnum clientVerification
Cb(folly::AsyncSSLSocket *sock)
HTTPServerOptions createDefaultOpts() override
void onEOM() noexceptoverride
virtual HTTPServerOptions createDefaultOpts()
void onError(ProxygenError) noexceptoverride
std::vector< std::unique_ptr< RequestHandlerFactory > > handlerFactories
std::pair< std::unique_ptr< HTTPServer >, std::unique_ptr< ServerThread > > setupServer(bool allowInsecureConnectionsOnSecureServer=false, folly::Optional< wangle::TLSTicketKeySeeds > seeds=folly::none)
std::vector< IPConfig > addresses() const
void connectSuccess() noexceptoverride
ResponseBuilder & header(const std::string &headerIn, const T &value)
void useExistingSockets(const std::vector< int > &socketFds)
AsyncSocket::UniquePtr sock_
NetworkSocket socket(int af, int type, int protocol)
const fs::path & path() const
std::unique_ptr< ScopedHTTPServer > createScopedServer()
std::unique_ptr< HHWheelTimer, Destructor > UniquePtr
static Optional< std::string > getCommonName(X509 &x509)
TEST_F(AsyncSSLSocketWriteTest, write_coalescing1)
FOLLY_CPP14_CONSTEXPR Value value_or(U &&dflt) const &
void setCertificate(const std::string &certPath, const std::string &keyPath, const std::string &passwordPath)
const X509 * getPeerCert()
std::unique_ptr< AsyncServerSocket, Destructor > UniquePtr
#define EXPECT_TRUE(condition)
void connectErr(const folly::AsyncSocketException &) noexceptoverride
void setLogging(bool enabled)
void onUpgrade(UpgradeProtocol) noexceptoverride
void connect(folly::EventBase *eventBase, const folly::SocketAddress &connectAddr, std::chrono::milliseconds timeoutMs=std::chrono::milliseconds(0), const folly::AsyncSocket::OptionMap &socketOptions=folly::AsyncSocket::emptyOptionMap, const folly::SocketAddress &bindAddr=folly::AsyncSocket::anyAddress())
folly::StringPiece getContainingDirectory(folly::StringPiece input)
std::unique_ptr< CurlClient > connectPlainText()
virtual ssl::X509UniquePtr getPeerCert() const
#define EXPECT_NE(val1, val2)
void connectSSL(folly::EventBase *eventBase, const folly::SocketAddress &connectAddr, const std::shared_ptr< folly::SSLContext > &ctx, SSL_SESSION *session=nullptr, std::chrono::milliseconds timeoutMs=std::chrono::milliseconds(0), const folly::AsyncSocket::OptionMap &socketOptions=folly::AsyncSocket::emptyOptionMap, const folly::SocketAddress &bindAddr=folly::AsyncSocket::anyAddress(), const std::string &serverName=empty_string)
std::unique_ptr< CurlClient > connectSSL(const std::string &caFile="", const std::string &certFile="", const std::string &keyFile="")
void updateTicketSeeds(wangle::TLSTicketKeySeeds seeds)
bool writeFile(const Container &data, const char *filename, int flags=O_WRONLY|O_CREAT|O_TRUNC, mode_t mode=0666)
const proxygen::HTTPMessage * getResponse() const
#define ASSERT_NE(val1, val2)
#define ASSERT_FALSE(condition)
#define EXPECT_FALSE(condition)
bool hexlify(const InputString &input, OutputString &output, bool append_output)
static std::unique_ptr< IOBuf > copyBuffer(const void *buf, std::size_t size, std::size_t headroom=0, std::size_t minTailroom=0)
#define ASSERT_TRUE(condition)
ServerThread(HTTPServer *server)
ThreadPoolListHook * addr
TEST(SequencedExecutor, CPUThreadPoolExecutor)
void onRequest(std::unique_ptr< HTTPMessage >) noexceptoverride
void onBody(std::unique_ptr< folly::IOBuf >) noexceptoverride
DummyFilter(RequestHandler *upstream)