httplib

The HTTPlib is a collection of classes to handle HTTP Headers (reading / creating them). They are used by the webserver, so normally there is no need to use them as long as you don't use IWebserverPassthrough. There it could become in handy using the HTTPlib classes to handle the HTTP header stuff. After setting the version number and the HTTP result (or the HTTP request method), the header is prepared to be send. You can set what ever field you want to and send that header directly by getting the buffer to the byte-stream and the size of it. So there is no need for any other function to prepare a http header. Just set the version, the request or result, what ever field you want to set more (it will always be a good idea to set at least the content length, even if it will be 0) and send the header.

File information

Filecommon/lib/httplib.h

Classes HTTPLib
HTTPHeader
HTTPParser
UHTTPParser
HTTPHeaderField
HTTPRange

Data types CLRF
HTTP_GET_KEY
HTTP_HEAD_KEY
HTTP_POST_KEY
HTTP_PUT_KEY
HTTP_CONNECT_KEY
HTTP_OPTIONS_KEY
HTTP_TRACE_KEY
HTTP_PROPFIND_KEY
HTTP_MKCOL_KEY
HTTP_COPY_KEY
HTTP_MOVE_KEY
HTTP_DELETE_KEY
HTTP_LOCK_KEY
HTTP_UNLOCK_KEY
HTTP_PROPPATCH_KEY
HTTP_SYSCLIENT_KEY
HTTP_VERSION_1_0
HTTP_VERSION_1_1
HTTPLib::http_request_method_t
HTTPLib::http_connection_t
HTTPLib::http_upgrade_t
HTTPLib::http_encoding_t
HTTPLib::http_result_t
HTTP result codes

Examples Code Example

Classes

HTTPLib

class HTTPLib {
public:
    static inline const char * GetHTTPRequestMethodName(http_request_method_t method);
};

This class actually is only for wrapping the types and constants used by the HTTP lib (beside the one helper function described here). The other parts of that class are described in the data types section of this document (see below).

Public functions

GetHTTPRequestMethodName
This inline function simply is for getting the name (as string) for a given HTTP method.

Parameters

http_request_method_t methodThe method id to get the name for.

Return Values

The name of the method as string.

HTTPHeader

class HTTPHeader {
public:
    HTTPHeader();
    ~HTTPHeader();

    void SetHTTPVersion(int major, int minor);
    void SetHTTPResult(const HTTPLib::http_result_t * result);
    void SetContentSize(size_t size);
    void SetContentRange(size_t start, size_t end, size_t completeSize);
    void SetContentType(const char * contentType);
    void SetEncoding(HTTPLib::http_encoding_t enc);
    void SetETag(const char * etag);
    void SetConnection(HTTPLib::http_connection_t connection);
    void SetUpgrade(HTTPLib::http_upgrade_t upgrade);
    void SetWebsocketAcceptKey(const char * key);
    void SetCustomField(const char * field);
    void SetCustomField(const char * field, const char * value);
    void SetDate();
    void SetRequest(HTTPLib::http_request_method_t req, const char * resource);

    const char * GetHeaderData() { return buffer; }
    size_t GetHeaderSize() { return contentSize; }
};

This class is used for creating an HTTP header asresponse or request. If you want to parse an HTTP Header, HTTPParse must be used.

Public functions

SetHTTPVersion
Sets the major and minor version of the HTTP protocol you want to use. If a header will be created as a response, the HTTP version requested can be obtained from an HTTPParser instance by calling HTTPParser::GetMajorVersion() or HTTPParser::GetMinorVersion() and set the same version for the response as used for the request.

This function must be called before using any other function, or the header you're going to build up will be incorrect. However, if you need to build a HTTP header multiple times for response to requests, you can reuse a HTTPHeader instance, setting the version only once and reuse it by setting the HTTP result code at first.

Parameters

