diff --git a/ApacheConnector/ApacheConnector_VS71.sln b/ApacheConnector/ApacheConnector_VS71.sln new file mode 100644 index 000000000..f8e4599a0 --- /dev/null +++ b/ApacheConnector/ApacheConnector_VS71.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ApacheConnector", "ApacheConnector_VS71.vcproj", "{9866EE28-0612-4746-BD35-3B15B0AF7267}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + debug_shared = debug_shared + release_shared = release_shared + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {9866EE28-0612-4746-BD35-3B15B0AF7267}.debug_shared.ActiveCfg = debug_shared|Win32 + {9866EE28-0612-4746-BD35-3B15B0AF7267}.debug_shared.Build.0 = debug_shared|Win32 + {9866EE28-0612-4746-BD35-3B15B0AF7267}.release_shared.ActiveCfg = release_shared|Win32 + {9866EE28-0612-4746-BD35-3B15B0AF7267}.release_shared.Build.0 = release_shared|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/ApacheConnector/ApacheConnector_VS71.vcproj b/ApacheConnector/ApacheConnector_VS71.vcproj new file mode 100644 index 000000000..a74d965ee --- /dev/null +++ b/ApacheConnector/ApacheConnector_VS71.vcproj @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ApacheConnector/ApacheConnector_VS80.sln b/ApacheConnector/ApacheConnector_VS80.sln new file mode 100644 index 000000000..f96dbb2a8 --- /dev/null +++ b/ApacheConnector/ApacheConnector_VS80.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ApacheConnector", "ApacheConnector_VS80.vcproj", "{9866EE28-0612-4746-BD35-3B15B0AF7267}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + debug_shared|Win32 = debug_shared|Win32 + release_shared|Win32 = release_shared|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9866EE28-0612-4746-BD35-3B15B0AF7267}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 + {9866EE28-0612-4746-BD35-3B15B0AF7267}.debug_shared|Win32.Build.0 = debug_shared|Win32 + {9866EE28-0612-4746-BD35-3B15B0AF7267}.release_shared|Win32.ActiveCfg = release_shared|Win32 + {9866EE28-0612-4746-BD35-3B15B0AF7267}.release_shared|Win32.Build.0 = release_shared|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ApacheConnector/ApacheConnector_VS80.vcproj b/ApacheConnector/ApacheConnector_VS80.vcproj new file mode 100644 index 000000000..71a289188 --- /dev/null +++ b/ApacheConnector/ApacheConnector_VS80.vcproj @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ApacheConnector/Makefile b/ApacheConnector/Makefile new file mode 100644 index 000000000..181e9d79a --- /dev/null +++ b/ApacheConnector/Makefile @@ -0,0 +1,23 @@ +# +# Makefile +# +# $Id: //poco/Main/ApacheConnector/Makefile#7 $ +# +# Makefile for ApacheConnector +# + +include $(POCO_BASE)/build/rules/global + +SYSFLAGS += -I/usr/include/apache2 -I/usr/include/apr-0 + +objects = ApacheRequestHandlerFactory \ + ApacheServerRequest ApacheServerResponse \ + ApacheStream ApacheConnector ApacheChannel \ + ApacheApplication ApacheChannel + +target = mod_poco +target_version = 1 +target_libs = PocoUtil PocoNet PocoXML PocoFoundation + +include $(POCO_BASE)/build/rules/dylib + diff --git a/ApacheConnector/dependencies b/ApacheConnector/dependencies new file mode 100644 index 000000000..5704ae3ff --- /dev/null +++ b/ApacheConnector/dependencies @@ -0,0 +1,4 @@ +Net +Util +XML +Foundation diff --git a/ApacheConnector/doc/ApacheConnectorUserGuide.page b/ApacheConnector/doc/ApacheConnectorUserGuide.page new file mode 100644 index 000000000..f20e06da0 --- /dev/null +++ b/ApacheConnector/doc/ApacheConnectorUserGuide.page @@ -0,0 +1,148 @@ +POCO ApacheConnector User Guide +ApacheConnector + +!!!Introduction +ApacheConnector (<[mod_poco]>) is an Apache module that allows one to write Apache server extensions using +the POCO Net HTTPServer framework. Almost any subclass of Poco::Net::HTTPRequestHandler written +for Poco::Net::HTTPServer can be used with ApacheConnector. For this to work, the request handler +subclass, together with its factory (Poco::Net::HTTPRequestHandlerFactory) must be contained +in a shared library. The ApacheConnector uses the Poco::ClassLoader to load request handler +factories from shared libraries. + +!!!Adding ApacheConnector to Apache +ApacheConnector is implemented as an ordinary Apache 2 module, named <[mod_poco]>. +To add <[mod_poco]> to Apache, add the following entry to the Apache configuration +file (usually <[httpd.conf]>): + + LoadModule poco_module modules/mod_pocod.so +---- + +!!!Configuring ApacheConnector +ApacheConnector must be able to find shared libraries containing request handler, as well +as optional configuration files. ApacheConnector provides an Poco::Util::Application class +to request handlers that can be used to access configuration data, loaded from configuration +files. + +!!Request Handler Configuration + +To have the ApacheConnector load a request handler class, the <[AddPocoRequestHandler]> directive +is used in the Apache configuration file: + + AddPocoRequestHandler ... +---- + +The first argument specifies the name of the request handler factory class. The second argument +contains the path of the shared library containing the request handler. +The third (and optionally following) argument(s) specify the URI paths handled by the +request handler. For example: + + AddPocoRequestHandler TimeRequestHandlerFactory p:/Poco/ApacheConnector/samples/TimeServer/bin/TimeServerd.dll /time +---- + +loads the TimeRequestHandlerFactory from TimeServerd.dll. Whenever a request for a URI starting with "/time" +is sent by a client, this request will be handled by the TimeRequestHandler. + +!!Configuration Files +ApacheConnector can also load POCO configuration files (.ini, .properties or .xml) for later use by +request handlers. This is done using the <[AddPocoConfig]> directive: + + AddPocoConfig +---- + +where specifies the full path to the configuration file. + +In a request handler, the configuration properties loaded this way can be accessed using: + + Poco::Util::Application& app = Poco::Util::Application::instance(); + std::string myProp = app.config().getString("MyProperty"); +---- + +!!!Logging in Request Handlers +ApacheConnector provides a special logging channel that logs to Apache's error log file. +This channel is set as the root channel when the ApacheConnector is loaded, so every +logger will automatically inherit this channel. + + +!!!A Sample Request Handler +Following is a sample for a request handler implementation. The complete sample project can be found in the +<[samples]> subdirectory of the ApacheConnector directory. + + #include "Poco/Net/HTTPServer.h" + #include "Poco/Net/HTTPRequestHandler.h" + #include "Poco/Net/HTTPRequestHandlerFactory.h" + #include "Poco/Net/HTTPServerRequest.h" + #include "Poco/Net/HTTPServerResponse.h" + #include "Poco/Timestamp.h" + #include "Poco/DateTimeFormatter.h" + #include "Poco/DateTimeFormat.h" + #include "Poco/ClassLibrary.h" + + + using Poco::Net::HTTPRequestHandler; + using Poco::Net::HTTPRequestHandlerFactory; + using Poco::Net::HTTPServerRequest; + using Poco::Net::HTTPServerResponse; + using Poco::Timestamp; + using Poco::DateTimeFormatter; + using Poco::DateTimeFormat; + + + class TimeRequestHandler: public HTTPRequestHandler + /// Return a HTML document with the current date and time. + { + public: + TimeRequestHandler() + { + } + + void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) + { + Timestamp now; + std::string dt(DateTimeFormatter::format(now, DateTimeFormat::SORTABLE_FORMAT)); + + response.setChunkedTransferEncoding(true); + response.setContentType("text/html"); + + std::ostream& ostr = response.send(); + ostr << "TimeServer powered by POCO ApacheConnector"; + ostr << ""; + ostr << "

