Applied Informatics Open Service Platform

OSP Web Server

Contents

Introduction

The Open Service Platform provides a built-in web server that can be extended with static pages and servlet-like request handler objects by any bundle. The web server is implemented in the following three bundles.

OSP Web Server Foundation

The OSP Web Server Foundation bundle (osp.web) provides request dispatching and browser session management. It does not contain the HTTP server itself. Instead, the actual HTTP and HTTPS servers each come in their own bundles.

OSP Web Server

The OSP Web Server bundle (osp.web.server) provides a HTTP server (based on the Poco::Net::HTTPServer class) that uses the features provided by the OSP Web Server Foundation bundle to dispatch incoming requests. Unless configured otherwise, the OSP Web Server is available on TCP port 22080 (http://localhost:22080/).

OSP Secure Web Server

The OSP Secure Web Server bundle (osp.web.server.secure) provides a SSL/TLS-based secure HTTP (HTTPS) server. Like the non-secure web server, it uses the OSP Web Server Foundation bundle to do most of the work.

Since both the non-secure and the secure web server use the OSP Web Server Foundation bundle for the actual request handling, any web pages and request handlers registered with the Web Server Foundation are visible on both web servers.

Unless configured otherwise, the OSP Secure Web Server is available on TCP port 22443 (https://localhost:22443/).

Registering Static Web Pages

The OSP Web Server Foundation bundle provides an extension point named osp.web.server.directory that can be used by a bundle to add its own static web pages and other resources (such as images and style sheets) to the server. A detailed description of the extension point can be found in the documentation for class Poco::OSP::Web::WebServerExtensionPoint.

The WebPage sample (found in OSP/samples/WebPage) shows how a bundle can add static web pages and resources to the web server. The WebPage sample bundle does not contain any code, it simply contains a HTML page (html/index.html, a style sheet (html/css/styles.css) and a few images (html/images/*), as well as an extensions.xml file. The extensions.xml file contains the extension for the osp.web.server.directory extension point:

<extensions>
    <extension point="osp.web.server.directory" 
               path="/sample" 
               resource="html" 
               allowSpecialization="none"
               description="Sample Page"/>
</extensions>

The path attribute specifies the path under which the files provided by the bundle can be accessed on the server. The resource attribute specifies the directory under which the files for the web server can be found in the bundle. For example, the bundle resource html/index.html will be available on the web server under the path /sample/index.html. Using the allowSpecialization attribute, a bundle can specify whether other bundles can register themselves for subdirectories of the directory specified in path. The following values are supported:

The description attribute can be used to provide a textual description of the resource to be found at the path. The path and description attributes can contain references to bundle properties (in the usual form ${property}).

Registering Request Handlers

Registering a request handler is similar to registering static resources. Instead of a path to a bundle resource, the name of a request handler factory class and the name of the library containing it must be specified. The extension point osp.web.server.requesthandler is used for that purpose.

The WebInfo sample (found in OSP/samples/WebInfo) shows how a bundle can add both static web content, as well as a request handler, to the web server.

The extensions.xml file contains the extension for both the osp.web.server.requesthandler and the osp.web.server.directory extension points:

<extensions>
    <extension point="osp.web.server.directory" 
               path="/info/css" 
               resource="css" 
               allowSpecialization="none" 
               hidden="true"/>
    <extension point="osp.web.server.directory" 
               path="/info/images" 
               resource="images" 
               allowSpecialization="none" 
               hidden="true"/>
    <extension point="osp.web.server.requesthandler" 
               path="/info" 
               class="InfoHandlerFactory" 
               library="WebInfo" 
               allowSpecialization="owner" 
               description="OSP Server Information"/>
</extensions>

Instead of the resource attribute used with the osp.web.server.directory extension point, the osp.web.server.requesthandler extension element uses the class and library attributes to specify the name of the class and library containing the request handler factory. Despite containing code, the WebInfo bundle does not contain a bundle activator. The Web Server Foundation automatically finds and loads the class containing the request handler factory from the library in the bundle. For this to work, the shared library containing the request handler factory must provide a named manifest. The name of the manifest must be WebServer. This allows the same library to export a default (unnamed) manifest declaring the bundle activator, as well as a manifest declaring request handler factories.

The implementation of a request handler and its factory usually looks like the following example:

#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/OSP/Web/WebRequestHandlerFactory.h"
#include "Poco/ClassLibrary.h"

using Poco::Net::HTTPRequestHandler;
using Poco::Net::HTTPServerRequest;
using Poco::Net::HTTPServerResponse;

class MyRequestHandler: public HTTPRequestHandler
{
public:
    void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
    {
        response.setChunkedTransferEncoding(true);
        std::ostream& ostr = response.send();

        ostr << "<HTML><HEAD><TITLE>Sample</TITLE>"
                "</HEAD><BODY>"
                "<H1>Hello, world!</H1>"
                "</BODY></HTML>";
    }
};

class MyRequestHandlerFactory: public WebRequestHandlerFactory
{
public:
    HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request)
    {
        return new MyRequestHandler;
    }
};

POCO_BEGIN_NAMED_MANIFEST(WebServer, WebRequestHandlerFactory)
    POCO_EXPORT_CLASS(MyRequestHandlerFactory)
POCO_END_MANIFEST

Authentication and Authorization

The OSP Web Server Foundation supports user authentication and authorization based on HTTP Basic Authorization. For both extension points, two additional attributes, permission and realm can be specified. The permission attribute contains the necessary permission required to access the resource. For more information about permissions, please refer to the OSP Authorization and Authentication documentation. The optional realm attribute specifies name of the realm that is sent back to the browser. Detailed information about HTTP Basic Authentication can be found in RFC 2617.

When a permission is specified for a resource, the web server requires the browser to send user credentials with each request for such a protected resource. The user name/password combination sent by the browser (using HTTP Basic Authentication) is first validated using the Poco::OSP::Auth::AuthService. If successful, the server checks, also using the AuthService, whether the user has the necessary permission.

To protect user names and passwords, HTTP Basic authentication works best when used over an encrypted (HTTPS) connection. The secure attribute can be used to specify that a certain resource is only available over an encrypted connection.

Response Content Compression

For static content stored in bundles, the OSP Web Server Foundation supports gzip compression. If the browser or client indicates that it supports gzip content encoding, by including an appropriate Accept-Encoding header in the request, and if compression is enabled, the response content will be compressed using gzip.

Compression can be enabled for specific content types in the global application configuration file, using the osp.web.server.compressResponses and osp.web.server.compressedMediaTypes properties.

For dynamically generated content, compression has to be implemented in the request handler. The easiest way to do this is to use the following code fragment to send the response:

response.setChunkedTransferEncoding(true);
bool compressResponse(request.hasToken("Accept-Encoding", "gzip"));
if (compressResponse) response.set("Content-Encoding", "gzip");
std::ostream& realResponseStream = response.send();
Poco::DeflatingOutputStream gzipStream(responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1);
std::ostream& responseStream = compressResponse ? gzipStream : realResponseStream;

The POCO C++ Server Page Compiler also has support for response content compression.

Programmatic Access to The Web Server

The OSP Web Server Foundation bundle provides two services to other bundles, the Poco::OSP::Web::WebServerDispatcher and the Poco::OSP::Web::WebSessionManager service.

The WebServerDispatcher Service

The Poco::OSP::Web::WebServerDispatcher service allows a bundle to add static content or request handlers to the web server programmatically. The addVirtualPath() member function can be used to add either static content or a request handler.

The WebSessionManager Service

The Poco::OSP::Web::WebSessionManager service provides HTTP session management to request handlers. Session management allows a request handler to maintain state information between different requests from the same browser session. The state information is maintained using Poco::OSP::Web::WebSession objects, which can store arbitrary name/value pairs. For the value, the Poco::Any class is used, which allows to store values of almost any type.

The WebSession sample (found in OSP/samples/WebSession) shows how to use the Poco::OSP::Web::WebSessionManager and Poco::OSP::Web::WebSession classes.

Configuring The Web Server

The web server can be configured by setting the following properties in the global application configuration file: