1 /*****************************************************************
3 | Neptune - HTTP Protocol
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are met:
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 | * Neither the name of Axiomatic Systems nor the
16 | names of its contributors may be used to endorse or promote products
17 | derived from this software without specific prior written permission.
19 | THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 ****************************************************************/
35 /*----------------------------------------------------------------------
37 +---------------------------------------------------------------------*/
41 #include "NptBufferedStreams.h"
42 #include "NptSockets.h"
44 #include "NptDynamicCast.h"
45 #include "NptVersion.h"
47 #include "NptThreads.h"
48 #include "NptAutomaticCleaner.h"
50 /*----------------------------------------------------------------------
52 +---------------------------------------------------------------------*/
53 const unsigned int NPT_HTTP_DEFAULT_PORT
= 80;
54 const unsigned int NPT_HTTPS_DEFAULT_PORT
= 443;
55 const unsigned int NPT_HTTP_INVALID_PORT
= 0;
57 const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_CONNECTION_TIMEOUT
= 30000;
58 const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_IO_TIMEOUT
= 30000;
59 const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_NAME_RESOLVER_TIMEOUT
= 60000;
60 const unsigned int NPT_HTTP_CLIENT_DEFAULT_MAX_REDIRECTS
= 20;
62 const NPT_Timeout NPT_HTTP_SERVER_DEFAULT_CONNECTION_TIMEOUT
= NPT_TIMEOUT_INFINITE
;
63 const NPT_Timeout NPT_HTTP_SERVER_DEFAULT_IO_TIMEOUT
= 60000;
65 const unsigned int NPT_HTTP_CONNECTION_MANAGER_MAX_CONNECTION_POOL_SIZE
= 5;
66 const unsigned int NPT_HTTP_CONNECTION_MANAGER_MAX_CONNECTION_AGE
= 30; // seconds
67 const unsigned int NPT_HTTP_MAX_RECONNECTS
= 10;
68 const unsigned int NPT_HTTP_MAX_100_RESPONSES
= 10;
70 const int NPT_HTTP_PROTOCOL_MAX_LINE_LENGTH
= 8192;
71 const int NPT_HTTP_PROTOCOL_MAX_HEADER_COUNT
= 100;
73 #define NPT_HTTP_PROTOCOL_1_0 "HTTP/1.0"
74 #define NPT_HTTP_PROTOCOL_1_1 "HTTP/1.1"
75 #define NPT_HTTP_METHOD_GET "GET"
76 #define NPT_HTTP_METHOD_HEAD "HEAD"
77 #define NPT_HTTP_METHOD_POST "POST"
78 #define NPT_HTTP_METHOD_PUT "PUT"
79 #define NPT_HTTP_METHOD_OPTIONS "OPTIONS"
80 #define NPT_HTTP_METHOD_DELETE "DELETE"
81 #define NPT_HTTP_METHOD_TRACE "TRACE"
83 #define NPT_HTTP_HEADER_HOST "Host"
84 #define NPT_HTTP_HEADER_CONNECTION "Connection"
85 #define NPT_HTTP_HEADER_USER_AGENT "User-Agent"
86 #define NPT_HTTP_HEADER_SERVER "Server"
87 #define NPT_HTTP_HEADER_CONTENT_LENGTH "Content-Length"
88 #define NPT_HTTP_HEADER_CONTENT_TYPE "Content-Type"
89 #define NPT_HTTP_HEADER_CONTENT_ENCODING "Content-Encoding"
90 #define NPT_HTTP_HEADER_TRANSFER_ENCODING "Transfer-Encoding"
91 #define NPT_HTTP_HEADER_LOCATION "Location"
92 #define NPT_HTTP_HEADER_RANGE "Range"
93 #define NPT_HTTP_HEADER_CONTENT_RANGE "Content-Range"
94 #define NPT_HTTP_HEADER_COOKIE "Cookie"
95 #define NPT_HTTP_HEADER_ACCEPT_RANGES "Accept-Ranges"
96 #define NPT_HTTP_HEADER_CONTENT_RANGE "Content-Range"
97 #define NPT_HTTP_HEADER_AUTHORIZATION "Authorization"
99 #define NPT_HTTP_TRANSFER_ENCODING_CHUNKED "chunked"
102 const int NPT_ERROR_HTTP_INVALID_RESPONSE_LINE
= NPT_ERROR_BASE_HTTP
- 0;
103 const int NPT_ERROR_HTTP_INVALID_REQUEST_LINE
= NPT_ERROR_BASE_HTTP
- 1;
104 const int NPT_ERROR_HTTP_NO_PROXY
= NPT_ERROR_BASE_HTTP
- 2;
105 const int NPT_ERROR_HTTP_INVALID_REQUEST
= NPT_ERROR_BASE_HTTP
- 3;
106 const int NPT_ERROR_HTTP_METHOD_NOT_SUPPORTED
= NPT_ERROR_BASE_HTTP
- 4;
107 const int NPT_ERROR_HTTP_TOO_MANY_REDIRECTS
= NPT_ERROR_BASE_HTTP
- 5;
108 const int NPT_ERROR_HTTP_TOO_MANY_RECONNECTS
= NPT_ERROR_BASE_HTTP
- 6;
109 const int NPT_ERROR_HTTP_CANNOT_RESEND_BODY
= NPT_ERROR_BASE_HTTP
- 7;
111 #define NPT_HTTP_LINE_TERMINATOR "\r\n"
113 #if !defined(NPT_CONFIG_HTTP_DEFAULT_USER_AGENT)
114 #define NPT_CONFIG_HTTP_DEFAULT_USER_AGENT "Neptune/" NPT_NEPTUNE_VERSION_STRING
117 /*----------------------------------------------------------------------
119 +---------------------------------------------------------------------*/
120 typedef unsigned int NPT_HttpStatusCode
;
121 typedef NPT_UrlQuery NPT_HttpUrlQuery
; // for backward compatibility
123 /*----------------------------------------------------------------------
125 +---------------------------------------------------------------------*/
126 class NPT_HttpUrl
: public NPT_Url
{
130 NPT_HttpUrl(const char* host
,
133 const char* query
= NULL
,
134 const char* fragment
= NULL
);
135 NPT_HttpUrl(const char* url
, bool ignore_scheme
= false);
138 NPT_String
ToString(bool with_fragment
= true) const override
;
141 /*----------------------------------------------------------------------
143 +---------------------------------------------------------------------*/
144 class NPT_HttpProtocol
148 const char* GetStatusCodeString(NPT_HttpStatusCode status_code
);
151 /*----------------------------------------------------------------------
153 +---------------------------------------------------------------------*/
154 class NPT_HttpHeader
{
156 // constructors and destructor
157 NPT_HttpHeader(const char* name
, const char* value
);
161 NPT_Result
Emit(NPT_OutputStream
& stream
) const;
162 const NPT_String
& GetName() const { return m_Name
; }
163 const NPT_String
& GetValue() const { return m_Value
; }
164 NPT_Result
SetName(const char* name
);
165 NPT_Result
SetValue(const char* value
);
173 /*----------------------------------------------------------------------
175 +---------------------------------------------------------------------*/
176 class NPT_HttpHeaders
{
178 // constructors and destructor
183 NPT_Result
Parse(NPT_BufferedInputStream
& stream
);
184 NPT_Result
Emit(NPT_OutputStream
& stream
) const;
185 const NPT_List
<NPT_HttpHeader
*>& GetHeaders() const { return m_Headers
; }
186 NPT_HttpHeader
* GetHeader(const char* name
) const;
187 const NPT_String
* GetHeaderValue(const char* name
) const;
188 NPT_Result
SetHeader(const char* name
, const char* value
, bool replace
=true);
189 NPT_Result
AddHeader(const char* name
, const char* value
);
190 NPT_Result
RemoveHeader(const char* name
);
194 NPT_List
<NPT_HttpHeader
*> m_Headers
;
197 /*----------------------------------------------------------------------
199 +---------------------------------------------------------------------*/
200 class NPT_HttpEntity
{
202 // constructors and destructor
204 NPT_HttpEntity(const NPT_HttpHeaders
& headers
);
205 virtual ~NPT_HttpEntity();
208 NPT_Result
SetInputStream(const NPT_InputStreamReference
& stream
,
209 bool update_content_length
= false);
210 NPT_Result
SetInputStream(const void* data
, NPT_Size size
);
211 NPT_Result
SetInputStream(const NPT_String
& string
);
212 NPT_Result
SetInputStream(const char* string
);
213 NPT_Result
GetInputStream(NPT_InputStreamReference
& stream
);
214 NPT_Result
Load(NPT_DataBuffer
& buffer
);
215 NPT_Result
SetHeaders(const NPT_HttpHeaders
& headers
);
218 NPT_Result
SetContentLength(NPT_LargeSize length
);
219 NPT_Result
SetContentType(const char* type
);
220 NPT_Result
SetContentEncoding(const char* encoding
);
221 NPT_Result
SetTransferEncoding(const char* encoding
);
222 NPT_LargeSize
GetContentLength() { return m_ContentLength
; }
223 const NPT_String
& GetContentType() { return m_ContentType
; }
224 const NPT_String
& GetContentEncoding() { return m_ContentEncoding
; }
225 const NPT_String
& GetTransferEncoding() { return m_TransferEncoding
;}
226 bool ContentLengthIsKnown() { return m_ContentLengthIsKnown
; }
230 NPT_InputStreamReference m_InputStream
;
231 NPT_LargeSize m_ContentLength
;
232 NPT_String m_ContentType
;
233 NPT_String m_ContentEncoding
;
234 NPT_String m_TransferEncoding
;
235 bool m_ContentLengthIsKnown
;
238 /*----------------------------------------------------------------------
240 +---------------------------------------------------------------------*/
241 class NPT_HttpMessage
{
243 // constructors and destructor
244 virtual ~NPT_HttpMessage();
247 const NPT_String
& GetProtocol() const {
250 NPT_Result
SetProtocol(const char* protocol
) {
251 m_Protocol
= protocol
;
254 NPT_HttpHeaders
& GetHeaders() {
257 const NPT_HttpHeaders
& GetHeaders() const {
260 NPT_Result
SetEntity(NPT_HttpEntity
* entity
);
261 NPT_HttpEntity
* GetEntity() {
264 NPT_HttpEntity
* GetEntity() const {
267 virtual NPT_Result
ParseHeaders(NPT_BufferedInputStream
& stream
);
271 NPT_HttpMessage(const char* protocol
);
274 NPT_String m_Protocol
;
275 NPT_HttpHeaders m_Headers
;
276 NPT_HttpEntity
* m_Entity
;
279 /*----------------------------------------------------------------------
281 +---------------------------------------------------------------------*/
282 class NPT_HttpRequest
: public NPT_HttpMessage
{
285 static NPT_Result
Parse(NPT_BufferedInputStream
& stream
,
286 const NPT_SocketAddress
* endpoint
,
287 NPT_HttpRequest
*& request
);
289 // constructors and destructor
290 NPT_HttpRequest(const NPT_HttpUrl
& url
,
292 const char* protocol
= NPT_HTTP_PROTOCOL_1_0
);
293 NPT_HttpRequest(const char* url
,
295 const char* protocol
= NPT_HTTP_PROTOCOL_1_0
);
296 ~NPT_HttpRequest() override
;
299 const NPT_HttpUrl
& GetUrl() const { return m_Url
; }
300 NPT_HttpUrl
& GetUrl() { return m_Url
; }
301 NPT_Result
SetUrl(const char* url
);
302 NPT_Result
SetUrl(const NPT_HttpUrl
& url
);
303 const NPT_String
& GetMethod() const { return m_Method
; }
304 virtual NPT_Result
Emit(NPT_OutputStream
& stream
, bool use_proxy
=false) const;
312 /*----------------------------------------------------------------------
314 +---------------------------------------------------------------------*/
315 class NPT_HttpResponse
: public NPT_HttpMessage
{
318 static NPT_Result
Parse(NPT_BufferedInputStream
& stream
,
319 NPT_HttpResponse
*& response
);
321 // constructors and destructor
322 NPT_HttpResponse(NPT_HttpStatusCode status_code
,
323 const char* reason_phrase
,
324 const char* protocol
= NPT_HTTP_PROTOCOL_1_0
);
325 ~NPT_HttpResponse() override
;
328 NPT_Result
SetStatus(NPT_HttpStatusCode status_code
,
329 const char* reason_phrase
,
330 const char* protocol
= NULL
);
331 NPT_Result
SetProtocol(const char* protocol
);
332 NPT_HttpStatusCode
GetStatusCode() const { return m_StatusCode
; }
333 const NPT_String
& GetReasonPhrase() const { return m_ReasonPhrase
; }
334 virtual NPT_Result
Emit(NPT_OutputStream
& stream
) const;
338 NPT_HttpStatusCode m_StatusCode
;
339 NPT_String m_ReasonPhrase
;
342 /*----------------------------------------------------------------------
343 | NPT_HttpProxyAddress
344 +---------------------------------------------------------------------*/
345 class NPT_HttpProxyAddress
348 NPT_HttpProxyAddress() : m_Port(NPT_HTTP_INVALID_PORT
) {}
349 NPT_HttpProxyAddress(const char* hostname
, NPT_UInt16 port
) :
350 m_HostName(hostname
), m_Port(port
) {}
352 const NPT_String
& GetHostName() const { return m_HostName
; }
353 void SetHostName(const char* hostname
) { m_HostName
= hostname
; }
354 NPT_UInt16
GetPort() const { return m_Port
; }
355 void SetPort(NPT_UInt16 port
) { m_Port
= port
; }
358 NPT_String m_HostName
;
362 /*----------------------------------------------------------------------
363 | NPT_HttpProxySelector
364 +---------------------------------------------------------------------*/
365 class NPT_HttpProxySelector
369 static NPT_HttpProxySelector
* GetDefault();
370 static NPT_HttpProxySelector
* GetSystemSelector();
373 virtual ~NPT_HttpProxySelector() {};
374 virtual NPT_Result
GetProxyForUrl(const NPT_HttpUrl
& url
, NPT_HttpProxyAddress
& proxy
) = 0;
378 static NPT_HttpProxySelector
* m_SystemDefault
;
381 class NPT_HttpRequestContext
;
383 /*----------------------------------------------------------------------
385 +---------------------------------------------------------------------*/
386 class NPT_HttpClient
{
390 Config() : m_ConnectionTimeout( NPT_HTTP_CLIENT_DEFAULT_CONNECTION_TIMEOUT
),
391 m_IoTimeout( NPT_HTTP_CLIENT_DEFAULT_CONNECTION_TIMEOUT
),
392 m_NameResolverTimeout(NPT_HTTP_CLIENT_DEFAULT_NAME_RESOLVER_TIMEOUT
),
393 m_MaxRedirects( NPT_HTTP_CLIENT_DEFAULT_MAX_REDIRECTS
),
394 m_UserAgent( NPT_CONFIG_HTTP_DEFAULT_USER_AGENT
) {}
395 NPT_Timeout m_ConnectionTimeout
;
396 NPT_Timeout m_IoTimeout
;
397 NPT_Timeout m_NameResolverTimeout
;
398 NPT_Cardinal m_MaxRedirects
;
399 NPT_String m_UserAgent
;
404 virtual ~Connection() {}
405 virtual NPT_InputStreamReference
& GetInputStream() = 0;
406 virtual NPT_OutputStreamReference
& GetOutputStream() = 0;
407 virtual NPT_Result
GetInfo(NPT_SocketInfo
& info
) = 0;
408 virtual bool SupportsPersistence() { return false; }
409 virtual bool IsRecycled() { return false; }
410 virtual NPT_Result
Recycle() { delete this; return NPT_SUCCESS
; }
411 virtual NPT_Result
Abort() { return NPT_ERROR_NOT_IMPLEMENTED
; }
416 virtual ~Connector() {}
418 virtual NPT_Result
Connect(const NPT_HttpUrl
& url
,
419 NPT_HttpClient
& client
,
420 const NPT_HttpProxyAddress
* proxy
,
421 bool reuse
, // whether we can reuse a connection or not
422 Connection
*& connection
) = 0;
425 NPT_Result
TrackConnection(NPT_HttpClient
& client
,
426 Connection
* connection
) { return client
.TrackConnection(connection
); }
427 Connector() {} // don't instantiate directly
431 static NPT_Result
WriteRequest(NPT_OutputStream
& output_stream
,
432 NPT_HttpRequest
& request
,
434 bool use_proxy
= false);
435 static NPT_Result
ReadResponse(NPT_InputStreamReference
& input_stream
,
438 NPT_HttpResponse
*& response
,
439 NPT_Reference
<Connection
>* cref
= NULL
);
442 * @param connector Pointer to a connector instance, or NULL to use
443 * the default (TCP) connector.
444 * @param transfer_ownership Boolean flag. If true, the NPT_HttpClient object
445 * becomes the owner of the passed Connector and will delete it when it is
446 * itself deleted. If false, the caller keeps the ownership of the connector.
447 * This flag is ignored if the connector parameter is NULL.
449 NPT_HttpClient(Connector
* connector
= NULL
, bool transfer_ownership
= true);
451 virtual ~NPT_HttpClient();
454 NPT_Result
SendRequest(NPT_HttpRequest
& request
,
455 NPT_HttpResponse
*& response
,
456 NPT_HttpRequestContext
* context
= NULL
);
458 const Config
& GetConfig() const { return m_Config
; }
459 NPT_Result
SetConfig(const Config
& config
);
460 NPT_Result
SetProxy(const char* http_proxy_hostname
,
461 NPT_UInt16 http_proxy_port
,
462 const char* https_proxy_hostname
= NULL
,
463 NPT_UInt16 https_proxy_port
= 0);
464 NPT_Result
SetProxySelector(NPT_HttpProxySelector
* selector
);
465 NPT_Result
SetConnector(Connector
* connector
);
466 NPT_Result
SetTimeouts(NPT_Timeout connection_timeout
,
467 NPT_Timeout io_timeout
,
468 NPT_Timeout name_resolver_timeout
);
469 NPT_Result
SetUserAgent(const char* user_agent
);
470 NPT_Result
SetOptions(NPT_Flags options
, bool on
);
474 NPT_Result
TrackConnection(Connection
* connection
);
475 NPT_Result
SendRequestOnce(NPT_HttpRequest
& request
,
476 NPT_HttpResponse
*& response
,
477 NPT_HttpRequestContext
* context
= NULL
);
481 NPT_HttpProxySelector
* m_ProxySelector
;
482 bool m_ProxySelectorIsOwned
;
483 Connector
* m_Connector
;
484 bool m_ConnectorIsOwned
;
485 NPT_Mutex m_AbortLock
;
489 /*----------------------------------------------------------------------
490 | NPT_HttpConnectionManager
491 +---------------------------------------------------------------------*/
492 class NPT_HttpConnectionManager
: public NPT_Thread
,
493 public NPT_AutomaticCleaner::Singleton
496 // singleton management
497 static NPT_HttpConnectionManager
* GetInstance();
499 class Connection
: public NPT_HttpClient::Connection
502 Connection(NPT_HttpConnectionManager
& manager
,
503 NPT_SocketReference
& socket
,
504 NPT_InputStreamReference input_stream
,
505 NPT_OutputStreamReference output_stream
);
506 ~Connection() override
;
508 // NPT_HttpClient::Connection methods
509 NPT_InputStreamReference
& GetInputStream() override
{ return m_InputStream
; }
510 NPT_OutputStreamReference
& GetOutputStream() override
{ return m_OutputStream
; }
511 NPT_Result
GetInfo(NPT_SocketInfo
& info
) override
{ return m_Socket
->GetInfo(info
); }
512 bool SupportsPersistence() override
{ return true; }
513 bool IsRecycled() override
{ return m_IsRecycled
; }
514 NPT_Result
Recycle() override
;
515 NPT_Result
Abort() override
{ return m_Socket
->Cancel(); }
518 NPT_HttpConnectionManager
& m_Manager
;
520 NPT_TimeStamp m_TimeStamp
;
521 NPT_SocketReference m_Socket
;
522 NPT_InputStreamReference m_InputStream
;
523 NPT_OutputStreamReference m_OutputStream
;
527 ~NPT_HttpConnectionManager() override
;
530 Connection
* FindConnection(NPT_SocketAddress
& address
);
531 NPT_Result
Recycle(Connection
* connection
);
532 NPT_Result
Track(NPT_HttpClient
* client
, NPT_HttpClient::Connection
* connection
);
533 NPT_Result
AbortConnections(NPT_HttpClient
* client
);
536 static NPT_Result
Untrack(NPT_HttpClient::Connection
* connection
);
539 typedef NPT_List
<NPT_HttpClient::Connection
*> ConnectionList
;
542 static NPT_HttpConnectionManager
* Instance
;
545 NPT_HttpConnectionManager();
547 // NPT_Thread methods
551 NPT_Result
UntrackConnection(NPT_HttpClient::Connection
* connection
);
552 NPT_Result
Cleanup();
556 NPT_Cardinal m_MaxConnections
;
557 NPT_Cardinal m_MaxConnectionAge
;
558 NPT_SharedVariable m_Aborted
;
559 NPT_List
<Connection
*> m_Connections
;
560 NPT_Map
<NPT_HttpClient
*, ConnectionList
> m_ClientConnections
;
563 /*----------------------------------------------------------------------
564 | NPT_HttpRequestContext
565 +---------------------------------------------------------------------*/
566 class NPT_HttpRequestContext
570 NPT_HttpRequestContext() {}
571 NPT_HttpRequestContext(const NPT_SocketAddress
* local_address
,
572 const NPT_SocketAddress
* remote_address
);
575 const NPT_SocketAddress
& GetLocalAddress() const { return m_LocalAddress
; }
576 const NPT_SocketAddress
& GetRemoteAddress() const { return m_RemoteAddress
; }
577 void SetLocalAddress(const NPT_SocketAddress
& address
) {
578 m_LocalAddress
= address
;
580 void SetRemoteAddress(const NPT_SocketAddress
& address
) {
581 m_RemoteAddress
= address
;
586 NPT_SocketAddress m_LocalAddress
;
587 NPT_SocketAddress m_RemoteAddress
;
590 /*----------------------------------------------------------------------
591 | NPT_HttpRequestHandler
592 +---------------------------------------------------------------------*/
593 class NPT_HttpRequestHandler
596 NPT_IMPLEMENT_DYNAMIC_CAST(NPT_HttpRequestHandler
)
599 virtual ~NPT_HttpRequestHandler() {}
602 virtual NPT_Result
SetupResponse(NPT_HttpRequest
& request
,
603 const NPT_HttpRequestContext
& context
,
604 NPT_HttpResponse
& response
) = 0;
607 * Override this method if you want to write the body yourself.
608 * The default implementation will simply write out the entity's
611 virtual NPT_Result
SendResponseBody(const NPT_HttpRequestContext
& context
,
612 NPT_HttpResponse
& response
,
613 NPT_OutputStream
& output
);
616 * A notification method called by the server upon completing the
617 * processing of a request.
619 virtual void Completed(NPT_Result
/*result*/) {}
622 /*----------------------------------------------------------------------
623 | NPT_HttpStaticRequestHandler
624 +---------------------------------------------------------------------*/
625 class NPT_HttpStaticRequestHandler
: public NPT_HttpRequestHandler
629 NPT_HttpStaticRequestHandler(const char* document
,
630 const char* mime_type
= "text/html",
632 NPT_HttpStaticRequestHandler(const void* data
,
634 const char* mime_type
= "text/html",
637 // NPT_HttpRequestHandler methods
638 NPT_Result
SetupResponse(NPT_HttpRequest
& request
,
639 const NPT_HttpRequestContext
& context
,
640 NPT_HttpResponse
& response
) override
;
643 NPT_String m_MimeType
;
644 NPT_DataBuffer m_Buffer
;
647 /*----------------------------------------------------------------------
648 | NPT_HttpFileRequestHandler_DefaultFileTypeMapEntry
649 +---------------------------------------------------------------------*/
650 typedef struct NPT_HttpFileRequestHandler_DefaultFileTypeMapEntry
{
651 const char* extension
;
652 const char* mime_type
;
653 } NPT_HttpFileRequestHandler_FileTypeMapEntry
;
655 /*----------------------------------------------------------------------
656 | NPT_HttpFileRequestHandler
657 +---------------------------------------------------------------------*/
658 class NPT_HttpFileRequestHandler
: public NPT_HttpRequestHandler
662 NPT_HttpFileRequestHandler(const char* url_root
,
663 const char* file_root
,
664 bool auto_dir
= false,
665 const char* auto_index
= NULL
);
667 // NPT_HttpRequestHandler methods
668 NPT_Result
SetupResponse(NPT_HttpRequest
& request
,
669 const NPT_HttpRequestContext
& context
,
670 NPT_HttpResponse
& response
) override
;
673 static const char* GetDefaultContentType(const char* extension
);
676 NPT_Map
<NPT_String
,NPT_String
>& GetFileTypeMap() { return m_FileTypeMap
; }
677 void SetDefaultMimeType(const char* mime_type
) {
678 m_DefaultMimeType
= mime_type
;
680 void SetUseDefaultFileTypeMap(bool use_default
) {
681 m_UseDefaultFileTypeMap
= use_default
;
684 static NPT_Result
SetupResponseBody(NPT_HttpResponse
& response
,
685 NPT_InputStreamReference
& stream
,
686 const NPT_String
* range_spec
= NULL
);
690 const char* GetContentType(const NPT_String
& filename
);
693 NPT_String m_UrlRoot
;
694 NPT_String m_FileRoot
;
695 NPT_Map
<NPT_String
, NPT_String
> m_FileTypeMap
;
696 NPT_String m_DefaultMimeType
;
697 bool m_UseDefaultFileTypeMap
;
699 NPT_String m_AutoIndex
;
702 /*----------------------------------------------------------------------
704 +---------------------------------------------------------------------*/
705 class NPT_HttpServer
{
709 NPT_Timeout m_ConnectionTimeout
;
710 NPT_Timeout m_IoTimeout
;
711 NPT_IpAddress m_ListenAddress
;
712 NPT_UInt16 m_ListenPort
;
716 // constructors and destructor
717 NPT_HttpServer(NPT_UInt16 listen_port
= NPT_HTTP_DEFAULT_PORT
, bool cancellable
= false);
718 NPT_HttpServer(NPT_IpAddress listen_address
,
719 NPT_UInt16 listen_port
= NPT_HTTP_DEFAULT_PORT
,
720 bool cancellable
= false);
721 virtual ~NPT_HttpServer();
724 NPT_Result
SetConfig(const Config
& config
);
725 const Config
& GetConfig() const { return m_Config
; }
726 NPT_Result
SetListenPort(NPT_UInt16 port
, bool reuse_address
= true);
727 NPT_Result
SetTimeouts(NPT_Timeout connection_timeout
, NPT_Timeout io_timeout
);
728 NPT_Result
SetServerHeader(const char* server_header
);
730 NPT_Result
WaitForNewClient(NPT_InputStreamReference
& input
,
731 NPT_OutputStreamReference
& output
,
732 NPT_HttpRequestContext
* context
,
733 NPT_Flags socket_flags
= 0);
734 NPT_Result
Loop(bool cancellable_sockets
=true);
735 NPT_UInt16
GetPort() { return m_BoundPort
; }
739 * Add a request handler. By default the ownership of the handler is NOT transfered to this object,
740 * so the caller is responsible for the lifetime management of the handler object.
742 virtual NPT_Result
AddRequestHandler(NPT_HttpRequestHandler
* handler
,
744 bool include_children
= false,
745 bool transfer_ownership
= false);
746 virtual NPT_HttpRequestHandler
* FindRequestHandler(NPT_HttpRequest
& request
);
747 virtual NPT_List
<NPT_HttpRequestHandler
*> FindRequestHandlers(NPT_HttpRequest
& request
);
750 * Parse the request from a new client, form a response, and send it back.
752 virtual NPT_Result
RespondToClient(NPT_InputStreamReference
& input
,
753 NPT_OutputStreamReference
& output
,
754 const NPT_HttpRequestContext
& context
);
758 struct HandlerConfig
{
759 HandlerConfig(NPT_HttpRequestHandler
* handler
,
761 bool include_children
,
762 bool transfer_ownership
= false);
766 bool WillHandle(NPT_HttpRequest
& request
);
769 NPT_HttpRequestHandler
* m_Handler
;
771 bool m_IncludeChildren
;
772 bool m_HandlerIsOwned
;
779 NPT_TcpServerSocket m_Socket
;
780 NPT_UInt16 m_BoundPort
;
782 NPT_List
<HandlerConfig
*> m_RequestHandlers
;
783 NPT_String m_ServerHeader
;
787 /*----------------------------------------------------------------------
789 +---------------------------------------------------------------------*/
790 class NPT_HttpResponder
{
794 NPT_Timeout m_IoTimeout
;
797 // constructors and destructor
798 NPT_HttpResponder(NPT_InputStreamReference
& input
,
799 NPT_OutputStreamReference
& output
);
800 virtual ~NPT_HttpResponder();
803 NPT_Result
SetConfig(const Config
& config
);
804 NPT_Result
SetTimeout(NPT_Timeout io_timeout
);
805 NPT_Result
ParseRequest(NPT_HttpRequest
*& request
,
806 const NPT_SocketAddress
* local_address
= NULL
);
807 NPT_Result
SendResponseHeaders(NPT_HttpResponse
& response
);
812 NPT_BufferedInputStreamReference m_Input
;
813 NPT_OutputStreamReference m_Output
;
816 /*----------------------------------------------------------------------
817 | NPT_HttpChunkedInputStream
818 +---------------------------------------------------------------------*/
819 class NPT_HttpChunkedInputStream
: public NPT_InputStream
822 // constructors and destructor
823 NPT_HttpChunkedInputStream(NPT_BufferedInputStreamReference
& stream
);
824 ~NPT_HttpChunkedInputStream() override
;
826 // NPT_InputStream methods
827 NPT_Result
Read(void* buffer
,
828 NPT_Size bytes_to_read
,
829 NPT_Size
* bytes_read
= NULL
) override
;
830 NPT_Result
Seek(NPT_Position offset
) override
;
831 NPT_Result
Tell(NPT_Position
& offset
) override
;
832 NPT_Result
GetSize(NPT_LargeSize
& size
) override
;
833 NPT_Result
GetAvailable(NPT_LargeSize
& available
) override
;
837 NPT_BufferedInputStreamReference m_Source
;
838 NPT_UInt32 m_CurrentChunkSize
;
842 /*----------------------------------------------------------------------
843 | NPT_HttpChunkedOutputStream
844 +---------------------------------------------------------------------*/
845 class NPT_HttpChunkedOutputStream
: public NPT_OutputStream
848 // constructors and destructor
849 NPT_HttpChunkedOutputStream(NPT_OutputStream
& stream
);
850 ~NPT_HttpChunkedOutputStream() override
;
852 // NPT_OutputStream methods
853 NPT_Result
Write(const void* buffer
,
854 NPT_Size bytes_to_write
,
855 NPT_Size
* bytes_written
= NULL
) override
;
856 NPT_Result
Seek(NPT_Position
/*offset*/) override
{ return NPT_ERROR_NOT_SUPPORTED
;}
857 NPT_Result
Tell(NPT_Position
& offset
) override
{ return m_Stream
.Tell(offset
); }
858 NPT_Result
Flush() override
{ return m_Stream
.Flush(); }
862 NPT_OutputStream
& m_Stream
;
865 #endif // _NPT_HTTP_H_