Web server based weather station using Sparkfun Weather Meters.

Dependencies:   FatFileSystem mbed WeatherMeters SDFileSystem

HTTPServer.h

Committer:
AdamGreen
Date:
2012-02-23
Revision:
0:616601bde9fb

File content as of revision 0:616601bde9fb:

/* Copyright 2011 Adam Green (http://mbed.org/users/AdamGreen/)

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
/* Header file for HTTP Server functionality. */
#ifndef HTTPSERVER_H_
#define HTTPSERVER_H_

#include <mbed.h>
#include "lwip/tcp.h"



// UNDONE: Make protected member of CHTTPServer object?
/** Structure used to buffer data being read in from content files and then
    written out the TCP/IP connections.
*/
struct SBuffer
{
    char*           pWrite;                 /**< Pointer into Data where the next tcp_write() should begin.  There are BytesToWrite valid bytes left in the Data array to be sent. */
    // UNDONE: These can be shorts since mbed only has a total of 64k anyway.
    unsigned int    BytesToWrite;           /**< Number of bytes in buffer left to be written to outbound connection. */
    unsigned int    UnacknowledgedBytes;    /**< Number of bytes outstanding on network waiting for acknowledgment. */
    char            Data[TCP_SND_BUF];      /**< The actual buffer holding data to be sent to remote client. */
};





// *****************
// * C++ Interface *
// *****************
/** Interface to be returned from an application to provide callbacks for a
    specific HTTP request.
*/
class IHTTPRequestHandlerContext
{
public:
    /** Called by the CHTTPServer object before any WriteRequestHeader() calls
        to let the application to know to expect subsequent 
        WriteRequestHeader() calls.
        
        @returns 0 if the application isn't interested in receiving subsequent
                 WriteRequestHeader() and EndRequestHeaders() callbacks.
                 Returns non-zero value to receive headers.
    */
    virtual int  BeginRequestHeaders() = 0;

    /** Called by CHTTPServer for each HTTP request header sent by the HTTP 
        client.  The server won't issue this callback if 0 was previously
        returned by the application from the BeginRequestHeaders() method.
        
        @param pHeaderName is the name of this header field.  If this string
               is empty then this header line is a continuation of the previous
               header line which did have a field name.  The string
               pointed to by this parameter has a short lifetime and is only
               valid during the duration of this call.
        @param pHeaderValue is the string value of this header field.  The
               string pointed to by this parameter has a short lifetime and is
               only valid during the duration of this call.
    */
    virtual void WriteRequestHeader(const char* pHeaderName, 
                                    const char* pHeaderValue) = 0;
    
    /** Called by the CHTTPServer object after it has completed all of the
        necessary WriteRequestHeader() calls to enumerate the headers of the
        HTTP client's request.
    */
    virtual void EndRequestHeaders() = 0;
    

    /** Called by CHTTPServer to let the application know that it should expect
        subsequent WriteRequestContentBlock() calls for processing of the
        request content as it arrives on the TCP/IP socket.
        
        Only POST requests from a client should include such content data.
        
        @param ContentSize is the size of the request content to be sent from
               the HTTP client.  This value indicates the total number of bytes
               that should result from all of the WriteRequestContentBlock()
               calls to follow.
               
        @returns 0 if the application isn't interested in receiving subsequent
                 WriteRequestContentBlock() and EndRequestContent() callbacks.
                 Returns non-zero value to receive request content data.
    */
    virtual int BeginRequestContent(size_t ContentSize) = 0;
    
    /** Called for each block of request data received from the HTTP client.
        The server won't issue this callback if the application returned 0 from
        the BeginRequestContent() method.
        
        @param pBlockBuffer is a pointer to the block of request content data
               most recently received from the HTTP client.
        @param BlockBufferSize is the number of bytes contained in 
               pBlockBuffer.
    */
    virtual void WriteRequestContentBlock(const void* pBlockBuffer, 
                                          size_t BlockBufferSize) = 0;
                                  
    /** Called by CHTTPServer after it has completed all of the 
        WriteRequestContentBlock() calls for processing of the request content
        data sent from the HTTP client.
    */
    virtual void EndRequestContent() = 0;
    
    
    /** Called by CHTTPServer object to get the status line from the
        application to be returned to the HTTP client for this request.
        Examples: "HTTP/1.0 200 OK\r\n" -or- "HTTP/1.0 404 File no found\r\n"
        
        @param pStatusLineLength points to the length to be filled in by the
               application indicating the length, in character, of the returned
               status line.  It should not include the NULL terminator.  It
               must have a non-zero value.
               
        @returns a pointer to the status line to be returned to the HTTP client
                 for this request.  It should start with the "HTTP/1.0" string
                 and end with a newline designator of "\r\n".  The return value
                 can't be NULL.
    */
    virtual const char* GetStatusLine(size_t* pStatusLineLength) = 0;
    
