/[H8]/trunk/docs/MCHPStack2.20/Source/http.c
ViewVC logotype

Annotation of /trunk/docs/MCHPStack2.20/Source/http.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue May 1 08:17:39 2007 UTC (17 years, 2 months ago) by hedin
File MIME type: text/plain
File size: 22257 byte(s)
Removed tcpip stack 4.02 and added tcpip stack 2.20.
1 hedin 62 /*********************************************************************
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
13     * Complier: MCC18 v1.00.50 or higher
14     * HITECH PICC-18 V8.10PL1 or higher
15     * Company: Microchip Technology, Inc.
16     *
17     * Software License Agreement
18     *
19     * The software supplied herewith by Microchip Technology Incorporated
20     * (the “Company”) for its PICmicro® Microcontroller is intended and
21     * supplied to you, the Company’s customer, for use solely and
22     * exclusively on Microchip PICmicro Microcontroller products. The
23     * software is owned by the Company and/or its supplier, and is
24     * protected under applicable copyright laws. All rights are reserved.
25     * Any use in violation of the foregoing restrictions may subject the
26     * user to criminal sanctions under applicable laws, as well as to
27     * civil liability for the breach of the terms and conditions of this
28     * license.
29     *
30     * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
31     * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
32     * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
33     * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
34     * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
35     * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
36     *
37     * HiTech PICC18 Compiler Options excluding device selection:
38     * -FAKELOCAL -G -O -Zg -E -C
39     *
40     *
41     *
42     *
43     * Author Date Comment
44     *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45     * Nilesh Rajbharti 8/14/01 Original
46     * Nilesh Rajbharti 9/12/01 Released (Rev. 1.0)
47     * Nilesh Rajbharti 2/9/02 Cleanup
48     * Nilesh Rajbharti 5/22/02 Rev 2.0 (See version.log for detail)
49     * Nilesh Rajbharti 7/9/02 Rev 2.1 (Fixed HTTPParse bug)
50     ********************************************************************/
51     #define THIS_IS_HTTP_SERVER
52    
53     #include <string.h>
54    
55     #include "stacktsk.h"
56     #include "http.h"
57     #include "mpfs.h"
58     #include "tcp.h"
59    
60    
61     #if !defined(STACK_USE_HTTP_SERVER)
62     #error HTTP Server module is not enabled.
63     #error Remove this file from your project to reduce your code size.
64     #endif
65    
66    
67    
68    
69     #if (MAC_TX_BUFFER_SIZE <= 130 || MAC_TX_BUFFER_SIZE > 1500 )
70     #error HTTP : Invalid MAC_TX_BUFFER_SIZE value specified.
71     #endif
72    
73    
74     /*
75     * Each dynamic variable within a CGI file should be preceeded with
76     * this character.
77     */
78     #define HTTP_VAR_ESC_CHAR '%'
79     #define HTTP_DYNAMIC_FILE_TYPE (HTTP_CGI)
80    
81     /*
82     * HTTP File Types
83     */
84     #define HTTP_TXT (0)
85     #define HTTP_HTML (1)
86     #define HTTP_GIF (2)
87     #define HTTP_CGI (3)
88     #define HTTP_JPG (4)
89     #define HTTP_JAVA (5)
90     #define HTTP_WAV (6)
91     #define HTTP_UNKNOWN (7)
92    
93    
94     #define FILE_EXT_LEN (3)
95     typedef struct _FILE_TYPES
96     {
97     char fileExt[FILE_EXT_LEN+1];
98     } FILE_TYPES;
99    
100    
101    
102    
103     /*
104     * Each entry in this structure must be in UPPER case.
105     * Order of these entries must match with those defined
106     * by "HTTP File Types" defines.
107     */
108     static ROM FILE_TYPES httpFiles[] =
109     {
110     { "TXT" }, // HTTP_TXT
111     { "HTM" }, // HTTP_HTML
112     { "GIF" }, // HTTP_GIF
113     { "CGI" }, // HTTP_CGI
114     { "JPG" }, // HTTP_JPG
115     { "CLA" }, // HTTP_JAVA
116     { "WAV" } // HTTP_WAV
117     };
118     #define TOTAL_FILE_TYPES ( sizeof(httpFiles)/sizeof(httpFiles[0]) )
119    
120    
121     typedef struct _HTTP_CONTENT
122     {
123     ROM char typeString[20];
124     } HTTP_CONTENT;
125    
126     /*
127     * Content entry order must match with those "HTTP File Types" define's.
128     */
129     static ROM HTTP_CONTENT httpContents[] =
130     {
131     { "text/plain" }, // HTTP_TXT
132     { "text/html" }, // HTTP_HTML
133     { "image/gif" }, // HTTP_GIF
134     { "text/html" }, // HTTP_CGI
135     { "image/jpeg" }, // HTTP_JPG
136     { "application/java-vm" }, // HTTP_JAVA
137     { "audio/x-wave" } // HTTP_WAV
138     };
139     #define TOTAL_HTTP_CONTENTS ( sizeof(httpContents)/sizeof(httpConetents[0]) )
140    
141     /*
142     * HTTP FSM states for each connection.
143     */
144     typedef enum _SM_HTTP
145     {
146     SM_HTTP_IDLE,
147     SM_HTTP_GET,
148     SM_HTTP_NOT_FOUND,
149     SM_HTTP_GET_READ,
150     SM_HTTP_GET_PASS,
151     SM_HTTP_GET_DLE,
152     SM_HTTP_GET_HANDLE,
153     SM_HTTP_GET_HANDLE_NEXT,
154     SM_HTTP_GET_VAR,
155     SM_HTTP_DISCONNECT,
156     SM_HTTP_DISCONNECT_WAIT,
157     SM_HTTP_HEADER,
158     SM_HTTP_DISCARD
159     } SM_HTTP;
160    
161    
162     /*
163     * Supported HTTP Commands
164     */
165     typedef enum _HTTP_COMMAND
166     {
167     HTTP_GET,
168     HTTP_POST,
169     HTTP_NOT_SUPPORTED,
170     HTTP_INVALID_COMMAND
171     } HTTP_COMMAND;
172    
173    
174    
175     /*
176     * HTTP Connection Info - one for each connection.
177     */
178     typedef struct _HTTP_INFO
179     {
180     TCP_SOCKET socket;
181     MPFS file;
182     SM_HTTP smHTTP;
183     BYTE smHTTPGet;
184     WORD VarRef;
185     BYTE bProcess;
186     BYTE Variable;
187     BYTE fileType;
188     } HTTP_INFO;
189     typedef BYTE HTTP_HANDLE;
190    
191    
192     typedef enum
193     {
194     HTTP_NOT_FOUND,
195     HTTP_OK,
196     HTTP_HEADER_END,
197     HTTP_NOT_AVAILABLE
198     } HTTP_MESSAGES;
199    
200     /*
201     * Following message order must match with that of HTTP_MESSAGES
202     * enum.
203     */
204     static ROM char *HTTPMessages[] =
205     {
206     "HTTP/1.0 404 Not found\r\n\r\nNot found.\r\n",
207     "HTTP/1.0 200 OK\r\n\Content-type: ",
208     "\r\n\r\n",
209     "HTTP/1.0 503 \r\n\r\nService Unavailable\r\n"
210     };
211    
212    
213     /*
214     * Standard HTTP messages.
215     */
216     ROM BYTE HTTP_OK_STRING[] = \
217     "HTTP/1.0 200 OK\r\nContent-type: ";
218     #define HTTP_OK_STRING_LEN \
219     (sizeof(HTTP_OK_STRING)-1)
220    
221     ROM BYTE HTTP_HEADER_END_STRING[] = \
222     "\r\n\r\n";
223     #define HTTP_HEADER_END_STRING_LEN \
224     (sizeof(HTTP_HEADER_END_STRING)-1)
225    
226     /*
227     * HTTP Command Strings
228     */
229     ROM BYTE HTTP_GET_STRING[] = \
230     "GET";
231     #define HTTP_GET_STRING_LEN \
232     (sizeof(HTTP_GET_STRING)-1)
233    
234     /*
235     * Default HTML file.
236     */
237     ROM BYTE HTTP_DEFAULT_FILE_STRING[] = \
238     "INDEX.HTM";
239     #define HTTP_DEFAULT_FILE_STRING_LEN \
240     (sizeof(HTTP_DEFAULT_FILE_STRING)-1)
241    
242    
243     /*
244     * Maximum nuber of arguments supported by this HTTP Server.
245     */
246     #define MAX_HTTP_ARGS (5)
247    
248     /*
249     * Maximum HTML Command String length.
250     */
251     #define MAX_HTML_CMD_LEN (80)
252    
253    
254     static HTTP_INFO HCB[MAX_HTTP_CONNECTIONS];
255    
256    
257     static void HTTPProcess(HTTP_HANDLE h);
258     static HTTP_COMMAND HTTPParse(BYTE *string,
259     BYTE** arg,
260     BYTE* argc,
261     BYTE* type);
262     static BOOL SendFile(HTTP_INFO* ph);
263    
264    
265    
266    
267     /*********************************************************************
268     * Function: void HTTPInit(void)
269     *
270     * PreCondition: TCP must already be initialized.
271     *
272     * Input: None
273     *
274     * Output: HTTP FSM and connections are initialized
275     *
276     * Side Effects: None
277     *
278     * Overview: Set all HTTP connections to Listening state.
279     * Initialize FSM for each connection.
280     *
281     * Note: This function is called only one during lifetime
282     * of the application.
283     ********************************************************************/
284     void HTTPInit(void)
285     {
286     BYTE i;
287    
288     for ( i = 0; i < MAX_HTTP_CONNECTIONS; i++ )
289     {
290     HCB[i].socket = TCPListen(HTTP_PORT);
291     HCB[i].smHTTP = SM_HTTP_IDLE;
292     }
293     }
294    
295    
296    
297     /*********************************************************************
298     * Function: void HTTPServer(void)
299     *
300     * PreCondition: HTTPInit() must already be called.
301     *
302     * Input: None
303     *
304     * Output: Opened HTTP connections are served.
305     *
306     * Side Effects: None
307     *
308     * Overview: Browse through each connections and let it
309     * handle its connection.
310     * If a connection is not finished, do not process
311     * next connections. This must be done, all
312     * connections use some static variables that are
313     * common.
314     *
315     * Note: This function acts as a task (similar to one in
316     * RTOS). This function performs its task in
317     * co-operative manner. Main application must call
318     * this function repeatdly to ensure all open
319     * or new connections are served on time.
320     ********************************************************************/
321     void HTTPServer(void)
322     {
323     BYTE conn;
324    
325     for ( conn = 0; conn < MAX_HTTP_CONNECTIONS; conn++ )
326     HTTPProcess(conn);
327     }
328    
329    
330     /*********************************************************************
331     * Function: static BOOL HTTPProcess(HTTP_HANDLE h)
332     *
333     * PreCondition: HTTPInit() called.
334     *
335     * Input: h - Index to the handle which needs to be
336     * processed.
337     *
338     * Output: Connection referred by 'h' is served.
339     *
340     * Side Effects: None
341     *
342     * Overview:
343     *
344     * Note: None.
345     ********************************************************************/
346     static void HTTPProcess(HTTP_HANDLE h)
347     {
348     BYTE httpData[MAX_HTML_CMD_LEN+1];
349     HTTP_COMMAND httpCommand;
350     WORD httpLength;
351     BOOL lbContinue;
352     BYTE *arg[MAX_HTTP_ARGS];
353     BYTE argc;
354     BYTE i;
355     HTTP_INFO* ph;
356     ROM char* romString;
357    
358     ph = &HCB[h];
359    
360     lbContinue = TRUE;
361     while( lbContinue )
362     {
363     lbContinue = FALSE;
364    
365     /*
366     * If during handling of HTTP socket, it gets disconnected,
367     * forget about previous processing and return to idle state.
368     */
369     if ( !TCPIsConnected(ph->socket) )
370     {
371     ph->smHTTP = SM_HTTP_IDLE;
372     break;
373     }
374    
375    
376     switch(ph->smHTTP)
377     {
378     case SM_HTTP_IDLE:
379     if ( TCPIsGetReady(ph->socket) )
380     {
381     lbContinue = TRUE;
382    
383     httpLength = 0;
384     while( httpLength < MAX_HTML_CMD_LEN &&
385     TCPGet(ph->socket, &httpData[httpLength++]) );
386     httpData[httpLength] = '\0';
387     TCPDiscard(ph->socket);
388    
389     ph->smHTTP = SM_HTTP_NOT_FOUND;
390     argc = MAX_HTTP_ARGS;
391     httpCommand = HTTPParse(httpData, arg, &argc, &ph->fileType);
392     if ( httpCommand == HTTP_GET )
393     {
394     /*
395     * If there are any arguments, this must be a remote command.
396     * Execute it and then send the file.
397     * The file name may be modified by command handler.
398     */
399     if ( argc > 1 )
400     {
401     /*
402     * Let main application handle this remote command.
403     */
404     HTTPExecCmd(&arg[0], argc);
405    
406     /*
407     * Command handler must have modified arg[0] which now
408     * points to actual file that will be sent as a result of
409     * this remote command.
410     */
411    
412     /*
413     * Assume that Web author will only use CGI or HTML
414     * file for remote command.
415     */
416     ph->fileType = HTTP_CGI;
417     }
418    
419     ph->file = MPFSOpen(arg[0]);
420     if ( ph->file == MPFS_INVALID )
421     {
422     ph->Variable = HTTP_NOT_FOUND;
423     ph->smHTTP = SM_HTTP_NOT_FOUND;
424     }
425     else if ( ph->file == MPFS_NOT_AVAILABLE )
426     {
427     ph->Variable = HTTP_NOT_AVAILABLE;
428     ph->smHTTP = SM_HTTP_NOT_FOUND;
429     }
430     else
431     {
432     ph->smHTTP = SM_HTTP_HEADER;
433     }
434     }
435     }
436     break;
437    
438     case SM_HTTP_NOT_FOUND:
439     if ( TCPIsPutReady(ph->socket) )
440     {
441     romString = HTTPMessages[ph->Variable];
442    
443     while( (i = *romString++) )
444     TCPPut(ph->socket, i);
445    
446     TCPFlush(ph->socket);
447     ph->smHTTP = SM_HTTP_DISCONNECT;
448     }
449     break;
450    
451     case SM_HTTP_HEADER:
452     if ( TCPIsPutReady(ph->socket) )
453     {
454     lbContinue = TRUE;
455    
456     for ( i = 0; i < HTTP_OK_STRING_LEN; i++ )
457     TCPPut(ph->socket, HTTP_OK_STRING[i]);
458    
459     romString = httpContents[ph->fileType].typeString;
460     while( (i = *romString++) )
461     TCPPut(ph->socket, i);
462    
463     for ( i = 0; i < HTTP_HEADER_END_STRING_LEN; i++ )
464     TCPPut(ph->socket, HTTP_HEADER_END_STRING[i]);
465    
466     if ( ph->fileType == HTTP_DYNAMIC_FILE_TYPE )
467     ph->bProcess = TRUE;
468     else
469     ph->bProcess = FALSE;
470    
471     ph->smHTTPGet = SM_HTTP_GET_READ;
472     ph->smHTTP = SM_HTTP_GET;
473     }
474     break;
475    
476    
477     case SM_HTTP_GET:
478     if ( TCPIsGetReady(ph->socket) )
479     TCPDiscard(ph->socket);
480    
481     if ( SendFile(ph) )
482     {
483     MPFSClose();
484     ph->smHTTP = SM_HTTP_DISCONNECT;
485    
486     }
487     break;
488    
489     case SM_HTTP_DISCONNECT:
490     if ( TCPIsConnected(ph->socket) )
491     {
492     if ( TCPIsPutReady(ph->socket) )
493     {
494     TCPDisconnect(ph->socket);
495    
496     /*
497     * Switch to not-handled state. This FSM has
498     * one common action that checks for disconnect
499     * condition and returns to Idle state.
500     */
501     ph->smHTTP = SM_HTTP_DISCONNECT_WAIT;
502     }
503     }
504     break;
505    
506     }
507     }
508     }
509    
510    
511     /*********************************************************************
512     * Function: static BOOL SendFile(HTTP_INFO* ph)
513     *
514     * PreCondition: None
515     *
516     * Input: ph - A HTTP connection info.
517     *
518     * Output: File reference by this connection is served.
519     *
520     * Side Effects: None
521     *
522     * Overview: None
523     *
524     * Note: None.
525     ********************************************************************/
526     static BOOL SendFile(HTTP_INFO* ph)
527     {
528     BOOL lbTransmit;
529     BYTE c;
530    
531     MPFSGetBegin(ph->file);
532    
533     while( TCPIsPutReady(ph->socket) )
534     {
535     lbTransmit = FALSE;
536    
537     if ( ph->smHTTPGet != SM_HTTP_GET_VAR )
538     {
539     c = MPFSGet();
540     if ( MPFSIsEOF() )
541     {
542     MPFSGetEnd();
543     TCPFlush(ph->socket);
544     return TRUE;
545     }
546     }
547    
548     if ( ph->bProcess )
549     {
550     switch(ph->smHTTPGet)
551     {
552     case SM_HTTP_GET_READ:
553     if ( c == HTTP_VAR_ESC_CHAR )
554     ph->smHTTPGet = SM_HTTP_GET_DLE;
555     else
556     lbTransmit = TRUE;
557     break;
558    
559     case SM_HTTP_GET_DLE:
560     if ( c == HTTP_VAR_ESC_CHAR )
561     {
562     lbTransmit = TRUE;
563     ph->smHTTPGet = SM_HTTP_GET_READ;
564     }
565     else
566     {
567     ph->Variable = (c - '0') << 4;
568     ph->smHTTPGet = SM_HTTP_GET_HANDLE;
569     }
570     break;
571    
572     case SM_HTTP_GET_HANDLE:
573     ph->Variable |= (c - '0');
574    
575     ph->smHTTPGet = SM_HTTP_GET_VAR;
576     ph->VarRef = HTTP_START_OF_VAR;
577    
578     break;
579    
580     case SM_HTTP_GET_VAR:
581     ph->VarRef = HTTPGetVar(ph->Variable, ph->VarRef, &c);
582     lbTransmit = TRUE;
583     if ( ph->VarRef == HTTP_END_OF_VAR )
584     ph->smHTTPGet = SM_HTTP_GET_READ;
585     break;
586    
587     default:
588     while(1);
589     }
590    
591     if ( lbTransmit )
592     TCPPut(ph->socket, c);
593     }
594     else
595     TCPPut(ph->socket, c);
596    
597     }
598    
599     ph->file = MPFSGetEnd();
600    
601     // We are not done sending a file yet...
602     return FALSE;
603     }
604    
605    
606     /*********************************************************************
607     * Function: static HTTP_COMMAND HTTPParse(BYTE *string,
608     * BYTE** arg,
609     * BYTE* argc,
610     * BYTE* type)
611     *
612     * PreCondition: None
613     *
614     * Input: string - HTTP Command String
615     * arg - List of string pointer to hold
616     * HTTP arguments.
617     * argc - Pointer to hold total number of
618     * arguments in this command string/
619     * type - Pointer to hold type of file
620     * received.
621     * Valid values are:
622     * HTTP_TXT
623     * HTTP_HTML
624     * HTTP_GIF
625     * HTTP_CGI
626     * HTTP_UNKNOWN
627     *
628     * Output: HTTP FSM and connections are initialized
629     *
630     * Side Effects: None
631     *
632     * Overview: None
633     *
634     * Note: This function parses URL that may or may not
635     * contain arguments.
636     * e.g. "GET HTTP/1.0 thank.htm?name=MCHP&age=12"
637     * would be returned as below:
638     * arg[0] => GET
639     * arg[1] => thank.htm
640     * arg[2] => name
641     * arg[3] => MCHP
642     * arg[4] => 12
643     * argc = 5
644     *
645     * This parses does not "de-escape" URL string.
646     ********************************************************************/
647     static HTTP_COMMAND HTTPParse(BYTE *string,
648     BYTE** arg,
649     BYTE* argc,
650     BYTE* type)
651     {
652     BYTE i;
653     BYTE smParse;
654     HTTP_COMMAND cmd;
655     BYTE *ext;
656     BYTE c;
657     ROM char* fileType;
658    
659     enum
660     {
661     SM_PARSE_IDLE,
662     SM_PARSE_ARG,
663     SM_PARSE_ARG_FORMAT
664     };
665    
666     smParse = SM_PARSE_IDLE;
667     ext = NULL;
668     i = 0;
669    
670     // Only "GET" is supported for time being.
671     if ( !memcmppgm2ram(string, (ROM void*) HTTP_GET_STRING, HTTP_GET_STRING_LEN) )
672     {
673     string += (HTTP_GET_STRING_LEN + 1);
674     cmd = HTTP_GET;
675     }
676     else
677     {
678     return HTTP_NOT_SUPPORTED;
679     }
680    
681     // Skip white spaces.
682     while( *string == ' ' )
683     string++;
684    
685     c = *string;
686    
687     while ( c != ' ' && c != '\0' && c != '\r' && c != '\n' )
688    
689     {
690     // Do not accept any more arguments than we haved designed to.
691     if ( i >= *argc )
692     break;
693    
694     switch(smParse)
695     {
696     case SM_PARSE_IDLE:
697     arg[i] = string;
698     c = *string;
699     if ( c == '/' || c == '\\' )
700     smParse = SM_PARSE_ARG;
701     break;
702    
703     case SM_PARSE_ARG:
704     arg[i++] = string;
705     smParse = SM_PARSE_ARG_FORMAT;
706     /*
707     * Do not break.
708     * Parameter may be empty.
709     */
710    
711     case SM_PARSE_ARG_FORMAT:
712     c = *string;
713     if ( c == '?' || c == '&' )
714     {
715     *string = '\0';
716     smParse = SM_PARSE_ARG;
717     }
718     else
719     {
720     // Recover space characters.
721     if ( c == '+' )
722     *string = ' ';
723    
724     // Remember where file extension starts.
725     else if ( c == '.' && i == 1 )
726     {
727     ext = ++string;
728     }
729    
730     else if ( c == '=' )
731     {
732     *string = '\0';
733     smParse = SM_PARSE_ARG;
734     }
735    
736     // Only interested in file name - not a path.
737     else if ( c == '/' || c == '\\' )
738     arg[i-1] = string+1;
739    
740     }
741     break;
742     }
743     string++;
744     c = *string;
745     }
746     *string = '\0';
747    
748     *type = HTTP_UNKNOWN;
749     if ( ext != NULL )
750     {
751     ext = (BYTE*)strupr((char*)ext);
752    
753     fileType = httpFiles[0].fileExt;
754     for ( c = 0; c < TOTAL_FILE_TYPES; c++ )
755     {
756     if ( !memcmppgm2ram((void*)ext, (ROM void*)fileType, FILE_EXT_LEN) )
757     {
758     *type = c;
759     break;
760     }
761     fileType += sizeof(FILE_TYPES);
762    
763     }
764     }
765    
766     if ( i == 0 )
767     {
768     memcpypgm2ram(arg[0], (ROM void*)HTTP_DEFAULT_FILE_STRING,
769     HTTP_DEFAULT_FILE_STRING_LEN);
770     arg[0][HTTP_DEFAULT_FILE_STRING_LEN] = '\0';
771     *type = HTTP_HTML;
772     i++;
773     }
774     *argc = i;
775    
776     return cmd;
777     }
778    
779    
780    
781    
782    

  ViewVC Help
Powered by ViewVC 1.1.20