Overview
Features
Download
Documentation
Community
Add-Ons & Services

HTTP(S), client/server application

Please post support and help requests here.

HTTP(S), client/server application

Postby ruediger » 11 Jun 2007, 19:48

Dear all,

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;
   
    SharedPtr ptrConsole = new KeyConsoleHandler(false);    // ask the user via console for the pwd
    SharedPtr ptrCert = new ConsoleCertificateHandler(false); // ask the user via console
    SharedPtr ptrContext = 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){
   SharedPtr ptrConsole = new KeyConsoleHandler(true);    // ask the user via console for the pwd
   SharedPtr ptrCert = new ConsoleCertificateHandler(true); // ask the user via console
   SharedPtr ptrContext = 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);
}


ruediger
 
Posts: 3
Joined: 09 Jun 2007, 17:42

Re: HTTP(S), client/server application

Postby peter » 12 Jun 2007, 08:56

> Dear all,
>
> 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 ;-)

Nice to hear that :-) I'll try and make sure you'll stick with POCO ;-)
>

>
> 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.

Yes, definitely. The predefined handlers are for testing only and should never be used in a productive environment. You are on the right track by writing your own KeyArgumentHandler but there were some changes:
If you've read the NetSSL docu at

http://appinf.com/poco/wiki/tiki-index.php?page=NetSSL

you probably discovered some differences.
The POCO_REGISTER_KEYFACTORY macro is deprecated but the new code
isn't yet released (the plan was to release it with 1.3.1 which got delayed a bit).
If you want I can send you the latest source for NetSSL,
simply mail me at

x.y @ appinf.com, x=peter,y=schojer

> is not possible, as POCO_REGISTER_KEYFACTORY(NetSSL_API, KeyArgumentHandler)
> expects a constructor that takes a single bool ??

The changes in the new NetSSL basically get rid of the macro which simply defined
a factory class for each argument handler. Now we use a template for that which basically does the same but it also assumes a one argument constructor.
So if you write your own handler plus a new Factory class which looks like that, you should be fine:

Code: Select all

class MyPrivateKeyFactoryImpl: public Poco::Net::PrivateKeyFactory
{
public;
   MyPrivateKeyFactoryImpl(const std::string& pk):_pk(pk)
   {
   }

   ~MyPrivateKeyFactoryImpl()
   {
   }

   PrivateKeyPassphraseHandler* create(bool server) const
   {
      return new KeyArgumentHandler(pk, server);
   }
private;
      std::string _pk;
};


Register the MyPrivateKeyFactoryImpl:
Code: Select all
   
Poco::Net::SSLManager::instance().privateKeyFactoryMgr().setFactory("KeyArgumentHandler", new MyPrivateKeyFactoryImpl("some string"));


NOTE: this could also work with the old version of NetSSL. Simply give it a try, if it doesn't, I can send you the new code anyway.

> 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 ?


Yes, correct. On the client side you only need a way to find out if the signer of a certificate - the certificate authority - is trusted, typcially such information is stored in a CA store, so no private key is needed. As long as your client does not use a client certificate (for example, there might a scenario where the SERVER forces clients to provide trusted certificates) you won't need a private key at the client side. The server side will always need a private key to load its certificate but it will never send its private key over the network.


>
> 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.


Well, that depends on your clients. If you do have no control over your clients, and use self signed certificates, they will always get a warning message stating that your certificate is not trust worthy.

>
> 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 ?


Yes, create a self-signed root certificate with the openssl tools.

>
> 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 ?


Basically, Boost license means: do what you want with our adn your code. You do not need to contribute back (though enhancements are always welcome :-) ), you do not need to give credits, you can choose whatever license you want for your code, simply use it and don't worry about spending millions for lawyers :-)

br
Peter
peter
 
Posts: 67
Joined: 11 Jul 2006, 16:26
Location: Austria

Re: HTTP(S), client/server application

Postby ruediger » 12 Jun 2007, 14:07

Peter,

thanks for the very comprehensive answer :-)

Best Regards,
Ruediger
ruediger
 
Posts: 3
Joined: 09 Jun 2007, 17:42


Return to Support

Who is online

Users browsing this forum: guenter and 2 guests