int majorThe major HTTP version to set.
int minorThe minor HTTP version to set.
SetHTTPResult
Set the result code for the HTTP header, to response to a HTTP request. This function will reset all other, previous set header data (except the HTTP version). So by setting the result code first n already existing HTTPHeader object can be reused for further response header creation.

Parameters

HTTPLib::http_result_t * resultPointer to the result code. Must be one of the HTTPLib::HTTP_* constants (see below).
SetContentSize
Set the content-length field of the header. It should be set every time, regardless if the size is 0 (for no content) or not.

Parameters

size_t sizeThe content length to set.
SetContentRange
Set the Content-Range field of the header. The start and end values are numbered from 0. The range field will be encoded with the given complete size in the format "start-end/completeSize".

Parameters

size_t startThe start of the range.
size_t endThe end of the range.
size_t completeSizeThe complete size of the requested resource.
SetContentType
Set the mime-type of the content field of the header.

Parameters

const char * contentTypeThe mime-type of the content to set (e. g. "text/html; charset=utf-8").
SetContentType
Set the mime-type of the content field of the header.

Parameters

const char * contentTypeThe mime-type of the content to set (e. g. "text/html; charset=utf-8").
SetContSetEncodingentType
Set the encoding of the content. For now, there are only two encoding type: HTTP_ENCODING_NONE and HTTP_ENCODING_GZIP if the content is in gzip compressed format.

Parameters

HTTPLib::http_encoding_t encThe encoding type to set.
SetETag
Set the etag. The etag field will be used to support browser side caching of data.

Parameters

const char * etagThe etag to set.
SetConnection
Set the connection type.

Parameters

HTTPLib::http_connection_t connectionThe type of the connection (HTTP_CONNECTION_NONE, HTTP_CONNECTION_KEEP_ALIVE, HTTP_CONNECTION_UPGRADE).
SetUpgrade
Set the upgrade type for connections defined with HTTP_CONNECTION_UPGRADE. For now, only HTTP_UPGRADE_WEBSOCKET is supported.

Parameters

HTTPLib::http_upgrade_t upgradeThe upgrade type for the connection.
SetWebsocketAcceptKey
Set the key to accept incomming websocket connection (only for response headers).

Parameters

const char * keyThe key to set.
SetCustomField (overloaded)
Set a custom header field. In this version of the function, the header field with the value must be given with the HTTP header conform format ("FieldName: Value"). Custom header field means not only totally user defined header fields, but also every protocol defined header field not covered by any of the other Set*() functions.

Parameters

const char * keyThe headerfield with the value to set.
SetCustomField (overloaded)
Set a custom header field. In this version, the header field anem and the value can be given seperately. Custom header field means not only totally user defined header fields, but also every protocol defined header field not covered by any of the other Set*() functions.

Parameters

const char * fieldThe name of the headerfield to set.
const char * keyThe value for that field.
SetDate
Set the date-time field for the HTTP header, using the current time.
SetRequest
(For request only) Set the request the header is for. This function resets all internal fields, starting to build up a new header.

Parameters

HTTPLib::http_request_method_t methodThe HTTP request method to build the header for.
const char * resourceThe resource to request.
GetHeaderData

Return Value

The http header in completely build up version, ready to send.
GetHeaderSize

Return Value

The length of the HTTP header.

HTTPParser

class HTTPParser {
public:
    typedef enum {
        HTTP_PARSE_DONE,
        HTTP_PARSE_NEED_DATA,
        HTTP_PARSE_CANCEL,
        HTTP_PARSE_ERROR
    } parseresult_t;

    HTTPParser();
    ~HTTPParser();

    size_t ParseData(char * data, size_t len, UHTTPParser * user = nullptr);

