first of all: thank you very much for this nice library. I am usually a Boost user and have only recently come across Poco. I am thoroughly impressed! I have already started to spread the word ;-)
Please find at the end of this mail some code I have written to teach myself the usage of Poco's HTTP(S) classes. For simplicity reasons and in order not make this mail even longer, I've left out the headers + "using" statements.
All questions / examples below apply to an OpenSuSE 10.2 box, g++ 4.1.2, Poco 1.3.0-ssl . I'm using OpenSSL.
===Please note that I have replaced occurances of colons with semicolons to avoid incorrect formatting.===
In my example, the HTTP server produces a string containing a number, which is incremented for every request. The client prints the string to the console and sends a response back. This is to test bi-directional communication. Ultimately I'd like to use this in a client-server type application (i.e.: no Web browser involved ...).
I have first tried to implement this for HTTP (i.e. without encryption). Please note that the example below shows the HTTPS version I've come up with and for which I have a number of questions. The code works nicely for plain HTTP (obviously the code then looks different to what is shown below - e.g. the SharedPtr/Context/SSLManager directives are missing in that version; and the pure HTTP code uses a ServerSocket instead of a SecureServerSocket).
With that code below I can do the same as for the unencrypted version, except that I have to type in the passphrase for each run and I have to acknowledge that it is o.k. that the certificates have expired.
Here is my first question:
Is there an easy way to avoid communication via console or configuation file ? I have my own mechanism for config files, and do not wish to change my entire code, so that it uses Pocos way of accessing configuration files. Ideally I'd like to derive my own class from PrivateKeyPassphraseHandler and pass a suitable passphrase (read from my own configuration files or the command line or the network with my own methods). As the application is client/server, I cannot rely on the console.
It appears, though, as if a class such as
- Code: Select all
class NetSSL_API KeyArgumentHandler
;public PrivateKeyPassphraseHandler
{
public:
KeyArgumentHandler(string pk, bool server)
;PrivateKeyPassphraseHandler(server){
_privateKey = pk;
}
~KeyArgumentHandler()
{ /* nothing */ }
void onPrivateKeyRequested(const void* pSender, std;;string& privateKey){
privateKey = _privateKey;
}
private:
KeyArgumentHandler(void); // intentionally left blank
string _privateKey;
};
is not possible, as POCO_REGISTER_KEYFACTORY(NetSSL_API, KeyArgumentHandler)
expects a constructor that takes a single bool ??
The second question applies to the use of the above macro mentioned. It is marked as "deprecated" in the documentation in some places, but is recommended in other places. Also, KeyConsoleHandler seems to use it internally. What is the recommended procedure ? And can I bypass the problem with the pre-defined format for the constructor with this procedure ?
The next question applies to the usage of SSL. It might reflect my lack of knowledge of its inner workings in general ...
In the NetSSL examples shipped with Poco, both client and server use a private key and also require the presence of the root key of the certificate authority.
It is my understanding that, if I access a "https" site somewhere on the internet, my browser receives the secure site's public key, and uses it to decrypt the site's messages and to encrypt possible answers entered by the user in the browser, e.g. into a form in an internet banking application. I.e., no private key is required on the client/browser side. Is this correct ? And is there a way to avoid having to ship private keys with clients in the example at the end of this mail ?
I do have control over the server site, but not over the client sites and I obviously do not wish to send around private keys to untrusted sites.
Likewise, my application needs encryption, but does not necessarily need "official" (i.e. signed) certificates. Ideally, I would want to just create my own public/private key pair and do not really need the help of entities such es Verisign.
Thus: Is there a way to use OpenSSL encryption with Poco's HTTPS classes without having to have a root certificate of a CA for the keys ?
O.k., here comes the last question:
The Boost public license (under which Poco is delivered) referes to "derived works". I do not see a definition of that term anywhere. My understanding is that "derived works" implies modification of the original source code, and that things like "deriving a class from a Poco class" or even just "including a Poco header file and compiling / linking the application" does _not_ constitute "derived works". Is this correct ? And could it be added to the FAQ ?
O.k., so much for now.
Apologies for the lengthy posting ... ;-)
Best Regards,
Ruediger Berlich
=========================== Client ==============================================
- Code: Select all
const unsigned int MAXCOUNTER=10;
main(){
int i;
SharedPtrptrConsole = new KeyConsoleHandler(false); // ask the user via console for the pwd
SharedPtrptrCert = new ConsoleCertificateHandler(false); // ask the user via console
SharedPtrptrContext = new Context("any.pem", "rootcert.pem", false, Context::VERIFY_RELAXED, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
SSLManager;;instance().initializeClient(ptrConsole, ptrCert, ptrContext);
for(i=0; i<10; i++){
HTTPSClientSession session("localhost", 10000);
HTTPRequest req(HTTPRequest;;HTTP_GET, "/GetData", HTTPMessage;;HTTP_1_1);
bool sent = false;
unsigned int counter = 0;
while(!sent){
try{
session.sendRequest(req);
sent=true;
}
catch(...){
usleep(900000);
cout << "Not sent" << endl;
}
if(counter++ >= MAXCOUNTER){
cout << "Maximum number of failed requests reached. Terminating ..." << endl;
exit(1);
}
}
HTTPResponse res;
istream& rs = session.receiveResponse(res);
if(HTTPResponse::HTTP_OK == res.getStatus()){
string result;
StreamCopier;;copyToString(rs,result);
string response = "client received " + result;
cout << "The result in attempt " << i << " is " << result << endl
<< "Sending response "" << response << """ << endl;
HTTPRequest resp(HTTPRequest::HTTP_PUT, "/Result", HTTPMessage::HTTP_1_1);
session.sendRequest(resp) << response;
}
else{
cout << "Attempt was not succesful" << endl;
}
}
}
=========================== Server =============================================
- Code: Select all
/*************************************************************************************/
bool first = true;
unsigned int trySecret;
FastMutex tryMutex;
// Sends an increasing value to the client upon request
class TryRequestHandler
;public HTTPRequestHandler
{
public:
TryRequestHandler(string command)
;_command(command){
FastMutex;;ScopedLock lock(tryMutex);
if(first){
trySecret=0;
first=false;
}
}
void handleRequest(HTTPServerRequest& request, HTTPServerResponse &response){
// check request
string serverRequest;
StreamCopier;;copyToString(request.stream(),serverRequest);
if(_command == "GetData"){
// increase secret value
{
FastMutex;;ScopedLock lock(tryMutex);
cout << "Sending secret "" << trySecret << """ << endl;
response.send() << trySecret;
trySecret++;
}
}
else if(_command == "Result"){
cout << "Received response "" << serverRequest << """ << endl;
}
else{
FastMutex;;ScopedLock lock(tryMutex);
cout << "unknown request" << endl
<< serverRequest << endl;
response.send() << "unknown";
}
}
private:
string _command;
};
/*************************************************************************************/
class TryRequestHandlerFactory
;public HTTPRequestHandlerFactory
{
public:
TryRequestHandlerFactory(void)
{ /* nothing */ }
HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request)
{
if (request.getURI() == "/GetData"){
return new TryRequestHandler("GetData");
}
else if(request.getURI() == "/Result"){
return new TryRequestHandler("Result");
}
else{
return 0;
}
}
};
/*************************************************************************************/
class HTTPTryServer:
public Poco;;Util;;ServerApplication
{
public:
HTTPTryServer()
{ /* nothing */ }
~HTTPTryServer()
{ /* nothing */ }
protected:
void initialize(Application& self){
ServerApplication;;initialize(self);
}
void uninitialize(){
ServerApplication;;uninitialize();
}
int main(const std;;vector& args){
SharedPtrptrConsole = new KeyConsoleHandler(true); // ask the user via console for the pwd
SharedPtrptrCert = new ConsoleCertificateHandler(true); // ask the user via console
SharedPtrptrContext = new Context("any.pem", "rootcert.pem", true, Context::VERIFY_NONE, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
SSLManager;;instance().initializeServer(ptrConsole, ptrCert, ptrContext);
ThreadPool;;defaultPool().addCapacity(16);
HTTPServerParams* pParams = new HTTPServerParams;
pParams->setMaxQueued(100);
pParams->setMaxThreads(16);
// set-up a server socket
SecureServerSocket svs(10000);
// set-up a HTTPServer instance
HTTPServer srv(new TryRequestHandlerFactory(), svs, pParams);
// start the HTTPServer
srv.start();
// wait for CTRL-C or kill
waitForTerminationRequest();
// Stop the HTTPServer
srv.stop();
return Application::EXIT_OK;
}
};
/*************************************************************************************/
int main(int argc, char** argv)
{
HTTPTryServer app;
return app.run(argc, argv);
}





