Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
363 johboh 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)