"; + ostr << dt; + ostr << "

"; + } + }; + + + class TimeRequestHandlerFactory: public HTTPRequestHandlerFactory + { + public: + TimeRequestHandlerFactory() + { + } + + HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request) + { + return new TimeRequestHandler; + } + }; + + + POCO_BEGIN_MANIFEST(HTTPRequestHandlerFactory) + POCO_EXPORT_CLASS(TimeRequestHandlerFactory) + POCO_END_MANIFEST +---- + +Both the TimeRequestHandler class and the TimeRequestHandlerFactory class are the same as for +an ordinary Poco::Net::HTTPServer. The only addition in this sample is the definition +of the class loader manifest, which allows the ApacheConnector to load the TimeRequestHandlerFactory +class from the shared library. + +To run this sample, the following directives must be added to the Apache configuration files: + + LoadModule poco_module p:/Poco/ApacheConnector/bin/mod_poco.so + AddPocoRequestHandler TimeRequestHandlerFactory p:/Poco/ApacheConnector/samples/TimeServer/bin/TimeServer.dll /time +---- + +You'll have to change the paths to <[mod_poco.so]> and <[TimeServer.dll]> to match your +own environment. +To test the sample, simply direct your favorite web browser to . diff --git a/ApacheConnector/include/ApacheApplication.h b/ApacheConnector/include/ApacheApplication.h new file mode 100644 index 000000000..cf08f21cf --- /dev/null +++ b/ApacheConnector/include/ApacheApplication.h @@ -0,0 +1,60 @@ +// +// ApacheApplication.h +// +// $Id: //poco/Main/ApacheConnector/include/ApacheApplication.h#2 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#ifndef ApacheConnector_ApacheApplication_INCLUDED +#define ApacheConnector_ApacheApplication_INCLUDED + + +#include "ApacheRequestHandlerFactory.h" +#include "Poco/Util/Application.h" +#include "Poco/Mutex.h" + + +class ApacheApplication: public Poco::Util::Application +{ +public: + ApacheApplication(); + /// Creates the ApacheApplication and sets the + /// ApacheChannel as the root logger channel. + + ~ApacheApplication(); + /// Destroys the ApacheApplication. + + void setup(); + /// Initializes the application if called for the first + /// time; does nothing in later calls. + + ApacheRequestHandlerFactory& factory(); + /// Returns the ApacheRequestHandlerFactory. + + static ApacheApplication& instance(); + /// Returns the application instance. + +private: + bool _ready; + ApacheRequestHandlerFactory _factory; + Poco::FastMutex _mutex; +}; + + +// +// inlines +// +inline ApacheRequestHandlerFactory& ApacheApplication::factory() +{ + return _factory; +} + + +#endif // ApacheConnector_ApacheApplication_INCLUDED diff --git a/ApacheConnector/include/ApacheChannel.h b/ApacheConnector/include/ApacheChannel.h new file mode 100644 index 000000000..128f6ebc3 --- /dev/null +++ b/ApacheConnector/include/ApacheChannel.h @@ -0,0 +1,34 @@ +// +// ApacheChannel.h +// +// $Id: //poco/Main/ApacheConnector/include/ApacheChannel.h#1 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#ifndef ApacheConnector_ApacheChannel_INCLUDED +#define ApacheConnector_ApacheChannel_INCLUDED + + +#include "Poco/Channel.h" + + +class ApacheChannel: public Poco::Channel + /// This class implements a logging channel + /// that uses the Apache logging facilities. +{ +public: + ApacheChannel(); + ~ApacheChannel(); + + void log(const Poco::Message& msg); +}; + + +#endif // ApacheConnector_ApacheChannel_INCLUDED diff --git a/ApacheConnector/include/ApacheConnector.h b/ApacheConnector/include/ApacheConnector.h new file mode 100644 index 000000000..aeb8ec489 --- /dev/null +++ b/ApacheConnector/include/ApacheConnector.h @@ -0,0 +1,90 @@ +// +// ApacheConnector.h +// +// $Id: //poco/Main/ApacheConnector/include/ApacheConnector.h#3 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#ifndef ApacheConnector_ApacheConnector_INCLUDED +#define ApacheConnector_ApacheConnector_INCLUDED + + +#include + + +struct request_rec; +class ApacheServerRequest; + + +class ApacheRequestRec + /// This class wraps an Apache request_rec. +{ +public: + ApacheRequestRec(request_rec* _pRec); + /// Creates the ApacheRequestRec; + + bool haveRequestBody(); + /// Returns true if the request contains a body. + + int readRequest(char* buffer, int length); + /// Read up to length bytes from request body into buffer. + /// Returns the number of bytes read, 0 if eof or -1 if an error occured. + + void writeResponse(const char* buffer, int length); + /// Writes the given characters as response to the given request_rec. + + void addHeader(const std::string& key, const std::string& value); + /// Adds the given key / value pair to the outgoing headers of the + /// http response. + + void setContentType(const std::string& mediaType); + /// Sets the response content type. + + void redirect(const std::string& uri); + /// Redirects the response to the given uri. + + void sendErrorResponse(int status); + /// Sends an error response with the given HTTP status code. + + int sendFile(const std::string& path, unsigned int fileSize, const std::string& mediaType); + /// Sends the file given by fileName as response. + + void copyHeaders(ApacheServerRequest& request); + /// Copies the request uri and header fields from the Apache request + /// to the ApacheServerRequest. + +private: + request_rec* _pRec; +}; + + +class ApacheConnector + /// This class provides static methods wrapping the + /// Apache API. +{ +public: + enum LogLevel + { + PRIO_FATAL = 1, /// A fatal error. The application will most likely terminate. This is the highest priority. + PRIO_CRITICAL, /// A critical error. The application might not be able to continue running successfully. + PRIO_ERROR, /// An error. An operation did not complete successfully, but the application as a whole is not affected. + PRIO_WARNING, /// A warning. An operation completed with an unexpected result. + PRIO_NOTICE, /// A notice, which is an information with just a higher priority. + PRIO_INFORMATION, /// An informational message, usually denoting the successful completion of an operation. + PRIO_DEBUG, /// A debugging message. + PRIO_TRACE /// A tracing message. This is the lowest priority. + }; + + static void log(const char* file, int line, int level, int status, const char* text); + /// Log the given message. +}; + + +#endif // ApacheConnector_ApacheConnector_INCLUDED diff --git a/ApacheConnector/include/ApacheRequestHandlerFactory.h b/ApacheConnector/include/ApacheRequestHandlerFactory.h new file mode 100644 index 000000000..9769dadd4 --- /dev/null +++ b/ApacheConnector/include/ApacheRequestHandlerFactory.h @@ -0,0 +1,59 @@ +// +// ApacheRequestHandlerFactory.h +// +// $Id: //poco/Main/ApacheConnector/include/ApacheRequestHandlerFactory.h#5 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#ifndef ApacheConnector_ApacheRequestHandlerFactory_INCLUDED +#define ApacheConnector_ApacheRequestHandlerFactory_INCLUDED + + +#include "ApacheServerRequest.h" +#include "Poco/Net/HTTPRequestHandlerFactory.h" +#include "Poco/ClassLoader.h" +#include "Poco/Mutex.h" +#include + + +class ApacheRequestHandlerFactory: public Poco::Net::HTTPRequestHandlerFactory +{ +public: + ApacheRequestHandlerFactory(); + /// Constructs the ApacheRequestHandlerFactory + + ~ApacheRequestHandlerFactory(); + /// Destructor of the ApacheRequestHandlerFactory + + Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request); + /// Creates a new request handler for the given HTTP request. + + bool mustHandle(const std::string& uri); + /// Returns 1 if the given uri must be handled by the + /// poco_mapper module, 0 otherwise. + + void handleURIs(const std::string& uris); + /// Parses the given string for dllName, factoryName and the URIs to handle + /// by the request-handler + + void addRequestHandlerFactory(const std::string& dllPath, const std::string& factoryName, const std::string& uri); + /// Adds the request handler from the given dll with the given name and + /// registers that handler with the given uri + +private: + typedef std::map RequestHandlerFactories; + + RequestHandlerFactories _requestHandlers; + Poco::ClassLoader _loader; + Poco::FastMutex _mutex; +}; + + +#endif // ApacheConnector_ApacheRequestHandlerFactory_INCLUDED diff --git a/ApacheConnector/include/ApacheServerRequest.h b/ApacheConnector/include/ApacheServerRequest.h new file mode 100644 index 000000000..0671e88ca --- /dev/null +++ b/ApacheConnector/include/ApacheServerRequest.h @@ -0,0 +1,102 @@ +// +// ApacheServerRequest.h +// +// $Id: //poco/Main/ApacheConnector/include/ApacheServerRequest.h#6 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#ifndef ApacheConnector_ApacheServerRequest_INCLUDED +#define ApacheConnector_ApacheServerRequest_INCLUDED + + +#include "ApacheConnector.h" +#include "ApacheStream.h" +#include "Poco/Net/HTTPServerRequest.h" +#include + + +class ApacheServerResponse; + + +class ApacheServerRequest: public Poco::Net::HTTPServerRequest +{ +public: + ApacheServerRequest( + ApacheRequestRec* pApacheRequest, + const char* serverName, + int serverPort, + const char* clientName, + int clientPort); + /// Creates a new ApacheServerRequest. + + ~ApacheServerRequest(); + /// Destroys the ApacheServerRequest. + + std::istream& stream(); + /// Returns the input stream for reading + /// the request body. + /// + /// The stream is valid until the HTTPServerRequest + /// object is destroyed. + + bool expectContinue() const; + /// Returns true if the client expects a + /// 100 Continue response. + + const Poco::Net::SocketAddress& clientAddress() const; + /// Returns the client's address. + + const Poco::Net::SocketAddress& serverAddress() const; + /// Returns the server's address. + + const Poco::Net::HTTPServerParams& serverParams() const; + /// Returns a reference to the server parameters. + + Poco::Net::HTTPServerResponse& response() const; + /// Returns a reference to the associated response + +protected: + void setResponse(ApacheServerResponse* pResponse); + +private: + ApacheRequestRec* _pApacheRequest; + ApacheServerResponse* _pResponse; + ApacheInputStream* _pStream; + Poco::Net::SocketAddress _serverAddress; + Poco::Net::SocketAddress _clientAddress; + + friend class ApacheServerResponse; +}; + + +// +// inlines +// +inline std::istream& ApacheServerRequest::stream() +{ + poco_check_ptr (_pStream); + + return *_pStream; +} + + +inline const Poco::Net::SocketAddress& ApacheServerRequest::clientAddress() const +{ + return _clientAddress; +} + + +inline const Poco::Net::SocketAddress& ApacheServerRequest::serverAddress() const +{ + return _serverAddress; +} + + +#endif // ApacheConnector_ApacheServerRequest_INCLUDED diff --git a/ApacheConnector/include/ApacheServerResponse.h b/ApacheConnector/include/ApacheServerResponse.h new file mode 100644 index 000000000..46516f648 --- /dev/null +++ b/ApacheConnector/include/ApacheServerResponse.h @@ -0,0 +1,124 @@ +// +// ApacheServerResponse.h +// +// $Id: //poco/Main/ApacheConnector/include/ApacheServerResponse.h#6 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#ifndef ApacheConnector_ApacheServerResponse_INCLUDED +#define ApacheConnector_ApacheServerResponse_INCLUDED + + +#include "ApacheConnector.h" +#include "ApacheStream.h" +#include "Poco/Net/Net.h" +#include "Poco/Net/HTTPServerResponse.h" + + +class ApacheServerRequest; + + +class ApacheServerResponse: public Poco::Net::HTTPServerResponse + /// This subclass of HTTPResponse is used for + /// representing server-side HTTP responses for apache. + /// + /// A ApacheServerResponse is passed to the + /// handleRequest() method of HTTPRequestHandler. + /// + /// handleRequest() must set a status code + /// and optional reason phrase, set headers + /// as necessary, and provide a message body. +{ +public: + ApacheServerResponse(ApacheServerRequest* pRequest); + /// Creates the ApacheServerResponse. + + ~ApacheServerResponse(); + /// Destroys the ApacheServerResponse. + + void sendContinue(); + /// Sends a 100 Continue response to the + /// client. + + void sendErrorResponse(int status); + /// Sends an error response with the given + /// status back to the client. + + std::ostream& send(); + /// Sends the response header to the client and + /// returns an output stream for sending the + /// response body. + /// + /// The returned stream is valid until the response + /// object is destroyed. + /// + /// Must not be called after sendFile(), sendBuffer() + /// or redirect() has been called. + + void sendFile(const std::string& path, const std::string& mediaType); + /// Sends the response header to the client, followed + /// by the content of the given file. + /// + /// Must not be called after send(), sendBuffer() + /// or redirect() has been called. + /// + /// Throws a FileNotFoundException if the file + /// cannot be found, or an OpenFileException if + /// the file cannot be opened. + + void sendBuffer(const void* pBuffer, std::size_t length); + /// Sends the response header to the client, followed + /// by the contents of the given buffer. + /// + /// The Content-Length header of the response is set + /// to length and chunked transfer encoding is disabled. + /// + /// If both the HTTP message header and body (from the + /// given buffer) fit into one single network packet, the + /// complete response can be sent in one network packet. + /// + /// Must not be called after send(), sendFile() + /// or redirect() has been called. + + void redirect(const std::string& uri); + /// Sets the status code to 302 (Found) + /// and sets the "Location" header field + /// to the given URI, which according to + /// the HTTP specification, must be absolute. + /// + /// Must not be called after send() has been called. + + void requireAuthentication(const std::string& realm); + /// Sets the status code to 401 (Unauthorized) + /// and sets the "WWW-Authenticate" header field + /// according to the given realm. + + bool sent() const; + /// Returns true if the response (header) has been sent. + +private: + void initApacheOutputStream(); + /// Initializes the ApacheOutputStram + + ApacheOutputStream* _pStream; + ApacheRequestRec* _pApacheRequest; +}; + + +// +// inlines +// +inline bool ApacheServerResponse::sent() const +{ + return _pStream != 0; +} + + +#endif // ApacheConnector_ApacheServerResponse_INCLUDED diff --git a/ApacheConnector/include/ApacheStream.h b/ApacheConnector/include/ApacheStream.h new file mode 100644 index 000000000..3fc8089fc --- /dev/null +++ b/ApacheConnector/include/ApacheStream.h @@ -0,0 +1,107 @@ +// +// ApacheStream.h +// +// $Id: //poco/Main/ApacheConnector/include/ApacheStream.h#5 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#ifndef ApacheConnector_ApacheStream_INCLUDED +#define ApacheConnector_ApacheStream_INCLUDED + + +#include "ApacheConnector.h" +#include "Poco/BufferedStreamBuf.h" +#include +#include + + +class ApacheStreamBuf: public Poco::BufferedStreamBuf + /// This is the streambuf class used for reading from and writing to a socket. +{ +public: + ApacheStreamBuf(ApacheRequestRec* pApacheRequest, bool haveData = false); + /// Creates a ApacheStreamBuf with the given socket. + + ~ApacheStreamBuf(); + /// Destroys the SocketStreamBuf. + +protected: + int readFromDevice(char* buffer, std::streamsize length); + int writeToDevice(const char* buffer, std::streamsize length); + +private: + enum + { + STREAM_BUFFER_SIZE = 1024 + }; + + ApacheRequestRec* _pApacheRequest; + bool _haveData; +}; + + +class ApacheIOS: public virtual std::ios + /// The base class for ApacheStream, ApacheInputStream and + /// ApacheOutputStream. + /// + /// This class is needed to ensure the correct initialization + /// order of the stream buffer and base classes. +{ +public: + ApacheIOS(ApacheRequestRec* pApacheRequest, bool haveData = false); + /// Creates the ApacheIOS with the given socket. + + ~ApacheIOS(); + /// Destroys the ApacheIOS. + /// + /// Flushes the buffer, but does not close the socket. + + ApacheStreamBuf* rdbuf(); + /// Returns a pointer to the internal ApacheStreamBuf. + + void close(); + /// Flushes the stream. + +protected: + ApacheStreamBuf _buf; +}; + + +class ApacheOutputStream: public ApacheIOS, public std::ostream + /// An output stream for writing to an Apache response. +{ +public: + ApacheOutputStream(ApacheRequestRec* pApacheRequest); + /// Creates the ApacheOutputStream with the given socket. + + ~ApacheOutputStream(); + /// Destroys the ApacheOutputStream. + /// + /// Flushes the buffer. +}; + + +class ApacheInputStream: public ApacheIOS, public std::istream + /// An input stream for reading from an Apache request. + /// + /// Using formatted input from a ApacheInputStream + /// is not recommended, due to the read-ahead behavior of + /// istream with formatted reads. +{ +public: + ApacheInputStream(ApacheRequestRec* pApacheRequest); + /// Creates the ApacheInputStream with the given socket. + + ~ApacheInputStream(); + /// Destroys the ApacheInputStream. +}; + + +#endif // ApacheConnector_ApacheStream_INCLUDED diff --git a/ApacheConnector/samples/FormServer/FormServer_vs71.vcproj b/ApacheConnector/samples/FormServer/FormServer_vs71.vcproj new file mode 100644 index 000000000..b08085081 --- /dev/null +++ b/ApacheConnector/samples/FormServer/FormServer_vs71.vcproj @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ApacheConnector/samples/FormServer/FormServer_vs80.vcproj b/ApacheConnector/samples/FormServer/FormServer_vs80.vcproj new file mode 100644 index 000000000..ce671367c --- /dev/null +++ b/ApacheConnector/samples/FormServer/FormServer_vs80.vcproj @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ApacheConnector/samples/FormServer/Makefile b/ApacheConnector/samples/FormServer/Makefile new file mode 100644 index 000000000..ae3db3330 --- /dev/null +++ b/ApacheConnector/samples/FormServer/Makefile @@ -0,0 +1,17 @@ +# +# Makefile +# +# $Id: //poco/Main/ApacheConnector/samples/FormServer/Makefile#1 $ +# +# Makefile for Poco ApacheConnector sample +# + +include $(POCO_BASE)/build/rules/global + +objects = FormServer + +target = FormServer +target_version = 1 +target_libs = PocoFoundation PocoNet + +include $(POCO_BASE)/build/rules/dylib diff --git a/ApacheConnector/samples/FormServer/src/FormServer.cpp b/ApacheConnector/samples/FormServer/src/FormServer.cpp new file mode 100644 index 000000000..c5d83e5c3 --- /dev/null +++ b/ApacheConnector/samples/FormServer/src/FormServer.cpp @@ -0,0 +1,188 @@ +// +// FormServer.cpp +// +// $Id: //poco/Main/ApacheConnector/samples/FormServer/src/FormServer.cpp#2 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#include "Poco/Net/HTTPServer.h" +#include "Poco/Net/HTTPRequestHandler.h" +#include "Poco/Net/HTTPRequestHandlerFactory.h" +#include "Poco/Net/HTTPServerRequest.h" +#include "Poco/Net/HTTPServerResponse.h" +#include "Poco/Net/HTMLForm.h" +#include "Poco/Net/PartHandler.h" +#include "Poco/CountingStream.h" +#include "Poco/NullStream.h" +#include "Poco/StreamCopier.h" +#include "Poco/ClassLibrary.h" + + +using Poco::Net::HTTPRequestHandler; +using Poco::Net::HTTPRequestHandlerFactory; +using Poco::Net::HTTPServerRequest; +using Poco::Net::HTTPServerResponse; +using Poco::Net::MessageHeader; +using Poco::Net::HTMLForm; +using Poco::Net::NameValueCollection; +using Poco::CountingInputStream; +using Poco::NullOutputStream; +using Poco::StreamCopier; + + +class MyPartHandler: public Poco::Net::PartHandler +{ +public: + MyPartHandler(): + _length(0) + { + } + + void handlePart(const MessageHeader& header, std::istream& stream) + { + _type = header.get("Content-Type", "(unspecified)"); + if (header.has("Content-Disposition")) + { + std::string disp; + NameValueCollection params; + MessageHeader::splitParameters(header["Content-Disposition"], disp, params); + _name = params.get("name", "(unnamed)"); + _fileName = params.get("filename", "(unnamed)"); + } + + CountingInputStream istr(stream); + NullOutputStream ostr; + StreamCopier::copyStream(istr, ostr); + _length = istr.chars(); + } + + int length() const + { + return _length; + } + + const std::string& name() const + { + return _name; + } + + const std::string& fileName() const + { + return _fileName; + } + + const std::string& contentType() const + { + return _type; + } + +private: + int _length; + std::string _type; + std::string _name; + std::string _fileName; +}; + + +class FormRequestHandler: public HTTPRequestHandler + /// Return a HTML document with the current date and time. +{ +public: + FormRequestHandler() + { + } + + void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) + { + MyPartHandler partHandler; + HTMLForm form(request, request.stream(), partHandler); + + response.setChunkedTransferEncoding(true); + response.setContentType("text/html"); + + std::ostream& ostr = response.send(); + + ostr << + "\n" + "\n" + "POCO Form Server Sample\n" + "\n" + "\n" + "

POCO Form Server Sample

\n" + "

GET Form

\n" + "
\n" + "\n" + "\n" + "
\n" + "

POST Form

\n" + "
\n" + "\n" + "\n" + "
\n" + "

File Upload

\n" + "
\n" + " \n" + "\n" + "
\n"; + + ostr << "

Request

\n"; + ostr << "Method: " << request.getMethod() << "
\n"; + ostr << "URI: " << request.getURI() << "
\n"; + NameValueCollection::ConstIterator it = request.begin(); + NameValueCollection::ConstIterator end = request.end(); + for (; it != end; ++it) + { + ostr << it->first << ": " << it->second << "
\n"; + } + ostr << "

"; + + if (!form.empty()) + { + ostr << "

Form

\n"; + it = form.begin(); + end = form.end(); + for (; it != end; ++it) + { + ostr << it->first << ": " << it->second << "
\n"; + } + ostr << "

"; + } + + if (!partHandler.name().empty()) + { + ostr << "

Upload

\n"; + ostr << "Name: " << partHandler.name() << "
\n"; + ostr << "File Name: " << partHandler.fileName() << "
\n"; + ostr << "Type: " << partHandler.contentType() << "
\n"; + ostr << "Size: " << partHandler.length() << "
\n"; + ostr << "

"; + } + ostr << "\n"; + } +}; + + +class FormRequestHandlerFactory: public HTTPRequestHandlerFactory +{ +public: + FormRequestHandlerFactory() + { + } + + HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request) + { + return new FormRequestHandler; + } +}; + + +POCO_BEGIN_MANIFEST(HTTPRequestHandlerFactory) + POCO_EXPORT_CLASS(FormRequestHandlerFactory) +POCO_END_MANIFEST diff --git a/ApacheConnector/samples/Makefile b/ApacheConnector/samples/Makefile new file mode 100644 index 000000000..f04d2ecf8 --- /dev/null +++ b/ApacheConnector/samples/Makefile @@ -0,0 +1,13 @@ +# +# Makefile +# +# $Id: //poco/Main/ApacheConnector/samples/Makefile#1 $ +# +# Makefile for Poco ApacheConnector Samples +# + +.PHONY: projects +clean all: projects +projects: + $(MAKE) -C TimeServer $(MAKECMDGOALS) + $(MAKE) -C FormServer $(MAKECMDGOALS) diff --git a/ApacheConnector/samples/TimeServer/Makefile b/ApacheConnector/samples/TimeServer/Makefile new file mode 100644 index 000000000..be171bb9e --- /dev/null +++ b/ApacheConnector/samples/TimeServer/Makefile @@ -0,0 +1,17 @@ +# +# Makefile +# +# $Id: //poco/Main/ApacheConnector/samples/TimeServer/Makefile#1 $ +# +# Makefile for Poco ApacheConnector sample +# + +include $(POCO_BASE)/build/rules/global + +objects = TimeServer + +target = TimeServer +target_version = 1 +target_libs = PocoFoundation PocoNet + +include $(POCO_BASE)/build/rules/dylib diff --git a/ApacheConnector/samples/TimeServer/TimeServer_vs71.vcproj b/ApacheConnector/samples/TimeServer/TimeServer_vs71.vcproj new file mode 100644 index 000000000..81e4c1fd0 --- /dev/null +++ b/ApacheConnector/samples/TimeServer/TimeServer_vs71.vcproj @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ApacheConnector/samples/TimeServer/TimeServer_vs80.vcproj b/ApacheConnector/samples/TimeServer/TimeServer_vs80.vcproj new file mode 100644 index 000000000..e5205c565 --- /dev/null +++ b/ApacheConnector/samples/TimeServer/TimeServer_vs80.vcproj @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ApacheConnector/samples/TimeServer/src/TimeServer.cpp b/ApacheConnector/samples/TimeServer/src/TimeServer.cpp new file mode 100644 index 000000000..0f734683e --- /dev/null +++ b/ApacheConnector/samples/TimeServer/src/TimeServer.cpp @@ -0,0 +1,77 @@ +// +// TimeServer.cpp +// +// $Id: //poco/Main/ApacheConnector/samples/TimeServer/src/TimeServer.cpp#1 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#include "Poco/Net/HTTPServer.h" +#include "Poco/Net/HTTPRequestHandler.h" +#include "Poco/Net/HTTPRequestHandlerFactory.h" +#include "Poco/Net/HTTPServerRequest.h" +#include "Poco/Net/HTTPServerResponse.h" +#include "Poco/Timestamp.h" +#include "Poco/DateTimeFormatter.h" +#include "Poco/DateTimeFormat.h" +#include "Poco/ClassLibrary.h" + + +using Poco::Net::HTTPRequestHandler; +using Poco::Net::HTTPRequestHandlerFactory; +using Poco::Net::HTTPServerRequest; +using Poco::Net::HTTPServerResponse; +using Poco::Timestamp; +using Poco::DateTimeFormatter; +using Poco::DateTimeFormat; + + +class TimeRequestHandler: public HTTPRequestHandler + /// Return a HTML document with the current date and time. +{ +public: + TimeRequestHandler() + { + } + + void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) + { + Timestamp now; + std::string dt(DateTimeFormatter::format(now, DateTimeFormat::SORTABLE_FORMAT)); + + response.setChunkedTransferEncoding(true); + response.setContentType("text/html"); + + std::ostream& ostr = response.send(); + ostr << "TimeServer powered by POCO ApacheConnector"; + ostr << ""; + ostr << "

"; + ostr << dt; + ostr << "

"; + } +}; + + +class TimeRequestHandlerFactory: public HTTPRequestHandlerFactory +{ +public: + TimeRequestHandlerFactory() + { + } + + HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request) + { + return new TimeRequestHandler; + } +}; + + +POCO_BEGIN_MANIFEST(HTTPRequestHandlerFactory) + POCO_EXPORT_CLASS(TimeRequestHandlerFactory) +POCO_END_MANIFEST diff --git a/ApacheConnector/samples/dependencies b/ApacheConnector/samples/dependencies new file mode 100644 index 000000000..5704ae3ff --- /dev/null +++ b/ApacheConnector/samples/dependencies @@ -0,0 +1,4 @@ +Net +Util +XML +Foundation diff --git a/ApacheConnector/samples/samples_vs71.sln b/ApacheConnector/samples/samples_vs71.sln new file mode 100644 index 000000000..ed6c79d0f --- /dev/null +++ b/ApacheConnector/samples/samples_vs71.sln @@ -0,0 +1,39 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_vs71.vcproj", "{7720D4EF-F5DD-4265-91C5-83980CB70B84}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FormServer", "FormServer\FormServer_vs71.vcproj", "{198BFE74-AD16-4D8B-81F7-F700B3B6456F}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + debug_shared = debug_shared + debug_static = debug_static + release_shared = release_shared + release_static = release_static + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.debug_shared.ActiveCfg = debug_shared|Win32 + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.debug_shared.Build.0 = debug_shared|Win32 + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.debug_static.ActiveCfg = debug_shared|Win32 + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.debug_static.Build.0 = debug_shared|Win32 + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.release_shared.ActiveCfg = release_shared|Win32 + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.release_shared.Build.0 = release_shared|Win32 + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.release_static.ActiveCfg = release_shared|Win32 + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.release_static.Build.0 = release_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.debug_shared.ActiveCfg = debug_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.debug_shared.Build.0 = debug_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.debug_static.ActiveCfg = debug_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.debug_static.Build.0 = debug_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.release_shared.ActiveCfg = release_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.release_shared.Build.0 = release_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.release_static.ActiveCfg = release_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.release_static.Build.0 = release_shared|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/ApacheConnector/samples/samples_vs80.sln b/ApacheConnector/samples/samples_vs80.sln new file mode 100644 index 000000000..314434083 --- /dev/null +++ b/ApacheConnector/samples/samples_vs80.sln @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeServer", "TimeServer\TimeServer_vs80.vcproj", "{7720D4EF-F5DD-4265-91C5-83980CB70B84}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FormServer", "FormServer\FormServer_vs80.vcproj", "{198BFE74-AD16-4D8B-81F7-F700B3B6456F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + debug_shared|Win32 = debug_shared|Win32 + release_shared|Win32 = release_shared|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.debug_shared|Win32.Build.0 = debug_shared|Win32 + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.release_shared|Win32.ActiveCfg = release_shared|Win32 + {7720D4EF-F5DD-4265-91C5-83980CB70B84}.release_shared|Win32.Build.0 = release_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.debug_shared|Win32.Build.0 = debug_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.release_shared|Win32.ActiveCfg = release_shared|Win32 + {198BFE74-AD16-4D8B-81F7-F700B3B6456F}.release_shared|Win32.Build.0 = release_shared|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ApacheConnector/src/ApacheApplication.cpp b/ApacheConnector/src/ApacheApplication.cpp new file mode 100644 index 000000000..167fdd337 --- /dev/null +++ b/ApacheConnector/src/ApacheApplication.cpp @@ -0,0 +1,57 @@ +// +// ApacheApplication.cpp +// +// $Id: //poco/Main/ApacheConnector/src/ApacheApplication.cpp#2 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#include "ApacheApplication.h" +#include "ApacheChannel.h" +#include "Poco/Logger.h" +#include "Poco/SingletonHolder.h" +#include + + +using Poco::Logger; +using Poco::FastMutex; + + +ApacheApplication::ApacheApplication(): + _ready(false) +{ + Logger::root().setChannel(new ApacheChannel); +} + + +ApacheApplication::~ApacheApplication() +{ + Logger::shutdown(); +} + + +void ApacheApplication::setup() +{ + FastMutex::ScopedLock lock(_mutex); + + if (!_ready) + { + std::vector cmdLine; + cmdLine.push_back("mod_poco"); + init(cmdLine); + _ready = true; + } +} + + +ApacheApplication& ApacheApplication::instance() +{ + static Poco::SingletonHolder sh; + return *sh.get(); +} diff --git a/ApacheConnector/src/ApacheChannel.cpp b/ApacheConnector/src/ApacheChannel.cpp new file mode 100644 index 000000000..cd03f9013 --- /dev/null +++ b/ApacheConnector/src/ApacheChannel.cpp @@ -0,0 +1,33 @@ +// +// ApacheApplication.cpp +// +// $Id: //poco/Main/ApacheConnector/src/ApacheChannel.cpp#1 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#include "ApacheChannel.h" +#include "ApacheConnector.h" +#include "Poco/Message.h" + + +ApacheChannel::ApacheChannel() +{ +} + + +ApacheChannel::~ApacheChannel() +{ +} + + +void ApacheChannel::log(const Poco::Message& msg) +{ + ApacheConnector::log(msg.getSource().c_str(), 0, msg.getPriority(), 0, msg.getText().c_str()); +} diff --git a/ApacheConnector/src/ApacheConnector.cpp b/ApacheConnector/src/ApacheConnector.cpp new file mode 100644 index 000000000..9b2094f8b --- /dev/null +++ b/ApacheConnector/src/ApacheConnector.cpp @@ -0,0 +1,290 @@ +// +// ApacheConnector.cpp +// +// $Id: //poco/Main/ApacheConnector/src/ApacheConnector.cpp#6 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#include "ApacheConnector.h" +#include "ApacheApplication.h" +#include "ApacheServerRequest.h" +#include "ApacheServerResponse.h" +#include "ApacheRequestHandlerFactory.h" +#include "Poco/Net/HTTPRequestHandler.h" +#include "httpd.h" +#include "http_connection.h" +#include "http_config.h" +#include "http_core.h" +#include "http_protocol.h" +#include "http_log.h" +#include "apr.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_buckets.h" +#include "apr_file_info.h" +#include "apr_hash.h" +#define APR_WANT_STRFUNC +#include "apr_want.h" +#include "http_request.h" +#include "util_filter.h" + + +using Poco::Net::HTTPServerRequest; +using Poco::Net::HTTPServerResponse; +using Poco::Net::HTTPRequestHandler; +using Poco::Net::HTTPResponse; + + +extern "C" module AP_MODULE_DECLARE_DATA poco_module; + + +ApacheRequestRec::ApacheRequestRec(request_rec* pRec): + _pRec(pRec) +{ +} + + +bool ApacheRequestRec::haveRequestBody() +{ + return ap_should_client_block(_pRec) != 0; +} + + +int ApacheRequestRec::readRequest(char* buffer, int length) +{ + return ap_get_client_block(_pRec, buffer, length); +} + + +void ApacheRequestRec::writeResponse(const char* buffer, int length) +{ + ap_rwrite(buffer, length, _pRec); +} + + +void ApacheRequestRec::redirect(const std::string& uri) +{ + apr_table_set(_pRec->headers_out, "Location", uri.c_str()); + _pRec->connection->keepalive = AP_CONN_CLOSE; + _pRec->status = 302; + ap_set_keepalive(_pRec); + ap_send_error_response(_pRec, 0); +} + + +void ApacheRequestRec::sendErrorResponse(int status) +{ + _pRec->connection->keepalive = AP_CONN_CLOSE; + _pRec->status = status; + ap_set_keepalive(_pRec); + + ap_send_error_response(_pRec, 0); +} + + +void ApacheRequestRec::addHeader(const std::string& key, const std::string& value) +{ + const apr_array_header_t *arr = apr_table_elts(_pRec->headers_out); + apr_table_add(const_cast(reinterpret_cast(arr)), key.c_str(), value.c_str()); +} + + +void ApacheRequestRec::setContentType(const std::string& mediaType) +{ + ap_set_content_type(_pRec, mediaType.c_str()); +} + + +int ApacheRequestRec::sendFile(const std::string& path, unsigned int fileSize, const std::string& mediaType) +{ + apr_file_t *thefile = 0; + apr_finfo_t finfo; + apr_size_t nBytes; + + // setting content-type + ap_set_content_type(_pRec, mediaType.c_str()); + + // opening file + if (apr_file_open(&thefile, path.c_str(), APR_READ, APR_UREAD | APR_GREAD, _pRec->pool) == APR_SUCCESS) + { + // getting fileinfo + apr_file_info_get(&finfo, APR_FINFO_NORM, thefile); + + // setting last-updated & co + ap_update_mtime(_pRec, finfo.mtime); + ap_set_last_modified(_pRec); + ap_set_content_length(_pRec, fileSize); + + // sending file + ap_send_fd(thefile, _pRec, 0, fileSize, &nBytes); + + // well done + return 0; + } + + // file not opened successfully -> produce an exception in C++ code + return 1; +} + + +void ApacheRequestRec::copyHeaders(ApacheServerRequest& request) +{ + const apr_array_header_t* arr = apr_table_elts(_pRec->headers_in); + const apr_table_entry_t* elts = (const apr_table_entry_t *)arr->elts; + + request.setMethod(_pRec->method); + request.setURI(_pRec->unparsed_uri); + + // iterating over raw-headers and printing them + for (int i = 0; i < arr->nelts; i++) + { + request.add(elts[i].key, elts[i].val); + } +} + + +void ApacheConnector::log(const char* file, int line, int level, int status, const char *text) +{ + ap_log_error(file, line, level, 0, NULL, text); +} + + +extern "C" int ApacheConnector_handler(request_rec *r) +{ + ApacheRequestRec rec(r); + ApacheApplication& app(ApacheApplication::instance()); + + try + { + // ensure application is ready + app.setup(); + + // if the ApacheRequestHandler declines handling - we stop + // request handling here and let other modules do their job! + if (!app.factory().mustHandle(r->uri)) + return DECLINED; + + apr_status_t rv; + if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) + return rv; + + std::auto_ptr pRequest(new ApacheServerRequest( + &rec, + r->connection->local_ip, + r->connection->local_addr->port, + r->connection->remote_ip, + r->connection->remote_addr->port)); + + std::auto_ptr pResponse(new ApacheServerResponse(pRequest.get())); + + // add header information to request + rec.copyHeaders(*pRequest); + + try + { + std::auto_ptr pHandler(app.factory().createRequestHandler(*pRequest)); + + if (pHandler.get()) + { + pHandler->handleRequest(*pRequest, *pResponse); + } + else + { + pResponse->sendErrorResponse(HTTP_NOT_IMPLEMENTED); + } + } + catch (...) + { + pResponse->sendErrorResponse(HTTP_INTERNAL_SERVER_ERROR); + throw; + } + } + catch (Poco::Exception& exc) + { + ApacheConnector::log(__FILE__, __LINE__, ApacheConnector::PRIO_ERROR, 0, exc.displayText().c_str()); + } + catch (...) + { + ApacheConnector::log(__FILE__, __LINE__, ApacheConnector::PRIO_ERROR, 0, "Unknown exception"); + } + return OK; +} + + +extern "C" void ApacheConnector_register_hooks(apr_pool_t *p) +{ + ap_hook_handler(ApacheConnector_handler, NULL, NULL, APR_HOOK_MIDDLE); +} + + +extern "C" const char* ApacheConnector_uris(cmd_parms *cmd, void *in_dconf, const char *in_str) +{ + try + { + ApacheApplication::instance().factory().handleURIs(in_str); + } + catch (Poco::Exception& exc) + { + ApacheConnector::log(__FILE__, __LINE__, ApacheConnector::PRIO_ERROR, 0, exc.displayText().c_str()); + } + catch (...) + { + ApacheConnector::log(__FILE__, __LINE__, ApacheConnector::PRIO_ERROR, 0, "Unknown exception"); + } + return 0; +} + + +extern "C" const char* ApacheConnector_config(cmd_parms *cmd, void *in_dconf, const char *in_str) +{ + try + { + ApacheApplication::instance().loadConfiguration(in_str); + } + catch (Poco::Exception& exc) + { + ApacheConnector::log(__FILE__, __LINE__, ApacheConnector::PRIO_ERROR, 0, exc.displayText().c_str()); + } + catch (...) + { + ApacheConnector::log(__FILE__, __LINE__, ApacheConnector::PRIO_ERROR, 0, "Unknown exception"); + } + return 0; +} + + +extern "C" const command_rec ApacheConnector_cmds[] = +{ + AP_INIT_RAW_ARGS( + "AddPocoRequestHandler", + reinterpret_cast(ApacheConnector_uris), + NULL, + RSRC_CONF, + "POCO RequestHandlerFactory class name followed by shared library path followed by a list of ' ' separated URIs that must be handled by this module."), + AP_INIT_RAW_ARGS( + "AddPocoConfig", + reinterpret_cast(ApacheConnector_config), + NULL, + RSRC_CONF, + "Path of the POCO configuration file."), + { NULL } +}; + + +module AP_MODULE_DECLARE_DATA poco_module = +{ + STANDARD20_MODULE_STUFF, + NULL, + NULL, + NULL, + NULL, + ApacheConnector_cmds, + ApacheConnector_register_hooks +}; diff --git a/ApacheConnector/src/ApacheRequestHandlerFactory.cpp b/ApacheConnector/src/ApacheRequestHandlerFactory.cpp new file mode 100644 index 000000000..21f24d759 --- /dev/null +++ b/ApacheConnector/src/ApacheRequestHandlerFactory.cpp @@ -0,0 +1,118 @@ +// +// ApacheRequestHandlerFactory.cpp +// +// $Id: //poco/Main/ApacheConnector/src/ApacheRequestHandlerFactory.cpp#8 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#include "ApacheRequestHandlerFactory.h" +#include "ApacheConnector.h" +#include "Poco/Net/HTTPRequestHandler.h" +#include "Poco/StringTokenizer.h" +#include "Poco/Manifest.h" +#include "Poco/File.h" +#include + + +using Poco::StringTokenizer; +using Poco::FastMutex; + + +ApacheRequestHandlerFactory::ApacheRequestHandlerFactory() +{ +} + + +ApacheRequestHandlerFactory::~ApacheRequestHandlerFactory() +{ +} + + +Poco::Net::HTTPRequestHandler* ApacheRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request) +{ + FastMutex::ScopedLock lock(_mutex); + + // only if the given uri is found in _uris we are + // handling this request. + RequestHandlerFactories::iterator it = _requestHandlers.begin(); + RequestHandlerFactories::iterator itEnd = _requestHandlers.end(); + std::string uri = request.getURI(); + + // if any uri in our map is found at the beginning of the given + // uri -> then we handle it!! + for (; it != itEnd; it++) + { + if (uri.find(it->first) == 0 || it->first.find(uri) == 0) + { + return it->second->createRequestHandler(request); + } + } + + return 0; +} + + +void ApacheRequestHandlerFactory::handleURIs(const std::string& uris) +{ + FastMutex::ScopedLock lock(_mutex); + + StringTokenizer st(uris, " ", StringTokenizer::TOK_TRIM); + StringTokenizer::Iterator it = st.begin(); + StringTokenizer::Iterator itEnd = st.end(); + std::string factoryName = (*it); + it++; + std::string dllName = (*it); + it++; + + for (; it != itEnd; it++) + { + addRequestHandlerFactory(dllName, factoryName, *it); + } +} + + +void ApacheRequestHandlerFactory::addRequestHandlerFactory(const std::string& dllPath, const std::string& factoryName, const std::string& uri) +{ + try + { + _loader.loadLibrary(dllPath); + Poco::Net::HTTPRequestHandlerFactory* pFactory = _loader.classFor(factoryName).create(); + _requestHandlers.insert(std::make_pair(uri, pFactory)); + } + catch (Poco::Exception& exc) + { + ApacheConnector::log(__FILE__, __LINE__, ApacheConnector::PRIO_ERROR, 0, exc.displayText().c_str()); + } +} + + +bool ApacheRequestHandlerFactory::mustHandle(const std::string& uri) +{ + FastMutex::ScopedLock lock(_mutex); + + // only if the given uri is found in _uris we are + // handling this request. + RequestHandlerFactories::iterator it = _requestHandlers.begin(); + RequestHandlerFactories::iterator itEnd = _requestHandlers.end(); + + // if any uri in our map is found at the beginning of the given + // uri -> then we handle it!! + for (; it != itEnd; it++) + { + // dealing with both cases: + // handler is registered with: /download + // uri: /download/xyz + // uri: /download + if (uri.find(it->first) == 0 || it->first.find(uri) == 0) + return true; + } + + return false; +} diff --git a/ApacheConnector/src/ApacheServerRequest.cpp b/ApacheConnector/src/ApacheServerRequest.cpp new file mode 100644 index 000000000..6d0601757 --- /dev/null +++ b/ApacheConnector/src/ApacheServerRequest.cpp @@ -0,0 +1,64 @@ +// +// ApacheServerRequest.cpp +// +// $Id: //poco/Main/ApacheConnector/src/ApacheServerRequest.cpp#9 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#include "ApacheServerRequest.h" +#include "ApacheServerResponse.h" +#include "ApacheRequestHandlerFactory.h" +#include "Poco/Exception.h" +#include + + +ApacheServerRequest::ApacheServerRequest( + ApacheRequestRec* pApacheRequest, + const char* serverName, + int serverPort, + const char* clientName, + int clientPort): + _pApacheRequest(pApacheRequest), + _pResponse(0), + _pStream(new ApacheInputStream(_pApacheRequest)), + _serverAddress(serverName, serverPort), + _clientAddress(clientName, clientPort) +{ +} + + +ApacheServerRequest::~ApacheServerRequest() +{ + delete _pStream; +} + + +const Poco::Net::HTTPServerParams& ApacheServerRequest::serverParams() const +{ + throw Poco::NotImplementedException("No HTTPServerParams available in Apache modules."); +} + + +Poco::Net::HTTPServerResponse& ApacheServerRequest::response() const +{ + return *_pResponse; +} + + +void ApacheServerRequest::setResponse(ApacheServerResponse* pResponse) +{ + _pResponse = pResponse; +} + + +bool ApacheServerRequest::expectContinue() const +{ + return false; +} diff --git a/ApacheConnector/src/ApacheServerResponse.cpp b/ApacheConnector/src/ApacheServerResponse.cpp new file mode 100644 index 000000000..ff9a22969 --- /dev/null +++ b/ApacheConnector/src/ApacheServerResponse.cpp @@ -0,0 +1,133 @@ +// +// ApacheServerResponse.cpp +// +// $Id: //poco/Main/ApacheConnector/src/ApacheServerResponse.cpp#8 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#include "ApacheServerResponse.h" +#include "ApacheServerRequest.h" +#include "ApacheStream.h" +#include "ApacheConnector.h" +#include "Poco/Net/HTTPCookie.h" +#include "Poco/File.h" +#include "Poco/Exception.h" +#include +#include + + +using Poco::File; +using Poco::OpenFileException; +using Poco::Net::HTTPCookie; + + +ApacheServerResponse::ApacheServerResponse(ApacheServerRequest* pRequest): + _pStream(0), + _pApacheRequest(pRequest->_pApacheRequest) +{ + setVersion(pRequest->getVersion()); + setKeepAlive(pRequest->getKeepAlive()); + + pRequest->setResponse(this); +} + + +ApacheServerResponse::~ApacheServerResponse() +{ + delete _pStream; +} + + +void ApacheServerResponse::initApacheOutputStream() +{ + poco_assert (!_pStream); + + _pApacheRequest->setContentType(getContentType()); + + std::vector cookies; + getCookies(cookies); + + std::size_t cnt = cookies.size(); + for (int c = 0; c < cnt; c++) + { + _pApacheRequest->addHeader("Set-Cookie", cookies[c].toString()); + } + + _pStream = new ApacheOutputStream(_pApacheRequest); +} + + +void ApacheServerResponse::sendContinue() +{ + // should be handled by Apache +} + + +std::ostream& ApacheServerResponse::send() +{ + poco_assert (!_pStream); + + initApacheOutputStream(); + + return *_pStream; +} + + +void ApacheServerResponse::sendFile(const std::string& path, const std::string& mediaType) +{ + poco_assert (!_pStream); + + initApacheOutputStream(); + + File f(path); + if (_pApacheRequest->sendFile(path, static_cast(f.getSize()), mediaType) != 0) + throw OpenFileException(path); +} + + +void ApacheServerResponse::sendBuffer(const void* pBuffer, std::size_t length) +{ + poco_assert (!_pStream); + + initApacheOutputStream(); + + _pStream->write(static_cast(pBuffer), static_cast(length)); +} + + +void ApacheServerResponse::redirect(const std::string& uri) +{ + poco_assert (!_pStream); + + initApacheOutputStream(); + + try + { + _pApacheRequest->redirect(uri); + } + catch (Poco::Exception&) + { + ApacheConnector::log(__FILE__, __LINE__, 7 , 0, "caught exception in ApacheServerResponse::redirect - ignoring\n"); + } +} + + +void ApacheServerResponse::sendErrorResponse(int status) +{ + initApacheOutputStream(); + + _pApacheRequest->sendErrorResponse(status); +} + + +void ApacheServerResponse::requireAuthentication(const std::string& realm) +{ + // should be handled by Apache +} diff --git a/ApacheConnector/src/ApacheStream.cpp b/ApacheConnector/src/ApacheStream.cpp new file mode 100644 index 000000000..1c331b243 --- /dev/null +++ b/ApacheConnector/src/ApacheStream.cpp @@ -0,0 +1,124 @@ +// +// ApacheStream.h +// +// $Id: //poco/Main/ApacheConnector/src/ApacheStream.cpp#9 $ +// +// Copyright (c) 2007, Applied Informatics Software Engineering GmbH. +// All rights reserved. +// +// This is unpublished proprietary source code of Applied Informatics. +// The contents of this file may not be disclosed to third parties, +// copied or duplicated in any form, in whole or in part. +// + + +#include "ApacheStream.h" +#include "ApacheConnector.h" +#include "Poco/Exception.h" + + +using Poco::BufferedStreamBuf; + + +// +// ApacheStreamBuf +// + + +ApacheStreamBuf::ApacheStreamBuf(ApacheRequestRec* pApacheRequest, bool haveData): + BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::in | std::ios::out), + _pApacheRequest(pApacheRequest), + _haveData(haveData) +{ +} + + +ApacheStreamBuf::~ApacheStreamBuf() +{ +} + + +int ApacheStreamBuf::readFromDevice(char* buffer, std::streamsize len) +{ + if (_haveData) + return _pApacheRequest->readRequest(buffer, static_cast(len)); + else + return 0; +} + + +int ApacheStreamBuf::writeToDevice(const char* buffer, std::streamsize length) +{ + _pApacheRequest->writeResponse(buffer, length); + return length; +} + + +// +// ApacheIOS +// + + +ApacheIOS::ApacheIOS(ApacheRequestRec* pApacheRequest, bool haveData): + _buf(pApacheRequest, haveData) +{ + poco_ios_init(&_buf); +} + + +ApacheIOS::~ApacheIOS() +{ + try + { + _buf.sync(); + } + catch (...) + { + } +} + + +ApacheStreamBuf* ApacheIOS::rdbuf() +{ + return &_buf; +} + + +void ApacheIOS::close() +{ + _buf.sync(); +} + + +// +// ApacheOutputStream +// + + +ApacheOutputStream::ApacheOutputStream(ApacheRequestRec* pApacheRequest): + ApacheIOS(pApacheRequest), + std::ostream(&_buf) +{ +} + + +ApacheOutputStream::~ApacheOutputStream() +{ +} + + +// +// ApacheInputStream +// + + +ApacheInputStream::ApacheInputStream(ApacheRequestRec* pApacheRequest): + ApacheIOS(pApacheRequest, pApacheRequest->haveRequestBody()), + std::istream(&_buf) +{ +} + + +ApacheInputStream::~ApacheInputStream() +{ +}