summaryrefslogtreecommitdiffstats
path: root/lib/libUPnP/Neptune/Source/Core/NptHttp.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libUPnP/Neptune/Source/Core/NptHttp.h')
-rw-r--r--lib/libUPnP/Neptune/Source/Core/NptHttp.h866
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_
+