    parseresult_t GetParseResult() const { return (parseresult_t)parseResult; }
    HTTPLib::http_encoding_t GetAcceptEncoding() const { return acceptEncoding; }
    HTTPLib::http_request_method_t GetRequestMethod() const { return reqMethod; }
    const char * GetRequestTarget() const { return requestTarget; }
    const char * GetRequestParameters() const { return requestParameters; }
    int GetMajorVersion() const { return httpVersion >> 8; }
    int GetMinorVersion() const { return httpVersion & 0x00FF; }
    int GetVersion() const { return httpVersion; }
    const HTTPHeaderField * GetHeaderField(const char * fieldName)  const;

    size_t GetContentLength() const { return contentLength; }
    bool IsConnectionType(HTTPLib::http_connection_t ct) const { return (connectionType & ct) != 0; }
    bool IsChunkedTransfer();
    const char * GetCookie() const { return cookie; }
    const char * GetETag() const { return etag; }
    const char * GetContentType() const { return contentType; }
    const char * GetHost() const { return host; }
    HTTPLib::http_upgrade_t GetUpgrade() const { return upgradeType; }
    const HTTPRange * GetRange() const { return rangeListStart; }
    size_t GetRangeCount() const { return rangeCount; }
    HTTPLib::http_encoding_t GetEncoding() const { return encoding; }

    const char * GetWebsocketKey() const { return websocketKey; }
    int GetWebsocketVersion() const { return websocketVersion; }
    const char * GetOrigin() const { return origin; }

    const HTTPLib::http_result_t * GetHTTPResultCode() const { return httpResultCode; }

    size_t GetHeaderSize() const { return 0; }
    char * MakeHeaderCopy() const { return nullptr; };
    void GetFieldListCopy(byte * & buffer, size_t & bufferSize) const;
};

This class will be used to parse a byte stream for a HTTP header and extract the fields / data from the header. Note that the byte stream must begin with a valid HTTP header, or an error will be returned.

Public functions

ParseData
Parsed the given data with the given length. You have to first call this function and then call GetParseResult() to check the status of the parsing process. Everything will be copied to an inside buffer, so the given buffer can be reused to receive additional header data to parse.

Parameters

char * dataThe data to parse.
size_t lenThe number of bytes inside the given data buffer.
UHTTPParser * userAn UHTTPParser instance that will be called after the request line had been parsed. This helps to define, wheter parsing should continue or not. See UHTTPParser for more information.

Callbacks

If the header indicates a HTTP request and if user is not nullptr, UHTTPParser::HTTPParserValidateRequest() will be called after parsing the first line (which is the request line), so that the request can be accepted or recjected before continue parsing the rest of the header.

Return Values

The number of bytes processed from the given data buffer. If less then len, the value should be added to data to acces the data behind the header inside the byte stream.
GetParseResult

Return Value

The result of the last ParseData() call. The result determines how to continue and will be one of the following value:
GetAcceptEncoding

Return Value

Returns the encoding the other requested server or requesting client side will accept. For now, HTTPlib only support the GZIP encoding (HTTP_ENCODING_GZIP).
GetRequestMethod

Return Value

Returns the request method of the header. Will be one of the following values:
GetRequestTarget

Return Value

Retruns the requested target aka requested resource.
GetMajorVersion

Return Value

Retruns the major version of the HTTP protocol for the request.
GetMinorVersion

Return Value

Retruns the minor version of the HTTP protocol for the request.
GetHeaderField
Use this function to ask for a specified header field. Use this if the headerfield you need canot be accessed through the functions of the mostly used header fields provided by HTTPParser.

Parameters

const char * fieldNameThe name of the header field to get.

Return Value

If the header field canot be found, the function returns nullptr. Else a HTTPHeaderField instance will be returned, providing the detail of the field. That instance canot be deleted and will completely managed by HTTPParser itself.
GetContentLength

Return Value

(For response only) Reports the content length defined by the header. This will be the amount of data to read from the byte stream to completely process the response. Can be 0.

Remarks

The return value of 0 doesn't mean, that there is no further data to process. The data send with a response can also be chunk encoded. Check IsChunkedTransfer() to get that information.
IsConnectionType
Can be used to check if the parsed header defines a special type of connection.

Parameters