    /** Called by the CHTTPServer object to get all of the response headers
        that the application would like to be returned to the HTTP client.  The
        CHTTPServer will append this header string to the 
        "Server: ServerName\r\n" header that it always sends.
        
        Example: "Content-Length: 100\r\n"
        
        @param pResponseHeaderLength points to the length to be filled in by
               the application indicating the length, in character, of the
               returned header string.  It should not include the NULL
               terminator and can be 0 if the returned value is NULL.
               
        @returns a pointer to the extra headers to be returned to the HTTP
                 client for this request.  It can be NULL if the application
                 has no special headers to be returned.
    */
    virtual const char* GetResponseHeaders(size_t* pResponseHeaderLength) = 0;
    
    /** Called by CHTTPServer to let application know that there will be
        subsequent ReadResponseContentBlock() calls to obtain the content data
        from the application to be sent back to the HTTP client in the
        response.
        
        @returns 0 if the application has no content to be sent back in the
                 HTTP response.
    */
    virtual int BeginResponseContent() = 0;
    
    /** Called by CHTTPServer to get the next block of response data to be
        sent back to the HTTP client.
        
        @param pBuffer is a pointer to the buffer to be filled in by the
               application with data to be sent back to the HTTP client in the
               response.
        @param BytesToRead indicates the number of bytes that should be placed
               into pBuffer by the application.  The application should only
               place fewer than this requested amount on the last block of
               data to be sent back to the HTTP client.
        
        @returns The number of bytes that were actually placed in pBuffer for
                 this call.  It can only be smaller than BytesToRead on the
                 last block to be sent since the server uses such truncated
                reads to know when it has sent the last block of response
                data.
    */
    virtual size_t ReadResponseContentBlock(char*  pBuffer,
                                            size_t BytesToRead) = 0;
    
    
    /** Called by CHTTPServer to let the application know that it has finished
       sending all of the response data to the HTTP client.  The application
       can use such a call to close any files that it has open for satsifying
       this request.
    */
    virtual void EndResponseContent() = 0;
    
    /** Called by the CHTTPServer object when it is completely done processing
       this HTTP response request so that the application can free up any
       resources it has associated with this HTTP client request, including the
       IHTTPRequestHandlerContext derived object servicing these callbacks.
    */
    virtual void Release() = 0;
};


/** The application can provide an IRequestHandler interface implementation to
 *  the HTTP server object.  The methods on such attached interface objects will
 *  be called by the server before it attempts default handling of HTTP
 *  requests.  This gives the application an opportunity to provide overrides
 *  for handling POST requests or GET requests in a certain part of the URI
 *  namespace.
 */
class IHTTPRequestHandler
{
public:
    /** Called by the server for each GET request.  If the application would
        like to handle the GET request rather than using the default server
        code then the application should return a valid 
        IHTTPRequestHandlerContext object pointer on which the server will call
        methods.  These method calls will inform the application of which
        headers were sent in the request and then obtain the response data to
        be sent back to the HTTP client.  Returning a NULL pointer indicates 
        that the server should search in its pRootPathname directory for the
        requested file.
        
        @param pURI is a pointer to the URI being requested by the HTTP
               client.  This is a short lived object that will only be
               valid during this call.
               
        @returns NULL if the CHTTPServer object should process the GET
                 request on its own.  Otherwise return an
                 IHTTPRequestHandlerContext object pointer so that the
                 application can be notified of additional request
                 information and provide the response data.
    */
    virtual IHTTPRequestHandlerContext* HandleGetRequest(const char* pURI) = 0;
    
    /** Called by the server for each HEAD request.  If the application would
        like to handle the HEAD request rather than using the default server
        code then the application should return a valid 
        IHTTPRequestHandlerContext object pointer on which the server will call
        methods.  These method calls will inform the application of which
        headers were sent in the request and then obtain the response data to
        be sent back to the HTTP client.  Returning a NULL pointer indicates 
        that the server should search in its pRootPathname directory for the
        requested file.
        
        @param pURI is a pointer to the URI being requested by the HTTP
               client.  This is a short lived object that will only be
               valid during this call.
               
        @returns NULL if the CHTTPServer object should process the HEAD
                 request on its own.  Otherwise return an
                 IHTTPRequestHandlerContext object pointer so that the
                 application can be notified of additional request
                 information.
    */
    virtual IHTTPRequestHandlerContext* HandleHeadRequest(const char* pURI) = 0;
    
