mirror of https://gitee.com/bigwinds/arangodb
cleanup
This commit is contained in:
parent
5178c77c6c
commit
617d3e2ea4
|
@ -0,0 +1,38 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief application https server feature
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Copyright 2010-2011, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "ApplicationHttpsServer.h"
|
||||
|
||||
#include "HttpsServer/ApplicationHttpsServerImpl.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
ApplicationHttpsServer* ApplicationHttpsServer::create (ApplicationServer* server) {
|
||||
return new ApplicationHttpsServerImpl(server);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief application https server feature
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Copyright 2010-2011, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TRIAGENS_FYN_REST_APPLICATION_HTTPS_SERVER_H
|
||||
#define TRIAGENS_FYN_REST_APPLICATION_HTTPS_SERVER_H 1
|
||||
|
||||
#include "ApplicationServer/ApplicationFeature.h"
|
||||
|
||||
#include <Rest/AddressPort.h>
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
class ApplicationServer;
|
||||
class HttpHandlerFactory;
|
||||
class HttpsServer;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief application https server feature
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ApplicationHttpsServer : public ApplicationFeature {
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a new feature
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static ApplicationHttpsServer* create (ApplicationServer*);
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shows the port options
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void showPortOptions (bool value = true) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds a https address:port
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual AddressPort addPort (string const&) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief builds the https server
|
||||
///
|
||||
/// Note that the server claims ownership of the factory.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual HttpsServer* buildServer (HttpHandlerFactory*) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief builds the https server
|
||||
///
|
||||
/// Note that the server claims ownership of the factory.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual HttpsServer* buildServer (HttpHandlerFactory*, vector<AddressPort> const&) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,355 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief application server https server implementation
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Copyright 2009-2011, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "ApplicationHttpsServerImpl.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <Basics/ProgramOptions.h>
|
||||
#include <Basics/ProgramOptionsDescription.h>
|
||||
#include <Basics/Random.h>
|
||||
#include <Basics/StringUtils.h>
|
||||
#include <Basics/delete_object.h>
|
||||
#include <Logger/Logger.h>
|
||||
|
||||
#include "Dispatcher/ApplicationServerDispatcher.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpsServer/HttpsServer.h"
|
||||
#include "HttpsServer/HttpsServerImpl.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace triagens::basics;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// helper classes and methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
string lastSSLError () {
|
||||
char buf[122];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
unsigned long err = ERR_get_error();
|
||||
ERR_error_string_n(err, buf, sizeof(buf) - 1);
|
||||
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief OpenSSL BIO guard
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BIOGuard {
|
||||
public:
|
||||
BIOGuard(BIO *bio)
|
||||
: _bio(bio) {
|
||||
|
||||
}
|
||||
|
||||
~BIOGuard() {
|
||||
BIO_free(_bio);
|
||||
}
|
||||
|
||||
public:
|
||||
BIO *_bio;
|
||||
};
|
||||
}
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
ApplicationHttpsServerImpl::ApplicationHttpsServerImpl (ApplicationServer* applicationServer)
|
||||
: applicationServer(applicationServer),
|
||||
showPort(true),
|
||||
requireKeepAlive(false),
|
||||
sslProtocol(3),
|
||||
sslCacheMode(0),
|
||||
sslOptions(SSL_OP_TLS_ROLLBACK_BUG),
|
||||
sslContext(0) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
ApplicationHttpsServerImpl::~ApplicationHttpsServerImpl () {
|
||||
for_each(httpsServers.begin(), httpsServers.end(), DeleteObject());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void ApplicationHttpsServerImpl::setupOptions (map<string, ProgramOptionsDescription>& options) {
|
||||
if (showPort) {
|
||||
options[ApplicationServer::OPTIONS_SERVER + ":help-ssl"]
|
||||
("server.secure", &httpsPorts, "listen port or address:port")
|
||||
;
|
||||
}
|
||||
|
||||
options[ApplicationServer::OPTIONS_SERVER + ":help-ssl"]
|
||||
("server.secure-require-keep-alive", "close connection, if keep-alive is missing")
|
||||
("server.keyfile", &httpsKeyfile, "keyfile for SSL connections")
|
||||
("server.cafile", &cafile, "file containing the CA certificates of clients")
|
||||
("server.ssl-protocol", &sslProtocol, "1 = SSLv2, 2 = SSLv3, 3 = SSLv23, 4 = TLSv1")
|
||||
("server.ssl-cache-mode", &sslCacheMode, "0 = off, 1 = client, 2 = server")
|
||||
("server.ssl-options", &sslOptions, "ssl options, see OpenSSL documentation")
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ApplicationHttpsServerImpl::parsePhase2 (ProgramOptions& options) {
|
||||
|
||||
// check keep alive
|
||||
if (options.has("server.secure-require-keep-alive")) {
|
||||
requireKeepAlive= true;
|
||||
}
|
||||
|
||||
|
||||
// add ports
|
||||
for (vector<string>::const_iterator i = httpsPorts.begin(); i != httpsPorts.end(); ++i) {
|
||||
addPort(*i);
|
||||
}
|
||||
|
||||
|
||||
// create the ssl context (if possible)
|
||||
bool ok = createSslContext();
|
||||
|
||||
if (! ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// and return
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AddressPort ApplicationHttpsServerImpl::addPort (string const& name) {
|
||||
AddressPort ap;
|
||||
|
||||
if (! ap.split(name)) {
|
||||
LOGGER_ERROR << "unknown server:port definition '" << name << "'";
|
||||
}
|
||||
else {
|
||||
httpsAddressPorts.push_back(ap);
|
||||
}
|
||||
|
||||
return ap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HttpsServer* ApplicationHttpsServerImpl::buildServer (HttpHandlerFactory* httpHandlerFactory) {
|
||||
return buildServer(httpHandlerFactory, httpsAddressPorts);
|
||||
}
|
||||
|
||||
|
||||
|
||||
HttpsServer* ApplicationHttpsServerImpl::buildServer (HttpHandlerFactory* httpHandlerFactory, vector<AddressPort> const& ports) {
|
||||
if (ports.empty()) {
|
||||
delete httpHandlerFactory;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return buildHttpsServer(httpHandlerFactory, ports);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool ApplicationHttpsServerImpl::createSslContext () {
|
||||
|
||||
// check keyfile
|
||||
if (httpsKeyfile.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// create context
|
||||
sslContext = HttpsServer::sslContext(HttpsServer::protocol_e(sslProtocol), httpsKeyfile);
|
||||
|
||||
if (sslContext == 0) {
|
||||
LOGGER_ERROR << "failed to create SSL context, cannot create a HTTPS server";
|
||||
return false;
|
||||
}
|
||||
|
||||
// set cache mode
|
||||
SSL_CTX_set_session_cache_mode(sslContext, sslCacheMode);
|
||||
LOGGER_INFO << "using SSL session cache mode: " << sslCacheMode;
|
||||
|
||||
// set options
|
||||
SSL_CTX_set_options(sslContext, sslOptions);
|
||||
LOGGER_INFO << "using SSL options: " << sslOptions;
|
||||
|
||||
|
||||
// set ssl context
|
||||
Random::UniformCharacter r("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
|
||||
string rctx = r.random(SSL_MAX_SSL_SESSION_ID_LENGTH);
|
||||
|
||||
int res = SSL_CTX_set_session_id_context(sslContext, (unsigned char const*) StringUtils::duplicate(rctx), rctx.size());
|
||||
|
||||
if (res != 1) {
|
||||
LOGGER_FATAL << "cannot set SSL session id context '" << rctx << "'";
|
||||
LOGGER_ERROR << lastSSLError();
|
||||
return false;
|
||||
}
|
||||
|
||||
// check CA
|
||||
if (! cafile.empty()) {
|
||||
LOGGER_TRACE << "trying to load CA certificates from '" << cafile << "'";
|
||||
|
||||
int res = SSL_CTX_load_verify_locations(sslContext, cafile.c_str(), 0);
|
||||
|
||||
if (res == 0) {
|
||||
LOGGER_FATAL << "cannot load CA certificates from '" << cafile << "'";
|
||||
LOGGER_ERROR << lastSSLError();
|
||||
return false;
|
||||
}
|
||||
|
||||
STACK_OF(X509_NAME) * certNames;
|
||||
|
||||
certNames = SSL_load_client_CA_file(cafile.c_str());
|
||||
|
||||
if (certNames == 0) {
|
||||
LOGGER_FATAL << "cannot load CA certificates from '" << cafile << "'";
|
||||
LOGGER_ERROR << lastSSLError();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TRI_IsTraceLogging(__FILE__)) {
|
||||
for (int i = 0; i < sk_X509_NAME_num(certNames); ++i) {
|
||||
X509_NAME* cert = sk_X509_NAME_value(certNames, i);
|
||||
|
||||
if (cert) {
|
||||
BIOGuard bout(BIO_new(BIO_s_mem()));
|
||||
|
||||
X509_NAME_print_ex(bout._bio, cert, 0, (XN_FLAG_SEP_COMMA_PLUS | XN_FLAG_DN_REV | ASN1_STRFLGS_UTF8_CONVERT) & ~ASN1_STRFLGS_ESC_MSB);
|
||||
|
||||
char* r;
|
||||
long len = BIO_get_mem_data(bout._bio, &r);
|
||||
|
||||
LOGGER_TRACE << "name: " << string(r, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX_set_client_CA_list(sslContext, certNames);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
HttpsServerImpl* ApplicationHttpsServerImpl::buildHttpsServer (HttpHandlerFactory* httpHandlerFactory,
|
||||
vector<AddressPort> const& ports) {
|
||||
Scheduler* scheduler = applicationServer->scheduler();
|
||||
|
||||
if (scheduler == 0) {
|
||||
LOGGER_FATAL << "no scheduler is known, cannot create https server";
|
||||
TRI_ShutdownLogging();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
Dispatcher* dispatcher = 0;
|
||||
ApplicationServerDispatcher* asd = dynamic_cast<ApplicationServerDispatcher*>(applicationServer);
|
||||
|
||||
if (asd != 0) {
|
||||
dispatcher = asd->dispatcher();
|
||||
}
|
||||
|
||||
// check the ssl context
|
||||
if (sslContext == 0) {
|
||||
LOGGER_FATAL << "no ssl context is known, cannot create https server";
|
||||
TRI_ShutdownLogging();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// create new server
|
||||
HttpsServerImpl* httpsServer = new HttpsServerImpl(scheduler, dispatcher, sslContext);
|
||||
|
||||
httpsServer->setHandlerFactory(httpHandlerFactory);
|
||||
|
||||
if (requireKeepAlive) {
|
||||
httpsServer->setCloseWithoutKeepAlive(true);
|
||||
}
|
||||
|
||||
// keep a list of active server
|
||||
httpsServers.push_back(httpsServer);
|
||||
|
||||
// open http ports
|
||||
deque<AddressPort> addresses;
|
||||
addresses.insert(addresses.begin(), ports.begin(), ports.end());
|
||||
|
||||
while (! addresses.empty()) {
|
||||
AddressPort ap = addresses[0];
|
||||
addresses.pop_front();
|
||||
|
||||
string bindAddress = ap.address;
|
||||
int port = ap.port;
|
||||
|
||||
bool result;
|
||||
|
||||
if (bindAddress.empty()) {
|
||||
LOGGER_TRACE << "trying to open port " << port << " for https requests";
|
||||
|
||||
result = httpsServer->addPort(port, applicationServer->addressReuseAllowed());
|
||||
}
|
||||
else {
|
||||
LOGGER_TRACE << "trying to open address " << bindAddress
|
||||
<< " on port " << port
|
||||
<< " for https requests";
|
||||
|
||||
result = httpsServer->addPort(bindAddress, port, applicationServer->addressReuseAllowed());
|
||||
}
|
||||
|
||||
if (result) {
|
||||
LOGGER_DEBUG << "opened port " << port << " for " << (bindAddress.empty() ? "any" : bindAddress);
|
||||
}
|
||||
else {
|
||||
LOGGER_TRACE << "failed to open port " << port << " for " << (bindAddress.empty() ? "any" : bindAddress);
|
||||
addresses.push_back(ap);
|
||||
|
||||
if (scheduler->isShutdownInProgress()) {
|
||||
addresses.clear();
|
||||
}
|
||||
else {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return httpsServer;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief application server https server implementation
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Copyright 2009-2011, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TRIAGENS_FYN_APPLICATION_SERVER_APPLICATION_HTTPS_SERVER_IMPL_H
|
||||
#define TRIAGENS_FYN_APPLICATION_SERVER_APPLICATION_HTTPS_SERVER_IMPL_H 1
|
||||
|
||||
#include "HttpsServer/ApplicationHttpsServer.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
class HttpsServerImpl;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief application server scheduler implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ApplicationHttpsServerImpl : public ApplicationHttpsServer {
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ApplicationHttpsServerImpl (ApplicationServer*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
~ApplicationHttpsServerImpl ();
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setupOptions (map<string, basics::ProgramOptionsDescription>&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool parsePhase2 (basics::ProgramOptions&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void showPortOptions (bool value) {
|
||||
showPort = value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AddressPort addPort (string const&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpsServer* buildServer (HttpHandlerFactory*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpsServer* buildServer (HttpHandlerFactory*, vector<AddressPort> const&);
|
||||
|
||||
protected:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief build an http server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpsServerImpl* buildHttpsServer (HttpHandlerFactory*, vector<AddressPort> const&);
|
||||
|
||||
protected:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief application server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ApplicationServer* applicationServer;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief show port options
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool showPort;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief is keep-alive required to keep the connection open
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool requireKeepAlive;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief all constructed http servers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
vector<HttpsServer*> httpsServers;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief all default ports
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
vector<string> httpsPorts;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief all used addresses
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
vector<AddressPort> httpsAddressPorts;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief keyfile
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
string httpsKeyfile;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief CA file
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
string cafile;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief ssl protocol to use
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32_t sslProtocol;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief ssl cache mode to use
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t sslCacheMode;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief ssl options to use
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t sslOptions;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief ssl context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SSL_CTX* sslContext;
|
||||
|
||||
private:
|
||||
bool createSslContext ();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,378 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief task for https communication
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Achim Brandt
|
||||
/// @author Copyright 2010-2011, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "HttpsAsyncCommTask.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <Logger/Logger.h>
|
||||
#include <Basics/MutexLocker.h>
|
||||
#include <Basics/StringBuffer.h>
|
||||
#include <Rest/HttpRequest.h>
|
||||
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpServer/HttpServerImpl.h"
|
||||
|
||||
using namespace triagens::basics;
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SSL helper functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
string lastSSLError () {
|
||||
char buf[122];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
unsigned long err = ERR_get_error();
|
||||
ERR_error_string_n(err, buf, sizeof(buf) - 1);
|
||||
|
||||
return string(buf);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
HttpsAsyncCommTask::HttpsAsyncCommTask (HttpServerImpl* server,
|
||||
socket_t fd,
|
||||
ConnectionInfo const& info,
|
||||
BIO* bio)
|
||||
: Task("HttpsAsyncCommTask"),
|
||||
GeneralAsyncCommTask<HttpServerImpl, HttpHandlerFactory, HttpCommTask>(server, fd, info),
|
||||
accepted(false),
|
||||
readBlocked(false),
|
||||
readBlockedOnWrite(false),
|
||||
writeBlockedOnRead(false),
|
||||
ssl((SSL*) info.sslContext),
|
||||
bio(bio) {
|
||||
tmpReadBuffer = new char[READ_BLOCK_SIZE];
|
||||
}
|
||||
|
||||
|
||||
|
||||
HttpsAsyncCommTask::~HttpsAsyncCommTask () {
|
||||
static int const SHUTDOWN_ITERATIONS = 10;
|
||||
bool ok = false;
|
||||
|
||||
for (int i = 0; i < SHUTDOWN_ITERATIONS; ++i) {
|
||||
if (SSL_shutdown(ssl) != 0) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! ok) {
|
||||
LOGGER_WARNING << "cannot complete SSL shutdown";
|
||||
}
|
||||
|
||||
SSL_free(ssl); // this will free bio as well
|
||||
delete[] tmpReadBuffer;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Task methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool HttpsAsyncCommTask::handleEvent (EventToken token, EventType revents) {
|
||||
bool result = GeneralAsyncCommTask<HttpServerImpl, HttpHandlerFactory, HttpCommTask>::handleEvent(token, revents);
|
||||
|
||||
if (result) {
|
||||
if (readBlockedOnWrite) {
|
||||
scheduler->startSocketEvents(writeWatcher);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SocketTask methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool HttpsAsyncCommTask::fillReadBuffer (bool& closed) {
|
||||
closed = false;
|
||||
|
||||
// is the handshake already done?
|
||||
if (! accepted) {
|
||||
if (! trySSLAccept()) {
|
||||
LOGGER_DEBUG << "failed to established SSL connection";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if read is blocked by write
|
||||
if (writeBlockedOnRead) {
|
||||
return trySSLWrite(closed, ! hasWriteBuffer());
|
||||
}
|
||||
|
||||
return trySSLRead(closed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool HttpsAsyncCommTask::handleWrite (bool& closed, bool noWrite) {
|
||||
|
||||
// is the handshake already done?
|
||||
if (! accepted) {
|
||||
if (! trySSLAccept()) {
|
||||
LOGGER_DEBUG << "failed to established SSL connection";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if write is blocked by read
|
||||
if (readBlockedOnWrite) {
|
||||
if (! trySSLRead(closed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return handleRead(closed);
|
||||
}
|
||||
|
||||
return trySSLWrite(closed, noWrite);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool HttpsAsyncCommTask::trySSLAccept () {
|
||||
int res = SSL_accept(ssl);
|
||||
|
||||
// accept successful
|
||||
if (res == 1) {
|
||||
LOGGER_DEBUG << "established SSL connection";
|
||||
accepted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// shutdown of connection
|
||||
else if (res == 0) {
|
||||
LOGGER_DEBUG << "SSL_accept failed";
|
||||
LOGGER_DEBUG << lastSSLError();
|
||||
return false;
|
||||
}
|
||||
|
||||
// maybe we need more data
|
||||
else {
|
||||
int err = SSL_get_error(ssl, res);
|
||||
|
||||
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
LOGGER_INFO << "error in SSL handshake";
|
||||
LOGGER_INFO << lastSSLError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool HttpsAsyncCommTask::trySSLRead (bool& closed) {
|
||||
closed = false;
|
||||
readBlocked = false;
|
||||
readBlockedOnWrite = false;
|
||||
|
||||
int nr = SSL_read(ssl, tmpReadBuffer, READ_BLOCK_SIZE);
|
||||
|
||||
if (nr <= 0) {
|
||||
int res = SSL_get_error(ssl, nr);
|
||||
|
||||
switch (res) {
|
||||
case SSL_ERROR_NONE:
|
||||
LOGGER_INFO << "unknown error in SSL_read";
|
||||
return false;
|
||||
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
closed = true;
|
||||
SSL_shutdown(ssl);
|
||||
return false;
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
readBlocked = true;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
readBlockedOnWrite = true;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
LOGGER_INFO << "received SSL_ERROR_WANT_CONNECT";
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_ACCEPT:
|
||||
LOGGER_INFO << "received SSL_ERROR_WANT_ACCEPT";
|
||||
break;
|
||||
|
||||
case SSL_ERROR_SYSCALL: {
|
||||
unsigned long err = ERR_peek_error();
|
||||
|
||||
if (err != 0) {
|
||||
LOGGER_DEBUG << "SSL_read returned syscall error with: " << lastSSLError();
|
||||
}
|
||||
else if (nr == 0) {
|
||||
LOGGER_DEBUG << "SSL_read returned syscall error because an EOF was received";
|
||||
}
|
||||
else {
|
||||
LOGGER_DEBUG << "SSL_read return syscall error: " << errno << ", " << strerror(errno);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
LOGGER_DEBUG << "received error with " << res << " and " << nr << ": " << lastSSLError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
readBuffer->appendText(tmpReadBuffer, nr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool HttpsAsyncCommTask::trySSLWrite (bool& closed, bool noWrite) {
|
||||
closed = false;
|
||||
|
||||
// if no write buffer is left, return
|
||||
if (noWrite) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool callCompletedWriteBuffer = false;
|
||||
|
||||
{
|
||||
MUTEX_LOCKER(writeBufferLock);
|
||||
|
||||
// write buffer to SSL connection
|
||||
size_t len = writeBuffer->length() - writeLength;
|
||||
int nr = 0;
|
||||
|
||||
if (0 < len) {
|
||||
writeBlockedOnRead = false;
|
||||
nr = SSL_write(ssl, writeBuffer->begin() + writeLength, (int) len);
|
||||
|
||||
if (nr <= 0) {
|
||||
int res = SSL_get_error(ssl, nr);
|
||||
|
||||
switch (res) {
|
||||
case SSL_ERROR_NONE:
|
||||
LOGGER_INFO << "unknown error in SSL_write";
|
||||
break;
|
||||
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
closed = true;
|
||||
SSL_shutdown(ssl);
|
||||
return false;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
LOGGER_INFO << "received SSL_ERROR_WANT_CONNECT";
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_ACCEPT:
|
||||
LOGGER_INFO << "received SSL_ERROR_WANT_ACCEPT";
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return false;
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
writeBlockedOnRead = true;
|
||||
return true;
|
||||
|
||||
case SSL_ERROR_SYSCALL: {
|
||||
unsigned long err = ERR_peek_error();
|
||||
|
||||
if (err != 0) {
|
||||
LOGGER_DEBUG << "SSL_read returned syscall error with: " << lastSSLError();
|
||||
}
|
||||
else if (nr == 0) {
|
||||
LOGGER_DEBUG << "SSL_read returned syscall error because an EOF was received";
|
||||
}
|
||||
else {
|
||||
LOGGER_DEBUG << "SSL_read return syscall error: " << errno << ", " << strerror(errno);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
LOGGER_DEBUG << "received error with " << res << " and " << nr << ": " << lastSSLError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
len -= nr;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
if (ownBuffer) {
|
||||
writeBuffer->free();
|
||||
delete writeBuffer;
|
||||
}
|
||||
|
||||
writeBuffer = 0;
|
||||
callCompletedWriteBuffer = true;
|
||||
}
|
||||
else {
|
||||
writeLength += nr;
|
||||
}
|
||||
}
|
||||
|
||||
// we have to release the lock, before calling completedWriteBuffer
|
||||
if (callCompletedWriteBuffer) {
|
||||
completedWriteBuffer(closed);
|
||||
|
||||
if (closed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// we might have a new write buffer
|
||||
scheduler->sendAsync(SocketTask::watcher);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief task for https communication
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Achim Brandt
|
||||
/// @author Copyright 2010-2011, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TRIAGENS_FYN_HTTP_SERVER_HTTPS_ASYNC_COMM_TASK_H
|
||||
#define TRIAGENS_FYN_HTTP_SERVER_HTTPS_ASYNC_COMM_TASK_H 1
|
||||
|
||||
#include "GeneralServer/GeneralAsyncCommTask.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "HttpServer/HttpCommTask.h"
|
||||
#include "HttpServer/HttpHandlerFactory.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
class HttpServerImpl;
|
||||
class HttpCommTask;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief task for https communication
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HttpsAsyncCommTask : public GeneralAsyncCommTask<HttpServerImpl, HttpHandlerFactory, HttpCommTask> {
|
||||
private:
|
||||
static size_t const READ_BLOCK_SIZE = 10000;
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new task with a given socket
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpsAsyncCommTask (HttpServerImpl*, socket_t, ConnectionInfo const&, BIO*);
|
||||
|
||||
protected:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructs a task
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
~HttpsAsyncCommTask ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool handleEvent (EventToken token, EventType event);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool fillReadBuffer (bool& closed);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool handleWrite (bool& closed, bool noWrite);
|
||||
|
||||
private:
|
||||
bool trySSLAccept ();
|
||||
bool trySSLRead (bool& closed);
|
||||
bool trySSLWrite (bool& closed, bool noWrite);
|
||||
|
||||
private:
|
||||
bool accepted;
|
||||
bool readBlocked;
|
||||
bool readBlockedOnWrite;
|
||||
bool writeBlockedOnRead;
|
||||
|
||||
char * tmpReadBuffer;
|
||||
|
||||
SSL* ssl;
|
||||
BIO* bio;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,127 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief https server
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Copyright 2010-2011, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "HttpsServer.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <Logger/Logger.h>
|
||||
#include <Basics/Mutex.h>
|
||||
#include <Basics/MutexLocker.h>
|
||||
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpsServer/HttpsAsyncCommTask.h"
|
||||
#include "Scheduler/Scheduler.h"
|
||||
|
||||
using namespace triagens::basics;
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SSL helper functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
Mutex SslLock;
|
||||
|
||||
string lastSSLError () {
|
||||
char buf[122];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
unsigned long err = ERR_get_error();
|
||||
ERR_error_string_n(err, buf, sizeof(buf) - 1);
|
||||
|
||||
return string(buf);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// static methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x00999999L)
|
||||
#define SSL_CONST /* */
|
||||
#else
|
||||
#define SSL_CONST const
|
||||
#endif
|
||||
|
||||
SSL_CTX* HttpsServer::sslContext (protocol_e protocol, string const& keyfile) {
|
||||
|
||||
// create our context
|
||||
SSL_METHOD SSL_CONST* meth = 0;
|
||||
|
||||
switch (protocol) {
|
||||
#ifndef OPENSSL_NO_SSL2
|
||||
case SSL_V2:
|
||||
meth = SSLv2_method();
|
||||
break;
|
||||
#endif
|
||||
case SSL_V3:
|
||||
meth = SSLv3_method();
|
||||
break;
|
||||
|
||||
case SSL_V23:
|
||||
meth = SSLv23_method();
|
||||
break;
|
||||
|
||||
case TLS_V1:
|
||||
meth = TLSv1_method();
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGGER_ERROR << "unknown SSL protocol method";
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSL_CTX* sslctx = SSL_CTX_new(meth);
|
||||
|
||||
// load our keys and certificates
|
||||
if (! SSL_CTX_use_certificate_chain_file(sslctx, keyfile.c_str())) {
|
||||
LOGGER_ERROR << "cannot read certificate from '" << keyfile << "'";
|
||||
LOGGER_ERROR << lastSSLError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (! SSL_CTX_use_PrivateKey_file(sslctx, keyfile.c_str(), SSL_FILETYPE_PEM)) {
|
||||
LOGGER_ERROR << "cannot read key from '" << keyfile << "'";
|
||||
LOGGER_ERROR << lastSSLError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
|
||||
SSL_CTX_set_verify_depth(sslctx, 1);
|
||||
#endif
|
||||
|
||||
return sslctx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief https server
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Copyright 2010-2011, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TRIAGENS_FYN_REST_HTTPS_SERVER_H
|
||||
#define TRIAGENS_FYN_REST_HTTPS_SERVER_H 1
|
||||
|
||||
#include "HttpServer/HttpServer.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief http server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HttpsServer : virtual public HttpServer {
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief SSL protocol methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum protocol_e {
|
||||
SSL_V2 = 1,
|
||||
SSL_V3 = 2,
|
||||
SSL_V23 = 3,
|
||||
TLS_V1 = 4
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a SSL context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SSL_CTX* sslContext (protocol_e, string const& keyfile);
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new http server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpsServer* create (Scheduler*, SSL_CTX*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new http server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpsServer* create (Scheduler*, Dispatcher*, SSL_CTX*);
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the verification mode
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void setVerificationMode (int mode) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the verification callback
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void setVerificationCallback (int (*func)(int, X509_STORE_CTX *)) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief https server
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Copyright 2010-2011, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "HttpsServerImpl.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <Logger/Logger.h>
|
||||
#include <Basics/Mutex.h>
|
||||
#include <Basics/MutexLocker.h>
|
||||
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "HttpsServer/HttpsAsyncCommTask.h"
|
||||
#include "Scheduler/Scheduler.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace triagens::basics;
|
||||
using namespace triagens::rest;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SSL helper functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
Mutex SslLock;
|
||||
|
||||
string lastSSLError () {
|
||||
char buf[122];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
unsigned long err = ERR_get_error();
|
||||
ERR_error_string_n(err, buf, sizeof(buf) - 1);
|
||||
|
||||
return string(buf);
|
||||
}
|
||||
}
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
HttpsServerImpl::HttpsServerImpl (Scheduler* scheduler, Dispatcher* dispatcher, SSL_CTX* ctx)
|
||||
: HttpServerImpl(scheduler, dispatcher), ctx(ctx), verificationMode(SSL_VERIFY_NONE), verificationCallback(0) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
HttpsServerImpl::~HttpsServerImpl () {
|
||||
SSL_CTX_free(ctx);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void HttpsServerImpl::handleConnected (socket_t socket, ConnectionInfo& info) {
|
||||
LOGGER_INFO << "trying to establish secure connection";
|
||||
|
||||
// convert in a SSL BIO structure
|
||||
BIO * sbio = BIO_new_socket((int) socket, BIO_NOCLOSE);
|
||||
|
||||
if (sbio == 0) {
|
||||
LOGGER_WARNING << "cannot build new SSL BIO: " << lastSSLError();
|
||||
::close(socket);
|
||||
return;
|
||||
}
|
||||
|
||||
// build a new connection
|
||||
SSL * ssl = SSL_new(ctx);
|
||||
|
||||
info.sslContext = ssl;
|
||||
|
||||
if (ssl == 0) {
|
||||
BIO_free_all(sbio);
|
||||
LOGGER_WARNING << "cannot build new SSL connection: " << lastSSLError();
|
||||
::close(socket);
|
||||
return;
|
||||
}
|
||||
|
||||
// enforce verification
|
||||
SSL_set_verify(ssl, verificationMode, verificationCallback);
|
||||
|
||||
// with the above bio
|
||||
SSL_set_bio(ssl, sbio, sbio);
|
||||
|
||||
// create a https task
|
||||
SocketTask* task = new HttpsAsyncCommTask(this, socket, info, sbio);
|
||||
|
||||
// and register it
|
||||
_scheduler->registerTask(task);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief https server implementation
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Copyright 2010-2011, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TRIAGENS_FYN_HTTP_SERVER_HTTPS_SERVER_IMPL_H
|
||||
#define TRIAGENS_FYN_HTTP_SERVER_HTTPS_SERVER_IMPL_H 1
|
||||
|
||||
#include "HttpsServer/HttpsServer.h"
|
||||
|
||||
#include "HttpServer/HttpServerImpl.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief http server implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HttpsServerImpl : public HttpServerImpl, public HttpsServer {
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new http server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpsServerImpl (Scheduler*, Dispatcher*, SSL_CTX*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructs a http server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
~HttpsServerImpl ();
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setVerificationMode (int mode) {
|
||||
verificationMode = mode;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setVerificationCallback (int (*func)(int, X509_STORE_CTX *)) {
|
||||
verificationCallback = func;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void handleConnected (socket_t, ConnectionInfo&);
|
||||
|
||||
private:
|
||||
SSL_CTX* ctx;
|
||||
int verificationMode;
|
||||
int (*verificationCallback)(int, X509_STORE_CTX *);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue