diff options
Diffstat (limited to 'lib/libUPnP/Neptune/Source/Core/NptHttp.h')
-rw-r--r-- | lib/libUPnP/Neptune/Source/Core/NptHttp.h | 866 |
1 files changed, 866 insertions, 0 deletions
diff --git a/lib/libUPnP/Neptune/Source/Core/NptHttp.h b/lib/libUPnP/Neptune/Source/Core/NptHttp.h new file mode 100644 index 0000000..3d2a0d2 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptHttp.h @@ -0,0 +1,866 @@ +/***************************************************************** +| +| Neptune - HTTP Protocol +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_HTTP_H_ +#define _NPT_HTTP_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptUri.h" +#include "NptTypes.h" +#include "NptList.h" +#include "NptBufferedStreams.h" +#include "NptSockets.h" +#include "NptMap.h" +#include "NptDynamicCast.h" +#include "NptVersion.h" +#include "NptTime.h" +#include "NptThreads.h" +#include "NptAutomaticCleaner.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const unsigned int NPT_HTTP_DEFAULT_PORT = 80; +const unsigned int NPT_HTTPS_DEFAULT_PORT = 443; +const unsigned int NPT_HTTP_INVALID_PORT = 0; + +const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_CONNECTION_TIMEOUT = 30000; +const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_IO_TIMEOUT = 30000; +const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_NAME_RESOLVER_TIMEOUT = 60000; +const unsigned int NPT_HTTP_CLIENT_DEFAULT_MAX_REDIRECTS = 20; + +const NPT_Timeout NPT_HTTP_SERVER_DEFAULT_CONNECTION_TIMEOUT = NPT_TIMEOUT_INFINITE; +const NPT_Timeout NPT_HTTP_SERVER_DEFAULT_IO_TIMEOUT = 60000; + +const unsigned int NPT_HTTP_CONNECTION_MANAGER_MAX_CONNECTION_POOL_SIZE = 5; +const unsigned int NPT_HTTP_CONNECTION_MANAGER_MAX_CONNECTION_AGE = 30; // seconds +const unsigned int NPT_HTTP_MAX_RECONNECTS = 10; +const unsigned int NPT_HTTP_MAX_100_RESPONSES = 10; + +const int NPT_HTTP_PROTOCOL_MAX_LINE_LENGTH = 8192; +const int NPT_HTTP_PROTOCOL_MAX_HEADER_COUNT = 100; + +#define NPT_HTTP_PROTOCOL_1_0 "HTTP/1.0" +#define NPT_HTTP_PROTOCOL_1_1 "HTTP/1.1" +#define NPT_HTTP_METHOD_GET "GET" +#define NPT_HTTP_METHOD_HEAD "HEAD" +#define NPT_HTTP_METHOD_POST "POST" +#define NPT_HTTP_METHOD_PUT "PUT" +#define NPT_HTTP_METHOD_OPTIONS "OPTIONS" +#define NPT_HTTP_METHOD_DELETE "DELETE" +#define NPT_HTTP_METHOD_TRACE "TRACE" + +#define NPT_HTTP_HEADER_HOST "Host" +#define NPT_HTTP_HEADER_CONNECTION "Connection" +#define NPT_HTTP_HEADER_USER_AGENT "User-Agent" +#define NPT_HTTP_HEADER_SERVER "Server" +#define NPT_HTTP_HEADER_CONTENT_LENGTH "Content-Length" +#define NPT_HTTP_HEADER_CONTENT_TYPE "Content-Type" +#define NPT_HTTP_HEADER_CONTENT_ENCODING "Content-Encoding" +#define NPT_HTTP_HEADER_TRANSFER_ENCODING "Transfer-Encoding" +#define NPT_HTTP_HEADER_LOCATION "Location" +#define NPT_HTTP_HEADER_RANGE "Range" +#define NPT_HTTP_HEADER_CONTENT_RANGE "Content-Range" +#define NPT_HTTP_HEADER_COOKIE "Cookie" +#define NPT_HTTP_HEADER_ACCEPT_RANGES "Accept-Ranges" +#define NPT_HTTP_HEADER_CONTENT_RANGE "Content-Range" +#define NPT_HTTP_HEADER_AUTHORIZATION "Authorization" + +#define NPT_HTTP_TRANSFER_ENCODING_CHUNKED "chunked" + + +const int NPT_ERROR_HTTP_INVALID_RESPONSE_LINE = NPT_ERROR_BASE_HTTP - 0; +const int NPT_ERROR_HTTP_INVALID_REQUEST_LINE = NPT_ERROR_BASE_HTTP - 1; +const int NPT_ERROR_HTTP_NO_PROXY = NPT_ERROR_BASE_HTTP - 2; +const int NPT_ERROR_HTTP_INVALID_REQUEST = NPT_ERROR_BASE_HTTP - 3; +const int NPT_ERROR_HTTP_METHOD_NOT_SUPPORTED = NPT_ERROR_BASE_HTTP - 4; +const int NPT_ERROR_HTTP_TOO_MANY_REDIRECTS = NPT_ERROR_BASE_HTTP - 5; +const int NPT_ERROR_HTTP_TOO_MANY_RECONNECTS = NPT_ERROR_BASE_HTTP - 6; +const int NPT_ERROR_HTTP_CANNOT_RESEND_BODY = NPT_ERROR_BASE_HTTP - 7; + +#define NPT_HTTP_LINE_TERMINATOR "\r\n" + +#if !defined(NPT_CONFIG_HTTP_DEFAULT_USER_AGENT) +#define NPT_CONFIG_HTTP_DEFAULT_USER_AGENT "Neptune/" NPT_NEPTUNE_VERSION_STRING +#endif + +/*---------------------------------------------------------------------- +| types ++---------------------------------------------------------------------*/ +typedef unsigned int NPT_HttpStatusCode; +typedef NPT_UrlQuery NPT_HttpUrlQuery; // for backward compatibility + +/*---------------------------------------------------------------------- +| NPT_HttpUrl ++---------------------------------------------------------------------*/ +class NPT_HttpUrl : public NPT_Url { +public: + // constructors + NPT_HttpUrl() {} + NPT_HttpUrl(const char* host, + NPT_UInt16 port, + const char* path, + const char* query = NULL, + const char* fragment = NULL); + NPT_HttpUrl(const char* url, bool ignore_scheme = false); + + // methods + NPT_String ToString(bool with_fragment = true) const override; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpProtocol ++---------------------------------------------------------------------*/ +class NPT_HttpProtocol +{ +public: + // class methods + const char* GetStatusCodeString(NPT_HttpStatusCode status_code); +}; + +/*---------------------------------------------------------------------- +| NPT_HttpHeader ++---------------------------------------------------------------------*/ +class NPT_HttpHeader { +public: + // constructors and destructor + NPT_HttpHeader(const char* name, const char* value); + ~NPT_HttpHeader(); + + // methods + NPT_Result Emit(NPT_OutputStream& stream) const; + const NPT_String& GetName() const { return m_Name; } + const NPT_String& GetValue() const { return m_Value; } + NPT_Result SetName(const char* name); + NPT_Result SetValue(const char* value); + +private: + // members + NPT_String m_Name; + NPT_String m_Value; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpHeaders ++---------------------------------------------------------------------*/ +class NPT_HttpHeaders { +public: + // constructors and destructor + NPT_HttpHeaders(); + ~NPT_HttpHeaders(); + + // methods + NPT_Result Parse(NPT_BufferedInputStream& stream); + NPT_Result Emit(NPT_OutputStream& stream) const; + const NPT_List<NPT_HttpHeader*>& GetHeaders() const { return m_Headers; } + NPT_HttpHeader* GetHeader(const char* name) const; + const NPT_String* GetHeaderValue(const char* name) const; + NPT_Result SetHeader(const char* name, const char* value, bool replace=true); + NPT_Result AddHeader(const char* name, const char* value); + NPT_Result RemoveHeader(const char* name); + +private: + // members + NPT_List<NPT_HttpHeader*> m_Headers; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpEntity ++---------------------------------------------------------------------*/ +class NPT_HttpEntity { +public: + // constructors and destructor + NPT_HttpEntity(); + NPT_HttpEntity(const NPT_HttpHeaders& headers); + virtual ~NPT_HttpEntity(); + + // methods + NPT_Result SetInputStream(const NPT_InputStreamReference& stream, + bool update_content_length = false); + NPT_Result SetInputStream(const void* data, NPT_Size size); + NPT_Result SetInputStream(const NPT_String& string); + NPT_Result SetInputStream(const char* string); + NPT_Result GetInputStream(NPT_InputStreamReference& stream); + NPT_Result Load(NPT_DataBuffer& buffer); + NPT_Result SetHeaders(const NPT_HttpHeaders& headers); + + // field access + NPT_Result SetContentLength(NPT_LargeSize length); + NPT_Result SetContentType(const char* type); + NPT_Result SetContentEncoding(const char* encoding); + NPT_Result SetTransferEncoding(const char* encoding); + NPT_LargeSize GetContentLength() { return m_ContentLength; } + const NPT_String& GetContentType() { return m_ContentType; } + const NPT_String& GetContentEncoding() { return m_ContentEncoding; } + const NPT_String& GetTransferEncoding() { return m_TransferEncoding;} + bool ContentLengthIsKnown() { return m_ContentLengthIsKnown; } + +private: + // members + NPT_InputStreamReference m_InputStream; + NPT_LargeSize m_ContentLength; + NPT_String m_ContentType; + NPT_String m_ContentEncoding; + NPT_String m_TransferEncoding; + bool m_ContentLengthIsKnown; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpMessage ++---------------------------------------------------------------------*/ +class NPT_HttpMessage { +public: + // constructors and destructor + virtual ~NPT_HttpMessage(); + + // methods + const NPT_String& GetProtocol() const { + return m_Protocol; + } + NPT_Result SetProtocol(const char* protocol) { + m_Protocol = protocol; + return NPT_SUCCESS; + } + NPT_HttpHeaders& GetHeaders() { + return m_Headers; + } + const NPT_HttpHeaders& GetHeaders() const { + return m_Headers; + } + NPT_Result SetEntity(NPT_HttpEntity* entity); + NPT_HttpEntity* GetEntity() { + return m_Entity; + } + NPT_HttpEntity* GetEntity() const { + return m_Entity; + } + virtual NPT_Result ParseHeaders(NPT_BufferedInputStream& stream); + +protected: + // constructors + NPT_HttpMessage(const char* protocol); + + // members + NPT_String m_Protocol; + NPT_HttpHeaders m_Headers; + NPT_HttpEntity* m_Entity; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpRequest ++---------------------------------------------------------------------*/ +class NPT_HttpRequest : public NPT_HttpMessage { +public: + // class methods + static NPT_Result Parse(NPT_BufferedInputStream& stream, + const NPT_SocketAddress* endpoint, + NPT_HttpRequest*& request); + + // constructors and destructor + NPT_HttpRequest(const NPT_HttpUrl& url, + const char* method, + const char* protocol = NPT_HTTP_PROTOCOL_1_0); + NPT_HttpRequest(const char* url, + const char* method, + const char* protocol = NPT_HTTP_PROTOCOL_1_0); + ~NPT_HttpRequest() override; + + // methods + const NPT_HttpUrl& GetUrl() const { return m_Url; } + NPT_HttpUrl& GetUrl() { return m_Url; } + NPT_Result SetUrl(const char* url); + NPT_Result SetUrl(const NPT_HttpUrl& url); + const NPT_String& GetMethod() const { return m_Method; } + virtual NPT_Result Emit(NPT_OutputStream& stream, bool use_proxy=false) const; + +protected: + // members + NPT_HttpUrl m_Url; + NPT_String m_Method; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpResponse ++---------------------------------------------------------------------*/ +class NPT_HttpResponse : public NPT_HttpMessage { +public: + // class methods + static NPT_Result Parse(NPT_BufferedInputStream& stream, + NPT_HttpResponse*& response); + + // constructors and destructor + NPT_HttpResponse(NPT_HttpStatusCode status_code, + const char* reason_phrase, + const char* protocol = NPT_HTTP_PROTOCOL_1_0); + ~NPT_HttpResponse() override; + + // methods + NPT_Result SetStatus(NPT_HttpStatusCode status_code, + const char* reason_phrase, + const char* protocol = NULL); + NPT_Result SetProtocol(const char* protocol); + NPT_HttpStatusCode GetStatusCode() const { return m_StatusCode; } + const NPT_String& GetReasonPhrase() const { return m_ReasonPhrase; } + virtual NPT_Result Emit(NPT_OutputStream& stream) const; + +protected: + // members + NPT_HttpStatusCode m_StatusCode; + NPT_String m_ReasonPhrase; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpProxyAddress ++---------------------------------------------------------------------*/ +class NPT_HttpProxyAddress +{ +public: + NPT_HttpProxyAddress() : m_Port(NPT_HTTP_INVALID_PORT) {} + NPT_HttpProxyAddress(const char* hostname, NPT_UInt16 port) : + m_HostName(hostname), m_Port(port) {} + + const NPT_String& GetHostName() const { return m_HostName; } + void SetHostName(const char* hostname) { m_HostName = hostname; } + NPT_UInt16 GetPort() const { return m_Port; } + void SetPort(NPT_UInt16 port) { m_Port = port; } + +private: + NPT_String m_HostName; + NPT_UInt16 m_Port; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpProxySelector ++---------------------------------------------------------------------*/ +class NPT_HttpProxySelector +{ +public: + // class methods + static NPT_HttpProxySelector* GetDefault(); + static NPT_HttpProxySelector* GetSystemSelector(); + + // methods + virtual ~NPT_HttpProxySelector() {}; + virtual NPT_Result GetProxyForUrl(const NPT_HttpUrl& url, NPT_HttpProxyAddress& proxy) = 0; + +private: + // class members + static NPT_HttpProxySelector* m_SystemDefault; +}; + +class NPT_HttpRequestContext; + +/*---------------------------------------------------------------------- +| NPT_HttpClient ++---------------------------------------------------------------------*/ +class NPT_HttpClient { +public: + // types + struct Config { + Config() : m_ConnectionTimeout( NPT_HTTP_CLIENT_DEFAULT_CONNECTION_TIMEOUT), + m_IoTimeout( NPT_HTTP_CLIENT_DEFAULT_CONNECTION_TIMEOUT), + m_NameResolverTimeout(NPT_HTTP_CLIENT_DEFAULT_NAME_RESOLVER_TIMEOUT), + m_MaxRedirects( NPT_HTTP_CLIENT_DEFAULT_MAX_REDIRECTS), + m_UserAgent( NPT_CONFIG_HTTP_DEFAULT_USER_AGENT) {} + NPT_Timeout m_ConnectionTimeout; + NPT_Timeout m_IoTimeout; + NPT_Timeout m_NameResolverTimeout; + NPT_Cardinal m_MaxRedirects; + NPT_String m_UserAgent; + }; + + class Connection { + public: + virtual ~Connection() {} + virtual NPT_InputStreamReference& GetInputStream() = 0; + virtual NPT_OutputStreamReference& GetOutputStream() = 0; + virtual NPT_Result GetInfo(NPT_SocketInfo& info) = 0; + virtual bool SupportsPersistence() { return false; } + virtual bool IsRecycled() { return false; } + virtual NPT_Result Recycle() { delete this; return NPT_SUCCESS; } + virtual NPT_Result Abort() { return NPT_ERROR_NOT_IMPLEMENTED; } + }; + + class Connector { + public: + virtual ~Connector() {} + + virtual NPT_Result Connect(const NPT_HttpUrl& url, + NPT_HttpClient& client, + const NPT_HttpProxyAddress* proxy, + bool reuse, // whether we can reuse a connection or not + Connection*& connection) = 0; + + protected: + NPT_Result TrackConnection(NPT_HttpClient& client, + Connection* connection) { return client.TrackConnection(connection); } + Connector() {} // don't instantiate directly + }; + + // class methods + static NPT_Result WriteRequest(NPT_OutputStream& output_stream, + NPT_HttpRequest& request, + bool should_persist, + bool use_proxy = false); + static NPT_Result ReadResponse(NPT_InputStreamReference& input_stream, + bool should_persist, + bool expect_entity, + NPT_HttpResponse*& response, + NPT_Reference<Connection>* cref = NULL); + + /** + * @param connector Pointer to a connector instance, or NULL to use + * the default (TCP) connector. + * @param transfer_ownership Boolean flag. If true, the NPT_HttpClient object + * becomes the owner of the passed Connector and will delete it when it is + * itself deleted. If false, the caller keeps the ownership of the connector. + * This flag is ignored if the connector parameter is NULL. + */ + NPT_HttpClient(Connector* connector = NULL, bool transfer_ownership = true); + + virtual ~NPT_HttpClient(); + + // methods + NPT_Result SendRequest(NPT_HttpRequest& request, + NPT_HttpResponse*& response, + NPT_HttpRequestContext* context = NULL); + NPT_Result Abort(); + const Config& GetConfig() const { return m_Config; } + NPT_Result SetConfig(const Config& config); + NPT_Result SetProxy(const char* http_proxy_hostname, + NPT_UInt16 http_proxy_port, + const char* https_proxy_hostname = NULL, + NPT_UInt16 https_proxy_port = 0); + NPT_Result SetProxySelector(NPT_HttpProxySelector* selector); + NPT_Result SetConnector(Connector* connector); + NPT_Result SetTimeouts(NPT_Timeout connection_timeout, + NPT_Timeout io_timeout, + NPT_Timeout name_resolver_timeout); + NPT_Result SetUserAgent(const char* user_agent); + NPT_Result SetOptions(NPT_Flags options, bool on); + +protected: + // methods + NPT_Result TrackConnection(Connection* connection); + NPT_Result SendRequestOnce(NPT_HttpRequest& request, + NPT_HttpResponse*& response, + NPT_HttpRequestContext* context = NULL); + + // members + Config m_Config; + NPT_HttpProxySelector* m_ProxySelector; + bool m_ProxySelectorIsOwned; + Connector* m_Connector; + bool m_ConnectorIsOwned; + NPT_Mutex m_AbortLock; + bool m_Aborted; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager ++---------------------------------------------------------------------*/ +class NPT_HttpConnectionManager : public NPT_Thread, + public NPT_AutomaticCleaner::Singleton +{ +public: + // singleton management + static NPT_HttpConnectionManager* GetInstance(); + + class Connection : public NPT_HttpClient::Connection + { + public: + Connection(NPT_HttpConnectionManager& manager, + NPT_SocketReference& socket, + NPT_InputStreamReference input_stream, + NPT_OutputStreamReference output_stream); + ~Connection() override; + + // NPT_HttpClient::Connection methods + NPT_InputStreamReference& GetInputStream() override { return m_InputStream; } + NPT_OutputStreamReference& GetOutputStream() override { return m_OutputStream; } + NPT_Result GetInfo(NPT_SocketInfo& info) override { return m_Socket->GetInfo(info); } + bool SupportsPersistence() override { return true; } + bool IsRecycled() override { return m_IsRecycled; } + NPT_Result Recycle() override; + NPT_Result Abort() override { return m_Socket->Cancel(); } + + // members + NPT_HttpConnectionManager& m_Manager; + bool m_IsRecycled; + NPT_TimeStamp m_TimeStamp; + NPT_SocketReference m_Socket; + NPT_InputStreamReference m_InputStream; + NPT_OutputStreamReference m_OutputStream; + }; + + // destructor + ~NPT_HttpConnectionManager() override; + + // methods + Connection* FindConnection(NPT_SocketAddress& address); + NPT_Result Recycle(Connection* connection); + NPT_Result Track(NPT_HttpClient* client, NPT_HttpClient::Connection* connection); + NPT_Result AbortConnections(NPT_HttpClient* client); + + // class methods + static NPT_Result Untrack(NPT_HttpClient::Connection* connection); + +private: + typedef NPT_List<NPT_HttpClient::Connection*> ConnectionList; + + // class members + static NPT_HttpConnectionManager* Instance; + + // constructor + NPT_HttpConnectionManager(); + + // NPT_Thread methods + void Run() override; + + // methods + NPT_Result UntrackConnection(NPT_HttpClient::Connection* connection); + NPT_Result Cleanup(); + + // members + NPT_Mutex m_Lock; + NPT_Cardinal m_MaxConnections; + NPT_Cardinal m_MaxConnectionAge; + NPT_SharedVariable m_Aborted; + NPT_List<Connection*> m_Connections; + NPT_Map<NPT_HttpClient*, ConnectionList> m_ClientConnections; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpRequestContext ++---------------------------------------------------------------------*/ +class NPT_HttpRequestContext +{ +public: + // constructor + NPT_HttpRequestContext() {} + NPT_HttpRequestContext(const NPT_SocketAddress* local_address, + const NPT_SocketAddress* remote_address); + + // methods + const NPT_SocketAddress& GetLocalAddress() const { return m_LocalAddress; } + const NPT_SocketAddress& GetRemoteAddress() const { return m_RemoteAddress; } + void SetLocalAddress(const NPT_SocketAddress& address) { + m_LocalAddress = address; + } + void SetRemoteAddress(const NPT_SocketAddress& address) { + m_RemoteAddress = address; + } + +private: + // members + NPT_SocketAddress m_LocalAddress; + NPT_SocketAddress m_RemoteAddress; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpRequestHandler ++---------------------------------------------------------------------*/ +class NPT_HttpRequestHandler +{ +public: + NPT_IMPLEMENT_DYNAMIC_CAST(NPT_HttpRequestHandler) + + // destructor + virtual ~NPT_HttpRequestHandler() {} + + // methods + virtual NPT_Result SetupResponse(NPT_HttpRequest& request, + const NPT_HttpRequestContext& context, + NPT_HttpResponse& response) = 0; + + /** + * Override this method if you want to write the body yourself. + * The default implementation will simply write out the entity's + * input stream. + */ + virtual NPT_Result SendResponseBody(const NPT_HttpRequestContext& context, + NPT_HttpResponse& response, + NPT_OutputStream& output); + + /** + * A notification method called by the server upon completing the + * processing of a request. + */ + virtual void Completed(NPT_Result /*result*/) {} +}; + +/*---------------------------------------------------------------------- +| NPT_HttpStaticRequestHandler ++---------------------------------------------------------------------*/ +class NPT_HttpStaticRequestHandler : public NPT_HttpRequestHandler +{ +public: + // constructors + NPT_HttpStaticRequestHandler(const char* document, + const char* mime_type = "text/html", + bool copy = true); + NPT_HttpStaticRequestHandler(const void* data, + NPT_Size size, + const char* mime_type = "text/html", + bool copy = true); + + // NPT_HttpRequestHandler methods + NPT_Result SetupResponse(NPT_HttpRequest& request, + const NPT_HttpRequestContext& context, + NPT_HttpResponse& response) override; + +private: + NPT_String m_MimeType; + NPT_DataBuffer m_Buffer; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpFileRequestHandler_DefaultFileTypeMapEntry ++---------------------------------------------------------------------*/ +typedef struct NPT_HttpFileRequestHandler_DefaultFileTypeMapEntry { + const char* extension; + const char* mime_type; +} NPT_HttpFileRequestHandler_FileTypeMapEntry; + +/*---------------------------------------------------------------------- +| NPT_HttpFileRequestHandler ++---------------------------------------------------------------------*/ +class NPT_HttpFileRequestHandler : public NPT_HttpRequestHandler +{ +public: + // constructors + NPT_HttpFileRequestHandler(const char* url_root, + const char* file_root, + bool auto_dir = false, + const char* auto_index = NULL); + + // NPT_HttpRequestHandler methods + NPT_Result SetupResponse(NPT_HttpRequest& request, + const NPT_HttpRequestContext& context, + NPT_HttpResponse& response) override; + + // class methods + static const char* GetDefaultContentType(const char* extension); + + // accessors + NPT_Map<NPT_String,NPT_String>& GetFileTypeMap() { return m_FileTypeMap; } + void SetDefaultMimeType(const char* mime_type) { + m_DefaultMimeType = mime_type; + } + void SetUseDefaultFileTypeMap(bool use_default) { + m_UseDefaultFileTypeMap = use_default; + } + + static NPT_Result SetupResponseBody(NPT_HttpResponse& response, + NPT_InputStreamReference& stream, + const NPT_String* range_spec = NULL); + +protected: + // methods + const char* GetContentType(const NPT_String& filename); + +private: + NPT_String m_UrlRoot; + NPT_String m_FileRoot; + NPT_Map<NPT_String, NPT_String> m_FileTypeMap; + NPT_String m_DefaultMimeType; + bool m_UseDefaultFileTypeMap; + bool m_AutoDir; + NPT_String m_AutoIndex; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpServer ++---------------------------------------------------------------------*/ +class NPT_HttpServer { +public: + // types + struct Config { + NPT_Timeout m_ConnectionTimeout; + NPT_Timeout m_IoTimeout; + NPT_IpAddress m_ListenAddress; + NPT_UInt16 m_ListenPort; + bool m_ReuseAddress; + }; + + // constructors and destructor + NPT_HttpServer(NPT_UInt16 listen_port = NPT_HTTP_DEFAULT_PORT, bool cancellable = false); + NPT_HttpServer(NPT_IpAddress listen_address, + NPT_UInt16 listen_port = NPT_HTTP_DEFAULT_PORT, + bool cancellable = false); + virtual ~NPT_HttpServer(); + + // methods + NPT_Result SetConfig(const Config& config); + const Config& GetConfig() const { return m_Config; } + NPT_Result SetListenPort(NPT_UInt16 port, bool reuse_address = true); + NPT_Result SetTimeouts(NPT_Timeout connection_timeout, NPT_Timeout io_timeout); + NPT_Result SetServerHeader(const char* server_header); + NPT_Result Abort(); + NPT_Result WaitForNewClient(NPT_InputStreamReference& input, + NPT_OutputStreamReference& output, + NPT_HttpRequestContext* context, + NPT_Flags socket_flags = 0); + NPT_Result Loop(bool cancellable_sockets=true); + NPT_UInt16 GetPort() { return m_BoundPort; } + void Terminate(); + + /** + * Add a request handler. By default the ownership of the handler is NOT transfered to this object, + * so the caller is responsible for the lifetime management of the handler object. + */ + virtual NPT_Result AddRequestHandler(NPT_HttpRequestHandler* handler, + const char* path, + bool include_children = false, + bool transfer_ownership = false); + virtual NPT_HttpRequestHandler* FindRequestHandler(NPT_HttpRequest& request); + virtual NPT_List<NPT_HttpRequestHandler*> FindRequestHandlers(NPT_HttpRequest& request); + + /** + * Parse the request from a new client, form a response, and send it back. + */ + virtual NPT_Result RespondToClient(NPT_InputStreamReference& input, + NPT_OutputStreamReference& output, + const NPT_HttpRequestContext& context); + +protected: + // types + struct HandlerConfig { + HandlerConfig(NPT_HttpRequestHandler* handler, + const char* path, + bool include_children, + bool transfer_ownership = false); + ~HandlerConfig(); + + // methods + bool WillHandle(NPT_HttpRequest& request); + + // members + NPT_HttpRequestHandler* m_Handler; + NPT_String m_Path; + bool m_IncludeChildren; + bool m_HandlerIsOwned; + }; + + // methods + NPT_Result Bind(); + + // members + NPT_TcpServerSocket m_Socket; + NPT_UInt16 m_BoundPort; + Config m_Config; + NPT_List<HandlerConfig*> m_RequestHandlers; + NPT_String m_ServerHeader; + bool m_Run; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpResponder ++---------------------------------------------------------------------*/ +class NPT_HttpResponder { +public: + // types + struct Config { + NPT_Timeout m_IoTimeout; + }; + + // constructors and destructor + NPT_HttpResponder(NPT_InputStreamReference& input, + NPT_OutputStreamReference& output); + virtual ~NPT_HttpResponder(); + + // methods + NPT_Result SetConfig(const Config& config); + NPT_Result SetTimeout(NPT_Timeout io_timeout); + NPT_Result ParseRequest(NPT_HttpRequest*& request, + const NPT_SocketAddress* local_address = NULL); + NPT_Result SendResponseHeaders(NPT_HttpResponse& response); + +protected: + // members + Config m_Config; + NPT_BufferedInputStreamReference m_Input; + NPT_OutputStreamReference m_Output; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedInputStream ++---------------------------------------------------------------------*/ +class NPT_HttpChunkedInputStream : public NPT_InputStream +{ +public: + // constructors and destructor + NPT_HttpChunkedInputStream(NPT_BufferedInputStreamReference& stream); + ~NPT_HttpChunkedInputStream() override; + + // NPT_InputStream methods + NPT_Result Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read = NULL) override; + NPT_Result Seek(NPT_Position offset) override; + NPT_Result Tell(NPT_Position& offset) override; + NPT_Result GetSize(NPT_LargeSize& size) override; + NPT_Result GetAvailable(NPT_LargeSize& available) override; + +protected: + // members + NPT_BufferedInputStreamReference m_Source; + NPT_UInt32 m_CurrentChunkSize; + bool m_Eos; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedOutputStream ++---------------------------------------------------------------------*/ +class NPT_HttpChunkedOutputStream : public NPT_OutputStream +{ +public: + // constructors and destructor + NPT_HttpChunkedOutputStream(NPT_OutputStream& stream); + ~NPT_HttpChunkedOutputStream() override; + + // NPT_OutputStream methods + NPT_Result Write(const void* buffer, + NPT_Size bytes_to_write, + NPT_Size* bytes_written = NULL) override; + NPT_Result Seek(NPT_Position /*offset*/) override { return NPT_ERROR_NOT_SUPPORTED;} + NPT_Result Tell(NPT_Position& offset) override { return m_Stream.Tell(offset); } + NPT_Result Flush() override { return m_Stream.Flush(); } + +protected: + // members + NPT_OutputStream& m_Stream; +}; + +#endif // _NPT_HTTP_H_ + |