    /** Called by the server for each POST request.  If the application would
        like to handle the POST request then it should return a valid 
        IHTTPRequestHandlerContext object pointer on which the server will call
        methods.  These method calls will inform the application of which
        headers were sent in the request and then obtain the response data to
        be sent back to the HTTP client.  Returning a NULL pointer indicates 
        that the server should fail this POST request with a not implemented
        error.
        
        @param pURI is a pointer to the URI being requested by the HTTP
               client.  This is a short lived object that will only be
               valid during this call.
               
        @returns NULL if the CHTTPServer object should fail the POST
                 request.  Otherwise return an IHTTPRequestHandlerContext 
                 object pointer so that the application can be notified of
                 additional request information and provide the response data.
    */
    virtual IHTTPRequestHandlerContext* HandlePostRequest(const char* pURI) = 0;
    
    /** Called by the server for each unrecognized request.  If the application
        would to handle such request then it should return a valid 
        IHTTPRequestHandlerContext object pointer on which the server will call
        methods.  These method calls will inform the application of which
        headers were sent in the request and then obtain the response data to
        be sent back to the HTTP client.  Returning a NULL pointer indicates 
        that the server should fail this bad request with an appropriate error.
        
        @param pRequest is a pointer to the request being made by the HTTP
               client.  This is a short lived object that will only be
               valid during this call.
               
        @returns NULL if the CHTTPServer object should fail this
                 request.  Otherwise return an IHTTPRequestHandlerContext 
                 object pointer so that the application can be notified of
                 additional request information and provide the response data.
    */
    virtual IHTTPRequestHandlerContext* HandleBadRequest(const char* pRequest) = 0;
};


// Forward declaration of class used to hold context for each HTTP client 
// connection.
class CHTTPContext;


/** HTTP server class.
*/
class CHTTPServer
{
public:
    /** Constructor */
    CHTTPServer();
    
    /** Attach IRequestHandler to the HTTP server to allow application to add
        custom GET/HEAD/POST handling.
    
        @param pHandler is a pointer to the application specific request handler object
               to be used by the HTTP server when it receives GET/POST requests.
        
        @returns 0 on successful attachment and a positive value otherwise.
    */
    int AttachRequestHandler(IHTTPRequestHandler* pHandler);
    
    /** Initializes the HTTP server object by binding it to to the specified
        port number.

        @param pRootPathame is the pathname of the default root directory from which the
               HTTP GET requests are satisfied.
        @param pServerName is the name of the server to be returned to the HTTP client
               in the Server header.
        @param BindPort is the TCP/IP port to which the HTTP server should listen for
                incoming requests.  The default port for HTTP would be 80.
    
        @returns 0 on success and a positive value otherwise.
    */
    int Bind(const char*    pRootPathname,
             const char*    pServerName = "lwIP_HTTPServer/1.0",
             unsigned short BindPort = 80);

protected:
    // Static Method Prototypes for lwIP Callbacks.
    static err_t        HTTPAccept(void* pvArg, tcp_pcb* pNewPCB, err_t err);

    // Methods called from CHTTPContext.
    friend class CHTTPContext;
    void                FreeBuffer(SBuffer* pBuffer);
    void                RemoveWaitingContext(CHTTPContext* pHTTPContext);
    SBuffer*            AllocateBuffer(CHTTPContext* pHTTPContext);

    // Listening port for HTTP Server.
    tcp_pcb*                m_pHTTPListenPCB;
    // Head and tail pointers for queue of client contexts that are waiting to
    // be allocated a SBuffer from the BufferPool.
    CHTTPContext*           m_pContextWaitingHead;
    CHTTPContext*           m_pContextWaitingTail;
    // The default root directory from which the HTTP GET requests are satisfied.
    const char*             m_pRootPathname;
    // Pointer to interface from application allowing it to handle HTTP requests.
    IHTTPRequestHandler*    m_pRequestHandler;
    // Server header returned to HTTP clients.
    size_t                  m_ServerHeaderLength;
    char                    m_ServerHeader[64];
    // Pool of buffers to use for transitioning data from the filesystem to
    // the network.
    SBuffer                 m_BufferPool[HTTP_BUFFER_POOL];
};


#endif /* HTTPSERVER_H_ */