HTTPLib::http_connection_t ctThe connection type to check for.

Return Value

True, of the conenction type given is defined in the header, else false.

Remarks

The value for ct must be HTTP_CONNECTION_NONE, HTTP_CONNECTION_KEEP_ALIVE or HTTP_CONNECTION_UPGRADE. See the data types section below for details.
IsChunkedTransfer

Return Value

True, if there is data available in chunk encoded format. reading and handling the cunks will be the applications responsebility.
GetCookie

Return Value

Returns the value of the cookie header field.
GetETag

Return Value

Returns the value of the etag header field.
GetContentType

Return Value

Returns the content type (aka mime-type) declared by the header.
GetHost

Return Value

Returns the host reported by the header.
GetUpgrade

Return Value

Returns the upgrade type (if there is any). For now, the HTTPlib only supports HTTP_UPGRADE_WEBSOCKET.
GetRange

Return Value

Returns an HTTPRange object to access the values given by the range header field. If there is no range request, nullptr will be returned. The returned object is the start of a linked list of ranges. See HTTPRange for more information.
GetEncoding

Return Value

Returns the value of the headers content-encoding field.
GetWebsocketKey

Return Value

Returns the websocket key.
GetWebsocketVersion

Return Value

Returns the requested websocket version.
GetOrigin

Return Value

Returns the value of the origin field.
GetHTTPResultCode

Return Value

For response headers, the function returns the HTTP result code of the previous request. If the incomming header was a request and there was an error during parsing the header, the function returns the HTTP result code to send as an answer.
GetFieldListCopy
Makes a copy of the field list from the header.

Parameters

byte * & buffer(Out) A reference to a byte * variable the buffer with the copy will be written to.
size_t & bufferSize(Out) A reference to a size_t variable the size of the buffer with the copy will be written to.

Return Value

After creating the copy, the pointer to the malloced buffer will be stored int the variable bufffer, and the size of it in bufferSize. The caller is responsible for releasing the buffer if no longer needed by calling free(buffer).

UHTTPParser

class UHTTPParser {
public:
    virtual ~UHTTPParser() {}
    virtual bool HTTPParserValidateRequest(class HTTPParser * httpParser) = 0;
};

This class is for passing a user to HTTPParser::ParseData(). After parsing the request line, UHTTPParser::HTTPParserValidateRequest() will be called. The app can check the request and validate it the HTTPParser continues with parsing the rest of the header. This can be done by checking the values of the given HTTPParser instance. Note that only the request type and the requested resource will be available at this point, but no header fields.

Public functions

HTTPParserValidateRequest
Will be called after parsing the request line to let the app decide, whether to continue parsing or not.

Parameters

HTTPParser * httpParserThe calling HTTPParser object.

Return Value

True to continue parsing, false to cancel it.

Remarks

When canceling the parsing process, the app must take care of eating up all unused data to clean the byte stream (if the same byte stream should be used for parsing the next header).

HTTPHeaderField

class HTTPHeaderField {
public:
    const char * GetValue(size_t idx) const { return values[idx]; }
    size_t GetValueCount() const { return valueCount; }
};

Represents a HTTP header field and its values. Even if a field can have more values (that means, that field appears mutltiple times in the header), there also can be multiple values set, seperated by ';'. Those will be handled as one value only, so an app must seperate them if needed. An header field can be obtained by calling HTTPParser::GetHeaderField().

Public functions

GetValue
Returns the value of the header field.

Parameters

size_t idxThe index of the value to get. Must be between 0 and GetValueCount().

Return Value

The value of the header.

Remarks

Don't manipulate that string (even not by typecasting). If there is need to edit the items, a copy of that return value mast be made.
GetValueCount

Return Value

The number of values available for that field.

HTTPRange

class HTTPRange {
public:
    HTTPRange() { this->next = NULL; }
    virtual ~HTTPRange() {}

