NptHttp.h

00001 /*****************************************************************
00002 |
00003 |   Neptune - HTTP Protocol
00004 |
00005 |   (c) 2001-2006 Gilles Boccon-Gibod
00006 |   Author: Gilles Boccon-Gibod (bok@bok.net)
00007 |
00008  ****************************************************************/
00009 
00010 #ifndef _NPT_HTTP_H_
00011 #define _NPT_HTTP_H_
00012 
00013 /*----------------------------------------------------------------------
00014 |   includes
00015 +---------------------------------------------------------------------*/
00016 #include "NptUri.h"
00017 #include "NptTypes.h"
00018 #include "NptList.h"
00019 #include "NptBufferedStreams.h"
00020 #include "NptSockets.h"
00021 #include "NptMap.h"
00022 
00023 /*----------------------------------------------------------------------
00024 |   constants
00025 +---------------------------------------------------------------------*/
00026 const unsigned int NPT_HTTP_DEFAULT_PORT = 80;
00027 const unsigned int NPT_HTTP_INVALID_PORT = 0;
00028 
00029 const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_CONNECTION_TIMEOUT    = 30000;
00030 const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_IO_TIMEOUT            = 30000;
00031 const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_NAME_RESOLVER_TIMEOUT = 60000;
00032 
00033 const NPT_Timeout NPT_HTTP_SERVER_DEFAULT_CONNECTION_TIMEOUT    = NPT_TIMEOUT_INFINITE;
00034 const NPT_Timeout NPT_HTTP_SERVER_DEFAULT_IO_TIMEOUT            = 60000;
00035 
00036 const int NPT_HTTP_PROTOCOL_MAX_LINE_LENGTH  = 8192;
00037 const int NPT_HTTP_PROTOCOL_MAX_HEADER_COUNT = 100;
00038 
00039 #define NPT_HTTP_PROTOCOL_1_0   "HTTP/1.0"
00040 #define NPT_HTTP_PROTOCOL_1_1   "HTTP/1.1"
00041 #define NPT_HTTP_METHOD_GET     "GET"
00042 #define NPT_HTTP_METHOD_HEAD    "HEAD"
00043 #define NPT_HTTP_METHOD_POST    "POST"
00044 
00045 #define NPT_HTTP_HEADER_HOST                "Host"
00046 #define NPT_HTTP_HEADER_CONNECTION          "Connection"
00047 #define NPT_HTTP_HEADER_USER_AGENT          "User-Agent"
00048 #define NPT_HTTP_HEADER_CONTENT_LENGTH      "Content-Length"
00049 #define NPT_HTTP_HEADER_CONTENT_TYPE        "Content-Type"
00050 #define NPT_HTTP_HEADER_CONTENT_ENCODING    "Content-Encoding"
00051 #define NPT_HTTP_HEADER_LOCATION            "Location"
00052 #define NPT_HTTP_HEADER_RANGE               "Range"
00053 #define NPT_HTTP_HEADER_CONTENT_RANGE       "Content-Range"
00054 #define NPT_HTTP_HEADER_COOKIE              "Cookie"
00055 
00056 const int NPT_ERROR_HTTP_INVALID_RESPONSE_LINE = NPT_ERROR_BASE_HTTP - 0;
00057 const int NPT_ERROR_HTTP_INVALID_REQUEST_LINE  = NPT_ERROR_BASE_HTTP - 1;
00058 const int NPT_ERROR_HTTP_NO_PROXY              = NPT_ERROR_BASE_HTTP - 2;
00059 
00060 #define NPT_HTTP_LINE_TERMINATOR "\r\n"
00061 
00062 /*----------------------------------------------------------------------
00063 |   types
00064 +---------------------------------------------------------------------*/
00065 typedef unsigned int NPT_HttpStatusCode;
00066 typedef NPT_UrlQuery NPT_HttpUrlQuery; // for backward compatibility
00067 
00068 /*----------------------------------------------------------------------
00069 |   NPT_HttpUrl
00070 +---------------------------------------------------------------------*/
00071 class NPT_HttpUrl : public NPT_Url {
00072 public:
00073     // constructors
00074     NPT_HttpUrl() {}
00075     NPT_HttpUrl(const char* host, 
00076                 NPT_UInt16  port, 
00077                 const char* path,
00078                 const char* query = NULL,
00079                 const char* fragment = NULL);
00080     NPT_HttpUrl(const char* url, bool ignore_scheme = false);
00081 
00082     // methods
00083     virtual NPT_String ToString(bool with_fragment = true) const;
00084 };
00085 
00086 /*----------------------------------------------------------------------
00087 |   NPT_HttpProtocol
00088 +---------------------------------------------------------------------*/
00089 class NPT_HttpProtocol
00090 {
00091 public:
00092     // class methods
00093     const char* GetStatusCodeString(NPT_HttpStatusCode status_code);
00094 };
00095 
00096 /*----------------------------------------------------------------------
00097 |   NPT_HttpHeader
00098 +---------------------------------------------------------------------*/
00099 class NPT_HttpHeader {
00100 public:
00101     // constructors and destructor
00102     NPT_HttpHeader(const char* name, const char* value);
00103     ~NPT_HttpHeader();
00104 
00105     // methods
00106     NPT_Result        Emit(NPT_OutputStream& stream) const;
00107     const NPT_String& GetName()  const { return m_Name;  }
00108     const NPT_String& GetValue() const { return m_Value; }
00109     NPT_Result        SetName(const char* name);
00110     NPT_Result        SetValue(const char* value);
00111 
00112 private:
00113     // members
00114     NPT_String m_Name;
00115     NPT_String m_Value;
00116 };
00117 
00118 /*----------------------------------------------------------------------
00119 |   NPT_HttpHeaders
00120 +---------------------------------------------------------------------*/
00121 class NPT_HttpHeaders {
00122 public:
00123     // constructors and destructor
00124      NPT_HttpHeaders();
00125     ~NPT_HttpHeaders();
00126 
00127     // methods
00128     NPT_Result Emit(NPT_OutputStream& stream) const;
00129     NPT_List<NPT_HttpHeader*>& GetHeaders() { return m_Headers; }
00130     NPT_HttpHeader*   GetHeader(const char* name) const;
00131     const NPT_String* GetHeaderValue(const char* name) const;
00132     NPT_Result        SetHeader(const char* name, const char* value);
00133     NPT_Result        AddHeader(const char* name, const char* value);
00134 
00135 private:
00136     // members
00137     NPT_List<NPT_HttpHeader*> m_Headers;
00138 };
00139 
00140 /*----------------------------------------------------------------------
00141 |   NPT_HttpEntity
00142 +---------------------------------------------------------------------*/
00143 class NPT_HttpEntity {
00144 public:
00145     // constructors and destructor
00146              NPT_HttpEntity();
00147              NPT_HttpEntity(const NPT_HttpHeaders& headers);
00148     virtual ~NPT_HttpEntity();
00149 
00150     // methods
00151     NPT_Result SetInputStream(const NPT_InputStreamReference& stream,
00152                               bool update_content_length = false);
00153     NPT_Result SetInputStream(const void* data, NPT_Size size);
00154     NPT_Result SetInputStream(const NPT_String& string);
00155     NPT_Result SetInputStream(const char* string);
00156     NPT_Result GetInputStream(NPT_InputStreamReference& stream);
00157     NPT_Result Load(NPT_DataBuffer& buffer);
00158     NPT_Result SetHeaders(const NPT_HttpHeaders& headers);
00159 
00160     // field access
00161     NPT_Result        SetContentType(const char* type);
00162     NPT_Result        SetContentEncoding(const char* encoding);
00163     NPT_Result        SetContentLength(NPT_Size length);
00164     NPT_Size          GetContentLength()   { return m_ContentLength;   }
00165     const NPT_String& GetContentType()     { return m_ContentType;     }
00166     const NPT_String& GetContentEncoding() { return m_ContentEncoding; }
00167 
00168 private:
00169     // members
00170     NPT_InputStreamReference m_InputStream;
00171     NPT_Size                 m_ContentLength;
00172     NPT_String               m_ContentType;
00173     NPT_String               m_ContentEncoding;
00174 };
00175 
00176 /*----------------------------------------------------------------------
00177 |   NPT_HttpMessage
00178 +---------------------------------------------------------------------*/
00179 class NPT_HttpMessage {
00180 public:
00181     // constructors and destructor
00182     virtual ~NPT_HttpMessage();
00183 
00184     // methods
00185     const NPT_String& GetProtocol() const { 
00186         return m_Protocol; 
00187     }
00188     NPT_Result SetProtocol(const char* protocol) {
00189         m_Protocol = protocol;
00190         return NPT_SUCCESS;
00191     }
00192     NPT_HttpHeaders& GetHeaders() { 
00193         return m_Headers;  
00194     }
00195     NPT_Result SetEntity(NPT_HttpEntity* entity);
00196     NPT_HttpEntity* GetEntity() {
00197         return m_Entity;
00198     }
00199     virtual NPT_Result ParseHeaders(NPT_BufferedInputStream& stream);
00200 
00201 protected:
00202     // constructors
00203     NPT_HttpMessage(const char* protocol);
00204 
00205     // members
00206     NPT_String      m_Protocol;
00207     NPT_HttpHeaders m_Headers;
00208     NPT_HttpEntity* m_Entity;
00209 };
00210 
00211 /*----------------------------------------------------------------------
00212 |   NPT_HttpRequest
00213 +---------------------------------------------------------------------*/
00214 class NPT_HttpRequest : public NPT_HttpMessage {
00215 public:
00216     // class methods
00217     static NPT_Result Parse(NPT_BufferedInputStream& stream, 
00218                             const NPT_SocketAddress* endpoint,
00219                             NPT_HttpRequest*&        request);
00220 
00221     // constructors and destructor
00222     NPT_HttpRequest(const NPT_HttpUrl& url,
00223                     const char*        method,
00224                     const char*        protocol = NPT_HTTP_PROTOCOL_1_0);
00225     NPT_HttpRequest(const char*        url,
00226                     const char*        method,
00227                     const char*        protocol = NPT_HTTP_PROTOCOL_1_0);
00228     virtual ~NPT_HttpRequest();
00229 
00230     // methods
00231     const NPT_HttpUrl& GetUrl() const { return m_Url; }
00232     NPT_HttpUrl&       GetUrl()       { return m_Url; }
00233     NPT_Result         SetUrl(const char* url);
00234     NPT_Result         SetUrl(const NPT_HttpUrl& url);
00235     const NPT_String&  GetMethod() const { return m_Method; }
00236     virtual NPT_Result Emit(NPT_OutputStream& stream, bool use_proxy=false) const;
00237     
00238 protected:
00239     // members
00240     NPT_HttpUrl m_Url;
00241     NPT_String  m_Method;
00242 };
00243 
00244 /*----------------------------------------------------------------------
00245 |   NPT_HttpResponse
00246 +---------------------------------------------------------------------*/
00247 class NPT_HttpResponse : public NPT_HttpMessage {
00248 public:
00249     // class methods
00250     static NPT_Result Parse(NPT_BufferedInputStream& stream, 
00251                             NPT_HttpResponse*&       response);
00252 
00253     // constructors and destructor
00254              NPT_HttpResponse(NPT_HttpStatusCode status_code,
00255                               const char*        reason_phrase,
00256                               const char*        protocol = NPT_HTTP_PROTOCOL_1_0);
00257     virtual ~NPT_HttpResponse();
00258 
00259     // methods
00260     NPT_Result         SetStatus(NPT_HttpStatusCode status_code,
00261                                  const char*        reason_phrase,
00262                                  const char*        protocol = NPT_HTTP_PROTOCOL_1_0);
00263     NPT_HttpStatusCode GetStatusCode()   { return m_StatusCode;   }
00264     NPT_String&        GetReasonPhrase() { return m_ReasonPhrase; }
00265     virtual NPT_Result Emit(NPT_OutputStream& stream) const;
00266 
00267 protected:
00268     // members
00269     NPT_HttpStatusCode m_StatusCode;
00270     NPT_String         m_ReasonPhrase;
00271 };
00272 
00273 /*----------------------------------------------------------------------
00274 |   NPT_HttpProxyAddress
00275 +---------------------------------------------------------------------*/
00276 class NPT_HttpProxyAddress
00277 {
00278 public:
00279     NPT_HttpProxyAddress() : m_Port(NPT_HTTP_INVALID_PORT) {}
00280     NPT_HttpProxyAddress(const char* hostname, NPT_UInt16 port) :
00281         m_HostName(hostname), m_Port(port) {}
00282 
00283     const NPT_String& GetHostName() const { return m_HostName; } 
00284     void              SetHostName(const char* hostname) { m_HostName = hostname; }
00285     NPT_UInt16        GetPort() const { return m_Port; }
00286     void              SetPort(NPT_UInt16 port) { m_Port = port; }
00287 
00288 private:
00289     NPT_String m_HostName;
00290     NPT_UInt16 m_Port;
00291 };
00292 
00293 /*----------------------------------------------------------------------
00294 |   NPT_HttpProxySelector
00295 +---------------------------------------------------------------------*/
00296 class NPT_HttpProxySelector
00297 {
00298 public:
00299     // class methods
00300     static NPT_HttpProxySelector* GetSystemDefault();
00301 
00302     // methods
00303     virtual ~NPT_HttpProxySelector() {};
00304     virtual NPT_Result GetProxyForUrl(const NPT_HttpUrl& url, NPT_HttpProxyAddress& proxy) = 0;
00305 };
00306 
00307 /*----------------------------------------------------------------------
00308 |   NPT_HttpClient
00309 +---------------------------------------------------------------------*/
00310 class NPT_HttpClient {
00311 public:
00312     // types
00313     struct Config {
00314         NPT_Timeout m_ConnectionTimeout;
00315         NPT_Timeout m_IoTimeout;
00316         NPT_Timeout m_NameResolverTimeout;
00317         bool        m_FollowRedirect;
00318     };
00319 
00320     class Connector {
00321     public:
00322         virtual ~Connector() {}
00323 
00324         virtual NPT_Result Connect(const char*                hostname, 
00325                                    NPT_UInt16                 port, 
00326                                    NPT_Timeout                connection_timeout,
00327                                    NPT_Timeout                io_timeout,
00328                                    NPT_Timeout                name_resolver_timeout,
00329                                    NPT_InputStreamReference&  input_stream,
00330                                    NPT_OutputStreamReference& output_stream) = 0;
00331 
00332     };
00333 
00338     NPT_HttpClient(Connector* connector = NULL);
00339 
00340     virtual ~NPT_HttpClient();
00341 
00342     // methods
00343     NPT_Result SendRequest(NPT_HttpRequest&   request,
00344                            NPT_HttpResponse*& response);
00345     NPT_Result SetConfig(const Config& config);
00346     NPT_Result SetProxy(const char* hostname, NPT_UInt16 port);
00347     NPT_Result SetProxySelector(NPT_HttpProxySelector* selector);
00348     NPT_Result SetTimeouts(NPT_Timeout connection_timeout,
00349                            NPT_Timeout io_timeout,
00350                            NPT_Timeout name_resolver_timeout);
00351 
00352 protected:
00353     // methods
00354     NPT_Result SendRequestOnce(NPT_HttpRequest&   request,
00355                                NPT_HttpResponse*& response);
00356 
00357     // members
00358     Config                 m_Config;
00359     NPT_HttpProxySelector* m_ProxySelector;
00360     bool                   m_ProxySelectorIsOwned;
00361     Connector*             m_Connector;
00362 };
00363 
00364 /*----------------------------------------------------------------------
00365 |   NPT_HttpRequestContext
00366 +---------------------------------------------------------------------*/
00367 class NPT_HttpRequestContext
00368 {
00369 public:
00370     // constructor
00371     NPT_HttpRequestContext() {}
00372     NPT_HttpRequestContext(const NPT_SocketAddress* local_address,
00373                            const NPT_SocketAddress* remote_address);
00374                   
00375     // methods
00376     const NPT_SocketAddress& GetLocalAddress()   const { return m_LocalAddress;  }
00377     const NPT_SocketAddress& GetRemoteAddress() const { return m_RemoteAddress; }
00378     void SetLocalAddress(const NPT_SocketAddress& address) {
00379         m_LocalAddress = address;
00380     }
00381     void SetRemoteAddress(const NPT_SocketAddress& address) {
00382         m_RemoteAddress = address;
00383     }
00384     
00385 private:
00386     // members
00387     NPT_SocketAddress m_LocalAddress;
00388     NPT_SocketAddress m_RemoteAddress;
00389 };
00390 
00391 /*----------------------------------------------------------------------
00392 |   NPT_HttpRequestHandler
00393 +---------------------------------------------------------------------*/
00394 class NPT_HttpRequestHandler 
00395 {
00396 public:
00397     // destructor
00398     virtual ~NPT_HttpRequestHandler() {}
00399 
00400     // methods
00401     virtual NPT_Result SetupResponse(NPT_HttpRequest&              request,
00402                                      const NPT_HttpRequestContext& context,
00403                                      NPT_HttpResponse&             response) = 0;
00404 };
00405 
00406 /*----------------------------------------------------------------------
00407 |   NPT_HttpStaticRequestHandler
00408 +---------------------------------------------------------------------*/
00409 class NPT_HttpStaticRequestHandler : public NPT_HttpRequestHandler
00410 {
00411 public:
00412     // constructors
00413     NPT_HttpStaticRequestHandler(const char* document, 
00414                                  const char* mime_type = "text/html",
00415                                  bool        copy = true);
00416     NPT_HttpStaticRequestHandler(const void* data,
00417                                  NPT_Size    size,
00418                                  const char* mime_type = "text/html",
00419                                  bool        copy = true);
00420 
00421     // NPT_HttpRequetsHandler methods
00422     virtual NPT_Result SetupResponse(NPT_HttpRequest&              request, 
00423                                      const NPT_HttpRequestContext& context,
00424                                      NPT_HttpResponse&             response);
00425 
00426 private:
00427     NPT_String     m_MimeType;
00428     NPT_DataBuffer m_Buffer;
00429 };
00430 
00431 /*----------------------------------------------------------------------
00432 |   NPT_HttpFileRequestHandler
00433 +---------------------------------------------------------------------*/
00434 class NPT_HttpFileRequestHandler : public NPT_HttpRequestHandler
00435 {
00436 public:
00437     // constructors
00438     NPT_HttpFileRequestHandler(const char* url_root,
00439                                const char* file_root);
00440 
00441     // NPT_HttpRequetsHandler methods
00442     virtual NPT_Result SetupResponse(NPT_HttpRequest&              request, 
00443                                      const NPT_HttpRequestContext& context,
00444                                      NPT_HttpResponse&             response);
00445 
00446     // accessors
00447     NPT_Map<NPT_String,NPT_String>& GetFileTypeMap() { return m_FileTypeMap; }
00448     void SetDefaultMimeType(const char* mime_type) {
00449         m_DefaultMimeType = mime_type;
00450     }
00451     void SetUseDefaultFileTypeMap(bool use_default) {
00452         m_UseDefaultFileTypeMap = use_default;
00453     }
00454 
00455 protected:
00456     // methods
00457     const char* GetContentType(const NPT_String& filename);
00458 
00459 private:
00460     NPT_String                      m_UrlRoot;
00461     NPT_String                      m_FileRoot;
00462     NPT_Map<NPT_String, NPT_String> m_FileTypeMap;
00463     NPT_String                      m_DefaultMimeType;
00464     bool                            m_UseDefaultFileTypeMap;
00465 };
00466 
00467 /*----------------------------------------------------------------------
00468 |   NPT_HttpServer
00469 +---------------------------------------------------------------------*/
00470 class NPT_HttpServer {
00471 public:
00472     // types
00473     struct Config {
00474         NPT_Timeout m_ConnectionTimeout;
00475         NPT_Timeout m_IoTimeout;
00476         NPT_UInt16  m_ListenPort;
00477     };
00478 
00479     // constructors and destructor
00480     NPT_HttpServer(NPT_UInt16 listen_port = NPT_HTTP_DEFAULT_PORT);
00481     virtual ~NPT_HttpServer();
00482 
00483     // methods
00484     NPT_Result SetConfig(const Config& config);
00485     NPT_Result SetListenPort(NPT_UInt16 port);
00486     NPT_Result SetTimeouts(NPT_Timeout connection_timeout, NPT_Timeout io_timeout);
00487     NPT_Result WaitForNewClient(NPT_InputStreamReference&  input,
00488                                 NPT_OutputStreamReference& output,
00489                                 NPT_HttpRequestContext*    context);
00490     NPT_Result Loop();
00491     
00496     NPT_Result AddRequestHandler(NPT_HttpRequestHandler* handler, const char* path, bool include_children = false);
00497     NPT_HttpRequestHandler* FindRequestHandler(NPT_HttpRequest& request);
00498 
00502     NPT_Result RespondToClient(NPT_InputStreamReference&     input,
00503                                NPT_OutputStreamReference&    output,
00504                                const NPT_HttpRequestContext& context);
00505 
00506 protected:
00507     // types
00508     struct HandlerConfig {
00509         HandlerConfig(NPT_HttpRequestHandler* handler,
00510                       const char*             path,
00511                       bool                    include_children);
00512         ~HandlerConfig();
00513 
00514         // methods
00515         bool WillHandle(NPT_HttpRequest& request);
00516 
00517         // members
00518         NPT_HttpRequestHandler* m_Handler;
00519         NPT_String              m_Path;
00520         bool                    m_IncludeChildren;
00521     };
00522 
00523     // methods
00524     NPT_Result Bind();
00525 
00526     // members
00527     NPT_TcpServerSocket      m_Socket;
00528     NPT_UInt16               m_BoundPort;
00529     Config                   m_Config;
00530     NPT_List<HandlerConfig*> m_RequestHandlers;
00531 };
00532 
00533 /*----------------------------------------------------------------------
00534 |   NPT_HttpResponder
00535 +---------------------------------------------------------------------*/
00536 class NPT_HttpResponder {
00537 public:
00538     // types
00539     struct Config {
00540         NPT_Timeout m_IoTimeout;
00541     };
00542 
00543     // constructors and destructor
00544     NPT_HttpResponder(NPT_InputStreamReference&  input,
00545                       NPT_OutputStreamReference& output);
00546     virtual ~NPT_HttpResponder();
00547 
00548     // methods
00549     NPT_Result SetConfig(const Config& config);
00550     NPT_Result SetTimeout(NPT_Timeout io_timeout);
00551     NPT_Result ParseRequest(NPT_HttpRequest*&        request,
00552                             const NPT_SocketAddress* local_address = NULL);
00553     NPT_Result SendResponse(NPT_HttpResponse& response,
00554                             bool              headers_only = false);
00555 
00556 protected:
00557     // members
00558     Config                           m_Config;
00559     NPT_BufferedInputStreamReference m_Input;
00560     NPT_OutputStreamReference        m_Output;
00561 };
00562 
00563 #endif // _NPT_HTTP_H_
00564