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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show 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 /*********************************************************************
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