    enum {
        RANGE_NONE        = 0x00,
        RANGE_START_END   = 0x01,
        RANGE_START_ONLY  = 0x02,
        RANGE_LAST_BYTES  = 0x03
    } rangeType;
    size_t start;
    size_t end;
    HTTPRange * next;
};

Represents the values of ranges send with an HTTP header. An instance of HTTPRange will be returned by HTTPParser::GetRange(). The retunred instance is the start of a linked list. So you must not call delete on it! HTTPParser itself will take care of releasing the objects when needed. The class itself has no functions. You have access directly to the fields of the class.

start
The start of the range given by the HTTP header.
end
The end of the range given by the HTTP header.
rangeType
The type of the range. Depending on the type the values of start and end need to be interpreted. rangeType can be one of the following:

Data types

Defines / Statics

#define CLRF                 "\r\n"

#define HTTP_GET_KEY         "GET"       
#define HTTP_HEAD_KEY        "HEAD"      
#define HTTP_POST_KEY        "POST"      
#define HTTP_PUT_KEY         "PUT"       
#define HTTP_CONNECT_KEY     "CONNECT"   
#define HTTP_OPTIONS_KEY     "OPTIONS"   
#define HTTP_TRACE_KEY       "TRACE"     
#define HTTP_PROPFIND_KEY    "PROPFIND"
#define HTTP_MKCOL_KEY       "MKCOL"
#define HTTP_COPY_KEY        "COPY"
#define HTTP_MOVE_KEY        "MOVE"
#define HTTP_DELETE_KEY      "DELETE"
#define HTTP_LOCK_KEY        "LOCK"
#define HTTP_UNLOCK_KEY      "UNLOCK"
#define HTTP_PROPPATCH_KEY   "PROPPATCH"
#define HTTP_SYSCLIENT_KEY   "SYSCLIENT"

#define HTTP_VERSION_1_0    0x0100
#define HTTP_VERSION_1_1    0x0101

CLRFThe end of line, used inside the HTTP header. The Header ends with on empty line, which is a line that only holds CLRF.
HTTP_GET_KEYThe keyword for a GET request.
HTTP_HEAD_KEYThe keyword for a HEAD request.
HTTP_POST_KEYThe keyword for a POST request.
HTTP_PUT_KEYThe keyword for a PUT request.
HTTP_CONNECT_KEYThe keyword for a CONNECT request.
HTTP_OPTIONS_KEYThe keyword for a OPTIONS request.
HTTP_TRACE_KEYThe keyword for a TRACE request.
HTTP_PROPFIND_KEYThe keyword for a PROPFIND request.
HTTP_MKCOL_KEYThe keyword for a MKCOL request.
HTTP_COPY_KEYThe keyword for a COPY request.
HTTP_MOVE_KEYThe keyword for a MOVE request.
HTTP_DELETE_KEYThe keyword for a DELETE request.
HTTP_LOCK_KEYThe keyword for a LOCK request.
HTTP_UNLOCK_KEYThe keyword for a UNLOCK request.
HTTP_PROPPATCH_KEYThe keyword for a PROPPATCH request.
HTTP_SYSCLIENT_KEYInternally AppPlatform specified request - don't use it.
HTTP_VERSION_1_0Dword constant for HTTP 1.0.
HTTP_VERSION_1_1Dword constant for HTTP 1.1.

http_request_method_t

typedef enum {
    HTTP_NONE,
    HTTP_GET,
    HTTP_HEAD,
    HTTP_POST,
    HTTP_PUT,
    HTTP_CONNECT,
    HTTP_OPTIONS,
    HTTP_TRACE,
    HTTP_PROPFIND,
    HTTP_MKCOL,
    HTTP_COPY,
    HTTP_MOVE,
    HTTP_DELETE,
    HTTP_LOCK,
    HTTP_UNLOCK,
    HTTP_PROPPATCH,
    HTTP_SYSCLIENT
} http_request_method_t;

This enum is used to define the method to use for a HTTP request and must be one of the following:

HTTP_NONE(NO HTTP VALUE!!!) Dummy value to initialize variable.
HTTP_GETTransfer a current representation of the target resource.
HTTP_HEADSame as GET, but only transfer the status line and header section.
HTTP_POSTPerform resource - specific processing on the request payload.
HTTP_PUT(WebDAV) Replace all current representations of the target resource with the request payload.
HTTP_CONNECTEstablish a tunnel to the server identified by the target resource.
HTTP_OPTIONS(WebDAV) Describe the communication options for the target resource.
HTTP_TRACE(WebDAV) Perform a message loop - back test along the path to the target resource.
HTTP_PROPFIND(WebDAV) Used to revceive properties for the given resource.
HTTP_MKCOL(WebDAV) Creates a new collection at the specified location.
HTTP_COPY(WebDAV) Copy the given resource to a specificed location.
HTTP_MOVE(WebDAV) Moves the given resource to a specified location.
HTTP_DELETE(WebDAV) Deletes the given resource.
HTTP_LOCK(WebDAV) Locks the given resource.
HTTP_UNLOCK(WebDAV) Unlocks the previously locked resource.
HTTP_PROPPATCH(WebDAV) Patches the properties of the given resource.
HTTP_SYSCLIENT(Used internally only) Sysclient request to authenticate localsocket requests - internally used.

http_connection_t

typedef enum {
    HTTP_CONNECTION_NONE = 0x00,
    HTTP_CONNECTION_KEEP_ALIVE = 0x01,
    HTTP_CONNECTION_CLOSE = 0x02,
    HTTP_CONNECTION_UPGRADE = 0x04
} http_connection_t;

This enum describes the type of a connection and must be one of the following:

HTTP_CONNECTION_NONEThe connection has no special state. This is the default.
HTTP_CONNECTION_KEEP_ALIVEThe connection is defiend to keep alive.
HTTP_CONNECTION_CLOSEIf defined, the connection must be closed after responding or receiving the response to a request.
HTTP_CONNECTION_UPGRADEThe connection should be (for requests) or had been (for responses) upgraded. Normally that will be used to establish websocket connections.

Remarks

The way how to handle HTTP_CONNECTION_KEEP_ALIVE and HTTP_CONNECTION_CLOSE depends on the used HTTP protocol version. For HTTP 1.0, close will be the default. So if HTTP_CONNECTION_KEEP_ALIVE is not set, the connection must close after responding or receiving the response of a request. For HTTP 1.1, keep alive is the default. So the connection should only be closed after receiving the response or responding a request, if HTTP_CONNECTION_CLOSE is set.

http_upgrade_t

typedef enum {
    HTTP_UPGRADE_NONE,
    HTTP_UPGRADE_WEBSOCKET
} http_upgrade_t;

These are the upgrades the a request can define.

HTTP_UPGRADE_NONENo upgrade, just a normal connection. This is the default.
HTTP_UPGRADE_WEBSOCKETThe connection had been or should be upgraded to be a websocket connection.

http_encoding_t

typedef enum {
    HTTP_ENCODING_NONE,      // Default
    HTTP_ENCODING_GZIP
} http_encoding_t;

These are the encoding types for a HTTP connection (the moment, only gzip is supported as special encoding).

HTTP_ENCODING_NONENo encoding. This is the default.
HTTP_ENCODING_GZIPThe data received or sent is in gzip compressed format.

http_result_t

typedef struct {
    int code;
    const char * description;
    size_t descLen;
} http_result_t;

This structure holds an HTTP result code in three parts: an integer value (easier to use for checking inside the code), a descroption string (actualle the one tha must be put to the header) and the length of the description. The HTTPLib defines constants for most of the result codes (see below). That constans can be used to pass to functions loke HTTPHeader::SetHTTPResult(). For more information about the resturn codes see RFC 7231, Page 41.

Values

int codeThe HTTP code as interger value.
const char * descriptionThe description of the code.
size_t descLenThe length of the description.

