Subversion Repositories HomeAutomation

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*********************************************************************
  2.  *
  3.  *               HTTP Implementation for Microchip TCP/IP Stack
  4.  *
  5.  **********************************************************************
  6.  * FileName:        Http.c
  7.  * Dependencies:    string.h
  8.  *                  Stacktsk.h
  9.  *                  Http.h
  10.  *                  MPFS.h
  11.  *                  TCP.h
  12.  * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
  13.  * Complier:        Microchip C18 v3.02 or higher
  14.  *                  Microchip C30 v2.01 or higher
  15.  * Company:         Microchip Technology, Inc.
  16.  *
  17.  * Software License Agreement
  18.  *
  19.  * This software is owned by Microchip Technology Inc. ("Microchip")
  20.  * and is supplied to you for use exclusively as described in the
  21.  * associated software agreement.  This software is protected by
  22.  * software and other intellectual property laws.  Any use in
  23.  * violation of the software license may subject the user to criminal
  24.  * sanctions as well as civil liability.  Copyright 2006 Microchip
  25.  * Technology Inc.  All rights reserved.
  26.  *
  27.  * This software is provided "AS IS."  MICROCHIP DISCLAIMS ALL
  28.  * WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED
  29.  * TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
  30.  * INFRINGEMENT.  Microchip shall in no event be liable for special,
  31.  * incidental, or consequential damages.
  32.  *
  33.  *
  34.  * Author               Date        Comment
  35.  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  36.  * Nilesh Rajbharti     8/14/01     Original
  37.  * Nilesh Rajbharti     9/12/01     Released (Rev. 1.0)
  38.  * Nilesh Rajbharti     2/9/02      Cleanup
  39.  * Nilesh Rajbharti     5/22/02     Rev 2.0 (See version.log for detail)
  40.  * Nilesh Rajbharti     7/9/02      Rev 2.1 (Fixed HTTPParse bug)
  41.  * Howard Schlunder     2/9/05      Fixed variable substitution
  42.  *                                  parsing (uses hex now)
  43.  ********************************************************************/
  44. #define THIS_IS_HTTP_SERVER
  45.  
  46. #include <string.h>
  47.  
  48. #include "..\Include\StackTsk.h"
  49. #include "..\Include\HTTP.h"
  50. #include "..\Include\MPFS.h"
  51. #include "..\Include\TCP.h"
  52. #include "..\Include\Helpers.h"
  53. #include "..\Include\UART.h"
  54. #include "..\Include\compiler.h"
  55. #include "..\Include\TimeSync.h"
  56. #include "..\Include\Scheduler.h"
  57.  
  58. #if defined(STACK_USE_HTTP_SERVER)
  59.  
  60.  
  61.  
  62. #if (MAC_TX_BUFFER_SIZE <= 130 || MAC_TX_BUFFER_SIZE > 1500 )
  63. #error HTTP : Invalid MAC_TX_BUFFER_SIZE value specified.
  64. #endif
  65.  
  66.  
  67. // HTTP FSM states for each connection.
  68. typedef enum _SM_HTTP
  69. {
  70.     SM_HTTP_IDLE = 0,
  71.     SM_HTTP_GET,
  72.     SM_HTTP_NOT_FOUND,
  73.     SM_HTTP_GET_READ,
  74.     SM_HTTP_GET_PASS,
  75.     SM_HTTP_GET_DLE,
  76.     SM_HTTP_GET_HANDLE,
  77.     SM_HTTP_GET_HANDLE_NEXT,
  78.     SM_HTTP_GET_VAR,
  79.     SM_HTTP_DISCONNECT,
  80.     SM_HTTP_DISCONNECT_WAIT,
  81.     SM_HTTP_HEADER,
  82.     SM_HTTP_HEADER2,
  83.     SM_HTTP_HEADER3,
  84.     SM_HTTP_DISCARD
  85. } SM_HTTP;
  86.  
  87. // Supported HTTP Commands
  88. typedef enum _HTTP_COMMAND
  89. {
  90.     HTTP_GET,
  91.     HTTP_POST,
  92.     HTTP_NOT_SUPPORTED,
  93.     HTTP_INVALID_COMMAND
  94. } HTTP_COMMAND;
  95.  
  96. // HTTP Connection Info - one for each connection.
  97. typedef struct _HTTP_INFO
  98. {
  99.     TCP_SOCKET socket;
  100.     MPFS file;
  101.     SM_HTTP smHTTP;
  102.     BYTE smHTTPGet;
  103.     WORD VarRef;
  104.     BYTE bProcess;
  105.     BYTE Variable;
  106. } HTTP_INFO;
  107. typedef BYTE HTTP_HANDLE;
  108.  
  109.  
  110. typedef enum
  111. {
  112.     HTTP_NOT_FOUND,
  113.     HTTP_NOT_AVAILABLE
  114. } HTTP_MESSAGES;
  115.  
  116.  
  117.  
  118. // HTTP Command Strings
  119. ROM BYTE HTTP_GET_STRING[]                      =           \
  120.                         "GET";
  121. #define HTTP_GET_STRING_LEN                                 \
  122.                         (sizeof(HTTP_GET_STRING)-1)
  123.  
  124.  
  125. // Maximum nuber of arguments supported by this HTTP Server.
  126. #define MAX_HTTP_ARGS       (11)
  127.  
  128. // Maximum HTML Command String length.
  129. #define MAX_HTML_CMD_LEN    (100)
  130.  
  131. static HTTP_INFO HCB[MAX_HTTP_CONNECTIONS];
  132.  
  133. static void HTTPProcess(HTTP_HANDLE h);
  134. static HTTP_COMMAND HTTPParse(BYTE *string,
  135.                               BYTE** arg,
  136.                               BYTE* argc);
  137.  
  138.  
  139.  
  140. ROM BYTE GOOD_BEG[]="HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n<html><head><title>Webbserver på 18F2620</title></head><body>";
  141. ROM BYTE GOOD_END[]="</body></html>\r\n";
  142. //ROM BYTE NOT_FOUND[]="HTTP/1.0 404 Not found\r\n\r\nNot found.\r\n";
  143.  
  144. ROM BYTE WELCOME[] ="<center><h3>Väkommen!</h3></center>Denna sida ligger på en microkontroller av typen 18F2620.<br><br>";
  145. ROM BYTE LED_TEXT[]="<b>LED1</b> är <i>";
  146. ROM BYTE LED_ON[]  ="på";
  147. ROM BYTE LED_OFF[] ="av";
  148. ROM BYTE TOGG[]    ="</i>. Växla <a href=\"?" VAR_LED1_STR "=1\">på</a> <a href=\"?" VAR_LED1_STR "=0\">av</a><br><br>";
  149. ROM BYTE CURRENTIME[]="Nuvarande tid (timestamp): <b>";
  150. ROM BYTE LASTTIME[]=", synkad (timestamp): <b>";
  151. ROM BYTE NO_SYNC[]="<i>Ingen synk ännu.</i>";
  152. ROM BYTE TIMEND[]="</b>";
  153. ROM BYTE SCHED[]="<br><br><u>Schemalagda händelser</u><br>";
  154. ROM BYTE JA[]="Ja";
  155. ROM BYTE NEJ[]="Nej";
  156. ROM BYTE ACTIVE[]="Aktiv: <i>";
  157. ROM BYTE WHEN[]="</i>, När: <i>";
  158. ROM BYTE REPEAT[]="</i>, Repetera: <i>";
  159. ROM BYTE WHAT[]="</i>, Vad: <i>";
  160. ROM BYTE VALUE[]="</i>, Sätts till värde: <i>";
  161. ROM BYTE SHEDEND[]="</i><br>";
  162.  
  163. char tmp[32];
  164.  
  165. /*********************************************************************
  166.  * Function:        void HTTPInit(void)
  167.  *
  168.  * PreCondition:    TCP must already be initialized.
  169.  *
  170.  * Input:           None
  171.  *
  172.  * Output:          HTTP FSM and connections are initialized
  173.  *
  174.  * Side Effects:    None
  175.  *
  176.  * Overview:        Set all HTTP connections to Listening state.
  177.  *                  Initialize FSM for each connection.
  178.  *
  179.  * Note:            This function is called only one during lifetime
  180.  *                  of the application.
  181.  ********************************************************************/
  182. void HTTPInit(void)
  183. {
  184.     BYTE i;
  185.  
  186.     for ( i = 0; i <  MAX_HTTP_CONNECTIONS; i++ )
  187.     {
  188.         HCB[i].socket = TCPListen(HTTP_PORT);
  189.         HCB[i].smHTTP = SM_HTTP_IDLE;
  190.     }
  191. }
  192.  
  193.  
  194.  
  195. /*********************************************************************
  196.  * Function:        void HTTPServer(void)
  197.  *
  198.  * PreCondition:    HTTPInit() must already be called.
  199.  *
  200.  * Input:           None
  201.  *
  202.  * Output:          Opened HTTP connections are served.
  203.  *
  204.  * Side Effects:    None
  205.  *
  206.  * Overview:        Browse through each connections and let it
  207.  *                  handle its connection.
  208.  *                  If a connection is not finished, do not process
  209.  *                  next connections.  This must be done, all
  210.  *                  connections use some static variables that are
  211.  *                  common.
  212.  *
  213.  * Note:            This function acts as a task (similar to one in
  214.  *                  RTOS).  This function performs its task in
  215.  *                  co-operative manner.  Main application must call
  216.  *                  this function repeatdly to ensure all open
  217.  *                  or new connections are served on time.
  218.  ********************************************************************/
  219. void HTTPServer(void)
  220. {
  221.     BYTE conn;
  222.  
  223.     for ( conn = 0;  conn < MAX_HTTP_CONNECTIONS; conn++ )
  224.         HTTPProcess(conn);
  225. }
  226.  
  227.  
  228. /*********************************************************************
  229.  * Function:        static BOOL HTTPProcess(HTTP_HANDLE h)
  230.  *
  231.  * PreCondition:    HTTPInit() called.
  232.  *
  233.  * Input:           h   -   Index to the handle which needs to be
  234.  *                          processed.
  235.  *
  236.  * Output:          Connection referred by 'h' is served.
  237.  *
  238.  * Side Effects:    None
  239.  *
  240.  * Overview:
  241.  *
  242.  * Note:            None.
  243.  ********************************************************************/
  244. static void HTTPProcess(HTTP_HANDLE h)
  245. {
  246.     BYTE httpData[MAX_HTML_CMD_LEN+1];
  247.     HTTP_COMMAND httpCommand;
  248.     WORD httpLength;
  249.     BOOL lbContinue;
  250.     BYTE *arg[MAX_HTTP_ARGS];
  251.     BYTE argc;
  252.     BYTE i;
  253.     HTTP_INFO* ph;
  254.     ROM char* romString;
  255.  
  256.     BYTE j;
  257.     EVENT event;
  258.     DWORD t;
  259.  
  260.     ph = &HCB[h];
  261.    
  262.     do
  263.     {
  264.         lbContinue = FALSE;
  265.  
  266.         // If during handling of HTTP socket, it gets disconnected,
  267.         // forget about previous processing and return to idle state.
  268.         if(!TCPIsConnected(ph->socket))
  269.         {
  270.             ph->smHTTP = SM_HTTP_IDLE;
  271.             break;
  272.         }
  273.  
  274.  
  275.         switch(ph->smHTTP)
  276.         {
  277.         case SM_HTTP_IDLE:
  278.             if(TCPIsGetReady(ph->socket))
  279.             {
  280.            
  281.                 lbContinue = TRUE;
  282.  
  283.                 httpLength = 0;
  284.                 while(httpLength < MAX_HTML_CMD_LEN &&
  285.                       TCPGet(ph->socket, &httpData[httpLength++]) );
  286.                 httpData[httpLength] = '\0';
  287.                 TCPDiscard(ph->socket);
  288.  
  289.                 ph->smHTTP = SM_HTTP_NOT_FOUND;
  290.                 argc = MAX_HTTP_ARGS;
  291.                 httpCommand = HTTPParse(httpData, arg, &argc);
  292.                 if ( httpCommand == HTTP_GET )
  293.                 {
  294.                     HTTPExecCmd(&arg[0], argc);
  295.                     ph->smHTTP = SM_HTTP_HEADER;
  296.                 }
  297.             }
  298.             break;
  299.  
  300.         case SM_HTTP_HEADER:
  301.  
  302.             if ( TCPIsPutReady(ph->socket) )
  303.             {
  304.                 for(i=0;i<sizeof(GOOD_BEG)-1;i++) TCPPut(ph->socket, GOOD_BEG[i]);
  305.  
  306.                 for(i=0;i<sizeof(WELCOME)-1;i++) TCPPut(ph->socket, WELCOME[i]);
  307.  
  308.                 for(i=0;i<sizeof(LED_TEXT)-1;i++) TCPPut(ph->socket, LED_TEXT[i]);
  309.    
  310.                 if (getVariable(VAR_LED1)) romString=LED_ON; else romString=LED_OFF;
  311.  
  312.                 while( (i = *romString++) ) TCPPut(ph->socket, i);
  313.  
  314.                 for(i=0;i<sizeof(TOGG)-1;i++) TCPPut(ph->socket, TOGG[i]);
  315.  
  316.                 for(i=0;i<sizeof(CURRENTIME)-1;i++) TCPPut(ph->socket, CURRENTIME[i]);
  317.  
  318.                 //getTimeStr(CURRENT,tmp);
  319.                
  320.                 if (t=getTime(CURRENT))
  321.                 {
  322.                     timestampToString(t,tmp);
  323.                     for(i=0;tmp[i]!='\0';i++) TCPPut(ph->socket, tmp[i]);
  324.                 } else TCPPut(ph->socket, '-');
  325.  
  326.                 for(i=0;i<sizeof(TIMEND)-1;i++) TCPPut(ph->socket, TIMEND[i]);
  327.  
  328.                 for(i=0;i<sizeof(LASTTIME)-1;i++) TCPPut(ph->socket, LASTTIME[i]);
  329.  
  330.                 if (t=getTime(LAST))
  331.                 {
  332.                     timestampToString(t,tmp);
  333.                     for(i=0;tmp[i]!='\0';i++) TCPPut(ph->socket, tmp[i]);
  334.                 }
  335.                 else
  336.                 {
  337.                     for(i=0;i<sizeof(NO_SYNC)-1;i++) TCPPut(ph->socket, NO_SYNC[i]);
  338.                 }
  339.  
  340.                 for(i=0;i<sizeof(TIMEND)-1;i++) TCPPut(ph->socket, TIMEND[i]);
  341.                 TCPFlush(ph->socket);
  342.                 ph->smHTTP = SM_HTTP_HEADER2;
  343.             }
  344.         break;
  345.  
  346.         case SM_HTTP_HEADER2:
  347.  
  348.             if ( TCPIsPutReady(ph->socket) )
  349.             {  
  350.  
  351.                 for(i=0;i<sizeof(GOOD_END)-1;i++) TCPPut(ph->socket, GOOD_END[i]);
  352.  
  353.                 TCPFlush(ph->socket);
  354.                 ph->smHTTP = SM_HTTP_DISCONNECT;
  355.             }
  356.         break;
  357.  
  358.  
  359.         case SM_HTTP_DISCONNECT:
  360.             if(TCPIsConnected(ph->socket))
  361.             {
  362.                 if(TCPIsPutReady(ph->socket))
  363.                 {
  364.                     TCPDisconnect(ph->socket);
  365.  
  366.                     // Switch to not-handled state.  This FSM has
  367.                     // one common action that checks for disconnect
  368.                     // condition and returns to Idle state.
  369.                     ph->smHTTP = SM_HTTP_DISCONNECT_WAIT;
  370.                 }
  371.             }
  372.             break;
  373.  
  374.         }
  375.     } while( lbContinue );
  376. }
  377.  
  378.  
  379. /*********************************************************************
  380.  * Function:        static HTTP_COMMAND HTTPParse(BYTE *string,
  381.  *                                              BYTE** arg,
  382.  *                                              BYTE* argc,
  383.  *                                              BYTE* type)
  384.  *
  385.  * PreCondition:    None
  386.  *
  387.  * Input:           string      - HTTP Command String
  388.  *                  arg         - List of string pointer to hold
  389.  *                                HTTP arguments.
  390.  *                  argc        - Pointer to hold total number of
  391.  *                                arguments in this command string/
  392.  *                  type        - Pointer to hold type of file
  393.  *                                received.
  394.  *                              Valid values are:
  395.  *                                  HTTP_TXT
  396.  *                                  HTTP_HTML
  397.  *                                  HTTP_GIF
  398.  *                                  HTTP_CGI
  399.  *                                  HTTP_UNKNOWN
  400.  *
  401.  * Output:          HTTP FSM and connections are initialized
  402.  *
  403.  * Side Effects:    None
  404.  *
  405.  * Overview:        None
  406.  *
  407.  * Note:            This function parses URL that may or may not
  408.  *                  contain arguments.
  409.  *                  e.g. "GET HTTP/1.0 thank.htm?name=MCHP&age=12"
  410.  *                      would be returned as below:
  411.  *                          arg[0] => GET
  412.  *                          arg[1] => thank.htm
  413.  *                          arg[2] => name
  414.  *                          arg[3] => MCHP
  415.  *                          arg[4] => 12
  416.  *                          argc = 5
  417.  *
  418.  *                  This parses does not "de-escape" URL string.
  419.  ********************************************************************/
  420. static HTTP_COMMAND HTTPParse(BYTE *string,
  421.                             BYTE** arg,
  422.                             BYTE* argc)
  423. {
  424.     BYTE i;
  425.     BYTE smParse;
  426.     HTTP_COMMAND cmd;
  427.     BYTE *ext;
  428.     BYTE c;
  429.  
  430.     enum
  431.     {
  432.         SM_PARSE_IDLE,
  433.         SM_PARSE_ARG,
  434.         SM_PARSE_ARG_FORMAT
  435.     };
  436.  
  437.  
  438.  
  439.     smParse = SM_PARSE_IDLE;
  440.     ext = NULL;
  441.     i = 0;
  442.  
  443.     // Only "GET" is supported for time being.
  444.     if ( !memcmppgm2ram(string, (ROM void*) HTTP_GET_STRING, HTTP_GET_STRING_LEN) )
  445.     {
  446.         string += (HTTP_GET_STRING_LEN + 1);
  447.         cmd = HTTP_GET;
  448.     }
  449.     else
  450.     {
  451.         return HTTP_NOT_SUPPORTED;
  452.     }
  453.  
  454.     // Skip white spaces.
  455.     while( *string == ' ' )
  456.         string++;
  457.  
  458.     c = *string;
  459.  
  460.     while ( c != ' ' &&  c != '\0' && c != '\r' && c != '\n' )
  461.  
  462.     {
  463.         // Do not accept any more arguments than we haved designed to.
  464.         if ( i >= *argc )
  465.             break;
  466.  
  467.         switch(smParse)
  468.         {
  469.         case SM_PARSE_IDLE:
  470.             arg[i] = string;
  471.             c = *string;
  472.             if ( c == '/' || c == '\\' )
  473.                 smParse = SM_PARSE_ARG;
  474.             break;
  475.  
  476.         case SM_PARSE_ARG:
  477.             arg[i++] = string;
  478.             smParse = SM_PARSE_ARG_FORMAT;
  479.             /*
  480.              * Do not break.
  481.              * Parameter may be empty.
  482.              */
  483.  
  484.         case SM_PARSE_ARG_FORMAT:
  485.             c = *string;
  486.             if ( c == '?' || c == '&' )
  487.             {
  488.                 *string = '\0';
  489.                 smParse = SM_PARSE_ARG;
  490.             }
  491.             else
  492.             {
  493.                 // Recover space characters.
  494.                 if ( c == '+' )
  495.                     *string = ' ';
  496.  
  497.                 // Remember where file extension starts.
  498.                 else if ( c == '.' && i == 1u )
  499.                 {
  500.                     ext = ++string;
  501.                 }
  502.  
  503.                 else if ( c == '=' )
  504.                 {
  505.                     *string = '\0';
  506.                     smParse = SM_PARSE_ARG;
  507.                 }
  508.  
  509.                 // Only interested in file name - not a path.
  510.                 else if ( c == '/' || c == '\\' )
  511.                     arg[i-1] = string+1;
  512.  
  513.             }
  514.             break;
  515.         }
  516.         string++;
  517.         c = *string;
  518.     }
  519.     *string = '\0';
  520.  
  521.     if ( i == 0u )
  522.     {
  523.         arg[0][0] = '\0';
  524.         i++;
  525.     }
  526.     *argc = i;
  527.  
  528.     return cmd;
  529. }
  530.  
  531.  
  532. #endif //#if defined(STACK_USE_HTTP_SERVER)
  533.