Remarks

HTTPLib has most of the HTTP return codes predefined in HTTP_* constants. The interger code of them is the same a the code of the result. So HTTP 100 has the integer number 100. The Description is a combination of the code number and the description defined by RFC (e. G. "200 OK"). The following result codes are offered by HTTPLib:

HTTP_100Continue
HTTP_101Switching Protocols
HTTP_200OK
HTTP_201Created
HTTP_202Accepted
HTTP_203Non-Authoritative Information
HTTP_204No Content
HTTP_205Reset Content
HTTP_206Partial Content
HTTP_207Multi-Status
HTTP_300Multiple Choices
HTTP_301Moved Permanently
HTTP_302Found
HTTP_303See Other
HTTP_304Not Modified
HTTP_305Use Proxy
HTTP_307Temporary Redirect
HTTP_400Bad Request
HTTP_401Unauthorized
HTTP_402Payment Required
HTTP_403Forbidden
HTTP_404Not Found
HTTP_405Method Not Allowed
HTTP_406Not Acceptable
HTTP_407Proxy Authentication Required
HTTP_408Request Timeout
HTTP_409Conflict
HTTP_410Gone
HTTP_411Length Required
HTTP_412Precondition Failed
HTTP_413Payload Too Large
HTTP_414URI Too Long
HTTP_415Unsupported Media Type
HTTP_416Range Not Satisfiable
HTTP_417Expectation Failed
HTTP_423Locked
HTTP_426Upgrade Required
HTTP_500Internal Server Error
HTTP_501Not Implemented
HTTP_502Bad Gateway
HTTP_503Service Unavailable
HTTP_504Gateway Timeout
HTTP_505HTTP Version Not Supported
HTTP_507Insufficient Storage

Code examples

// This example shows how to use the HTTP library to response to an incomming HTTP request.
// The class itself is a subclass of USocket (for receiving data) and UHTTPParser
// (to check the request and only accept GET requests).

void MyApp::SocketRecvResult(ISocket * const socket, void * buf, size_t len) {
    // parser is an HTTPParser instance of the object the function here is part of.
    this->parser->ParseData(buf, len, this);

    switch (this->parser->GetParseResult())
    {
        case HTTPParser::HTTP_PARSE_NEED_DATA:
            // More data need for the header. Note that we must make a partial Recv() call here.
            socket->Recv(buffer, 8192, true);
            break;

        case HTTPParser::HTTP_PARSE_ERROR:
            debug->printf("Error while parsing the HTTP header.");
            socket->Shutdown();
            break;

        case HTTPParser::HTTP_PARSE_CANCEL: // Unsupported request - see below
            debug->printf("Parsing canceled.");
            socket->Shutdown();
            break;

        case HTTPParser::HTTP_PARSE_DONE:
            this->ResponseGETRequest(socket);
            break;
    }
}


// The callback function from UHTTPParser. We only accept GET requests...
bool MyApp::HTTPParserValidateRequest(class HTTPParser * httpParser)
{
    if (httpParser->GetRequestMethod()) == HTTPLib::HTTP_GET) return true;
    
    debug->printf("Only GET requests are supported.");
    return false;
}


void MyApp::ResponseGETRequest(ISocket * socket)
{
    const char * responseData = "<!DOCTYPE html><html xmlns=\"http://www.w3.org/1999/xhtml\"><body>Hello World</body></html>"
    size_t responseLen = strlen(responseData);
    
    // Use the object on the stack - no need to delete it later.
    HTTPHeader header;
    header.SetHTTPVersion(this->parser->GetMajorVersion(), this->parser->GetMinorVersion());
    header.SetHTTPResult(&HTTPLib::HTTP_200);
    header.SetContentSize(responseLen);
    
    // Finally - send everything.
    socket->Send(header.GetHeaderData(), header.GetHeaderSize());
    socket->Send(responseData, responseLen);
}