OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [athttpd/] [current/] [src/] [http.c] - Blame information for rev 867

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
/* =================================================================
2
 *
3
 *      http.c
4
 *
5
 *      Handles the client requests.
6
 *
7
 * =================================================================
8
 * ####ECOSGPLCOPYRIGHTBEGIN####
9
 * -------------------------------------------
10
 * This file is part of eCos, the Embedded Configurable Operating System.
11
 * Copyright (C) 2005, 2007 Free Software Foundation, Inc.
12
 *
13
 * eCos is free software; you can redistribute it and/or modify it under
14
 * the terms of the GNU General Public License as published by the Free
15
 * Software Foundation; either version 2 or (at your option) any later
16
 * version.
17
 *
18
 * eCos is distributed in the hope that it will be useful, but WITHOUT
19
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21
 * for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with eCos; if not, write to the Free Software Foundation, Inc.,
25
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
26
 *
27
 * As a special exception, if other files instantiate templates or use
28
 * macros or inline functions from this file, or you compile this file
29
 * and link it with other works to produce a work based on this file,
30
 * this file does not by itself cause the resulting work to be covered by
31
 * the GNU General Public License. However the source code for this file
32
 * must still be made available in accordance with section (3) of the GNU
33
 * General Public License v2.
34
 *
35
 * This exception does not invalidate any other reasons why a work based
36
 * on this file might be covered by the GNU General Public License.
37
 * -------------------------------------------
38
 * ####ECOSGPLCOPYRIGHTEND####
39
 * =================================================================
40
 * #####DESCRIPTIONBEGIN####
41
 *
42
 *  Author(s):    Anthony Tonizzo (atonizzo@gmail.com)
43
 *  Contributors: Sergei Gavrikov (w3sg@SoftHome.net)
44
 *                Lars Povlsen    (lpovlsen@vitesse.com)
45
 *  Date:         2006-06-12
46
 *  Purpose:
47
 *  Description:
48
 *
49
 * ####DESCRIPTIONEND####
50
 *
51
 * =================================================================
52
 */
53
 
54
#include <pkgconf/hal.h>
55
#include <pkgconf/kernel.h>
56
#include <cyg/kernel/kapi.h>           // Kernel API.
57
#include <cyg/infra/diag.h>            // For diagnostic printing.
58
#include <network.h>
59
#include <time.h>
60
 
61
#include <cyg/hal/hal_tables.h>
62
#include <cyg/fileio/fileio.h>
63
#include <stdio.h>                     // sprintf().
64
#include <stdlib.h>
65
 
66
#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER
67
#include <cyg/objloader/elf.h>
68
#include <cyg/objloader/objelf.h>
69
#endif
70
 
71
#include <cyg/athttpd/http.h>
72
#include <cyg/athttpd/socket.h>
73
#include <cyg/athttpd/handler.h>
74
#include <cyg/athttpd/forms.h>
75
 
76
cyg_int32 debug_print = 0;
77
 
78
const char *day_of_week[7] = {"Sun", "Mon", "Tue", "Wed",
79
                                 "Thu", "Fri", "Sat"};
80
const char *month_of_year[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
81
                                    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
82
const char *home_pages[] = {"index.html",   "index.htm",
83
                            "default.html", "home.html"};
84
CYG_HAL_TABLE_BEGIN(cyg_httpd_mime_table, httpd_mime_table);
85
CYG_HAL_TABLE_END(cyg_httpd_mime_table_end, httpd_mime_table);
86
 
87
__externC cyg_httpd_mime_table_entry cyg_httpd_mime_table[];
88
__externC cyg_httpd_mime_table_entry cyg_httpd_mime_table_end[];
89
 
90
// Standard handlers added by default. Correspond to the most used extensions.
91
// The user can add his/her own later.
92
CYG_HTTPD_MIME_TABLE_ENTRY(hal_htm_entry, "htm",
93
                                       "text/html; charset=iso-8859-1");
94
CYG_HTTPD_MIME_TABLE_ENTRY(hal_html_entry, "html",
95
                                       "text/html; charset=iso-8859-1");
96
CYG_HTTPD_MIME_TABLE_ENTRY(hal_gif_entry, "gif", "image/gif");
97
CYG_HTTPD_MIME_TABLE_ENTRY(hal_jpg_entry, "jpg", "image/jpg");
98
CYG_HTTPD_MIME_TABLE_ENTRY(hal_png_entry, "png", "image/png");
99
CYG_HTTPD_MIME_TABLE_ENTRY(hal_css_entry, "css", "text/css");
100
CYG_HTTPD_MIME_TABLE_ENTRY(hal_js_entry, "js", "application/x-javascript");
101
 
102
void
103
cyg_httpd_send_error(cyg_int32 err_type)
104
{
105
    httpstate.status_code = err_type;
106
 
107
    // Errors pages close the socket and are never cached.
108
    httpstate.mode |= CYG_HTTPD_MODE_NO_CACHE;
109
 
110
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
111
    diag_printf("Sending error: %d\n", err_type);
112
#endif    
113
 
114
#ifdef CYGOPT_NET_ATHTTPD_USE_FS
115
    // Check if the user has defines his own error pages.
116
    struct stat sp;
117
    char file_name[CYG_HTTPD_MAXPATH];
118
    strcpy(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR);
119
    if (file_name[strlen(file_name)-1] != '/')
120
        strcat(file_name, "/");
121
    strcat(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ERRORDIR);
122
    if (file_name[strlen(file_name)-1] != '/')
123
        strcat(file_name, "/");
124
    sprintf(file_name + strlen(file_name), "error_%d.html", err_type);
125
    cyg_httpd_cleanup_filename(file_name);
126
    cyg_int32 rc = stat(file_name, &sp);
127
    if (rc == 0)
128
    {
129
        char *extension = rindex(file_name, '.');
130
        if (extension == NULL)
131
            // No extension in the file name.
132
            httpstate.mime_type = 0;
133
        else
134
            httpstate.mime_type = cyg_httpd_find_mime_string(++extension);
135
 
136
        httpstate.payload_len  = sp.st_size;
137
        cyg_int32 header_length = cyg_httpd_format_header();
138
        cyg_httpd_write(httpstate.outbuffer, header_length);
139
 
140
        // File found.
141
        FILE *fp = fopen(file_name, "r");
142
        if(fp == NULL)
143
            return;
144
 
145
        ssize_t payload_size = fread(httpstate.outbuffer,
146
                                     1,
147
                                     CYG_HTTPD_MAXOUTBUFFER,
148
                                     fp);
149
        while (payload_size > 0)
150
        {
151
            ssize_t bytes_written = cyg_httpd_write_chunked(httpstate.outbuffer,
152
                                                            payload_size);
153
            if (bytes_written != payload_size)
154
                break;
155
 
156
            payload_size = fread(httpstate.outbuffer,
157
                                 1,
158
                                 CYG_HTTPD_MAXOUTBUFFER,
159
                                 fp);
160
        }
161
 
162
        fclose(fp);
163
        return;
164
    }
165
#endif    
166
 
167
    // Because the size of the frame is not known upfront (every error message
168
    //  is different and thus has different length) we use chunked frames to
169
    //  send the message out.
170
#if defined(CYGOPT_NET_ATHTTPD_CLOSE_CHUNKED_CONNECTIONS)
171
    httpstate.mode |= CYG_HTTPD_MODE_CLOSE_CONN;
172
#endif
173
 
174
    httpstate.mode |= CYG_HTTPD_MODE_TRANSFER_CHUNKED;
175
    httpstate.status_code = err_type;
176
    httpstate.last_modified = -1;
177
    httpstate.mime_type = "text/html";
178
    cyg_int32 header_length = cyg_httpd_format_header();
179
    cyg_httpd_write(httpstate.outbuffer, header_length);
180
 
181
    // If no file has been defined, send a simple notification. We must use
182
    //  chunked frames, because we do not know upfron the length of the
183
    //  packet we have to send.
184
    strcpy(httpstate.outbuffer,
185
           "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n");
186
    switch (err_type)
187
    {
188
    case CYG_HTTPD_STATUS_MOVED_PERMANENTLY:
189
        strcat(httpstate.outbuffer,
190
               "<html><head><title>301 Moved Permanently</title></head>\r\n"
191
               "<body><h1>Moved Permanently</h1>\r\n"
192
               "<p>The document has moved <a href=\"");
193
        strcat(httpstate.outbuffer, httpstate.url);
194
        strcat(httpstate.outbuffer, "\">here</a>.\r\n");
195
        break;
196
    case CYG_HTTPD_STATUS_MOVED_TEMPORARILY:
197
        strcat(httpstate.outbuffer,
198
               "<html><head><title>302 Found</title></head>\r\n"
199
               "<body><h1>Redirect</h1>\r\n"
200
               "<p>Please continue <a href=\"");
201
        strcat(httpstate.outbuffer, httpstate.url);
202
        strcat(httpstate.outbuffer, "\">here</a>.\r\n");
203
        break;
204
    case CYG_HTTPD_STATUS_NOT_AUTHORIZED:
205
        strcat(httpstate.outbuffer,
206
               "<html><head><title>401 Not Authorized</title></head>\r\n");
207
        strcat(httpstate.outbuffer,
208
               "<body><p>Authorization required to access this URL.</p>\r\n");
209
        break;
210
    case CYG_HTTPD_STATUS_NOT_MODIFIED:
211
        cyg_httpd_end_chunked();
212
        return;
213
    case CYG_HTTPD_STATUS_NOT_FOUND:
214
        strcat(httpstate.outbuffer,
215
               "<html><head><title>404 Not Found</title></head>\r\n");
216
        sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
217
                "<p>The requested URL: %s was not found on this server</p>\r\n",
218
                httpstate.url);
219
        break;
220
    case CYG_HTTPD_STATUS_SYSTEM_ERROR:
221
        strcat(httpstate.outbuffer,
222
               "<html><head><title>500 Server Error</title></head>\r\n");
223
        strcat(httpstate.outbuffer,
224
               "<p>The server encountered an unexpected condition that "
225
               "prevented it from fulfilling the request"
226
               " by the client</p>\r\n");
227
        break;
228
    case CYG_HTTPD_STATUS_NOT_IMPLEMENTED:
229
        strcat(httpstate.outbuffer,
230
               "<html><head><title>501 Not Implemented</title></head>\r\n");
231
        strcat(httpstate.outbuffer,
232
               "<p>The method requested is not implemented</p>\r\n");
233
        break;
234
    default:
235
        strcat(httpstate.outbuffer,
236
               "<html><head><title>400 Bad Request</title></head>\r\n");
237
        strcat(httpstate.outbuffer,
238
               "<p>Bad request</p>\r\n");
239
        break;
240
    }
241
 
242
    sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
243
            "<hr>%s at %d.%d.%d.%d Port %d\r\n</body></html>\r\n",
244
            CYGDAT_NET_ATHTTPD_SERVEROPT_SERVERID,
245
            httpstate.host[0],
246
            httpstate.host[1],
247
            httpstate.host[2],
248
            httpstate.host[3],
249
            CYGNUM_NET_ATHTTPD_SERVEROPT_PORT);
250
 
251
    cyg_httpd_write_chunked(httpstate.outbuffer, strlen(httpstate.outbuffer));
252
    cyg_httpd_end_chunked();
253
}
254
 
255
// Return a time_t that is always UTC (aka GMT).
256
time_t
257
cyg_httpd_parse_date(char *time)
258
{
259
    int    i;
260
    char   month[4];
261
    struct tm tm_mod;
262
 
263
    // We are going to get rid of the day of the week. This is always the first
264
    //  part of the string, separated by a blank.
265
    time = strchr( time, ' ');
266
    if ( time == NULL)
267
        return 0;
268
    time++;
269
 
270
    /// RFC1123. The date is in the format: Sun, 06 Nov 1994 08:49:37 GMT.
271
    cyg_int32 rc = sscanf(time,
272
                          "%2d %3s %4d %2d:%2d:%2d GMT",
273
                          &tm_mod.tm_mday,
274
                          month,
275
                          &tm_mod.tm_year,
276
                          &tm_mod.tm_hour,
277
                          &tm_mod.tm_min,
278
                          &tm_mod.tm_sec);
279
    if (rc != 6)
280
    {
281
        // RFC1036. The date is in the format: Sunday, 06-Nov-94 08:49:37 GMT.
282
        rc = sscanf(time,
283
                    "%2d-%3s-%2d %2d:%2d:%2d GMT",
284
                    &tm_mod.tm_mday,
285
                    month,
286
                    &tm_mod.tm_year,
287
                    &tm_mod.tm_hour,
288
                    &tm_mod.tm_min,
289
                    &tm_mod.tm_sec);
290
        if (rc != 6)
291
        {
292
            // asctime().
293
            rc = sscanf(time,"%3s %2d %2d:%2d:%2d %4d",
294
                        month,
295
                        &tm_mod.tm_mday,
296
                        &tm_mod.tm_hour,
297
                        &tm_mod.tm_min,
298
                        &tm_mod.tm_sec,
299
                        &tm_mod.tm_year);
300
            if (rc != 6)
301
                return 0;
302
        }
303
    }
304
 
305
    for (i = 0; i < sizeof(month_of_year); i++)
306
        if (strcmp(month, month_of_year[i]) == 0)
307
        {
308
            tm_mod.tm_mon = i;
309
            if (tm_mod.tm_year > 1900)
310
                tm_mod.tm_year -= 1900;
311
            return mktime(&tm_mod);
312
        }
313
 
314
    return 0;
315
}
316
 
317
// Finds the mime string into the mime_table associated with a specific 
318
//  extension. Returns the MIME type to send in the header, or NULL if the
319
//  extension is not in the table.
320
char*
321
cyg_httpd_find_mime_string(char *ext)
322
{
323
    cyg_httpd_mime_table_entry *entry = cyg_httpd_mime_table;
324
 
325
    while (entry != cyg_httpd_mime_table_end)
326
    {
327
        if (!strcmp((const char*)ext, entry->extension))
328
            return entry->mime_string;
329
        entry++;
330
    }
331
 
332
    return (char*)0;
333
}
334
 
335
void
336
cyg_httpd_cleanup_filename(char *filename)
337
{
338
    char *src = strstr(filename, "//");
339
    while (src != 0)
340
    {
341
        strcpy(src + 1, src + 2);
342
        src = strstr(filename, "//");
343
    }
344
 
345
    src = strstr(filename, "/./");
346
    while (src != 0)
347
    {
348
        strcpy(src + 1, src + 3);
349
        src = strstr(filename, "/./");
350
    }
351
 
352
    src = strstr(filename, "/../");
353
    while (src != 0)
354
    {
355
        char *comp1 = filename, *comp2 = filename;
356
 
357
        // Search the path component before this redirection.
358
        while ((comp1 = strchr(comp1, '/')) != src)
359
            comp2 = ++comp1;
360
 
361
        strcpy(comp2, src + 4);
362
        src = strstr(filename, "/../");
363
    }
364
}
365
 
366
cyg_int32
367
cyg_httpd_initialize(void)
368
{
369
    httpstate.post_data = NULL;
370
    httpstate.needs_auth = (cyg_httpd_auth_table_entry *)0;
371
    return 0;
372
}
373
 
374
void
375
cyg_httpd_append_homepage(char *root)
376
{
377
#ifdef CYGOPT_NET_ATHTTPD_USE_FS
378
    struct stat sp;
379
    cyg_int32 i;
380
 
381
    cyg_int32 root_len = strlen(root);
382
    for (i = 0; i < sizeof(home_pages)/sizeof(char*); i++)
383
    {
384
        root[root_len] = '\0';
385
        sprintf(root + root_len, "%s", home_pages[i]);
386
        cyg_int32 rc = stat(root, &sp);
387
        if (rc == 0)
388
            return;
389
    }
390
    root[root_len] = 0;
391
#endif    
392
 
393
#ifdef CYGDAT_NET_ATHTTPD_ALTERNATE_HOME    
394
    if (strcmp(root, "/") == 0)
395
        // The client is trying to open the main index file.
396
        strcat(root, CYGDAT_NET_ATHTTPD_ALTERNATE_HOME);
397
#endif    
398
}
399
 
400
#ifdef CYGOPT_NET_ATHTTPD_USE_FS
401
void
402
cyg_httpd_send_file(char *name)
403
{
404
    cyg_int32  err;
405
    FILE      *fp;
406
    struct stat sp;
407
    char       file_name[CYG_HTTPD_MAXPATH];
408
 
409
    strcpy(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR);
410
    if (file_name[strlen(file_name)-1] != '/')
411
        strcat(file_name, "/");
412
    strcat(file_name, name);
413
    cyg_httpd_cleanup_filename(file_name);
414
 
415
    // Check if the file is in the file system. This will also give us the
416
    //  size of the file, to be used in the HTTP header.
417
    cyg_int32 rc = stat(file_name, &sp);
418
    if (rc < 0)
419
    {
420
        // Before giving up, we make a last ditch attempt at finding a file
421
        //  within the internal resources of the server. The user can add
422
        //  his/her own files to the table.
423
        cyg_httpd_ires_table_entry *p = cyg_httpd_find_ires(name);
424
        if (p != NULL)
425
        {
426
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
427
            diag_printf("Sending Internal Resource: %s\n", name);
428
#endif    
429
            cyg_httpd_send_ires(p);
430
        }
431
        else
432
            cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
433
        return;
434
    }
435
 
436
    if (S_ISDIR(sp.st_mode))
437
    {
438
        char tmp_url[CYG_HTTPD_MAXURL];
439
        strcpy(tmp_url, httpstate.url);
440
        // Directories need a trialing slash, and if missing, we'll redirect
441
        //  the client to the right URL. This is called (appropriately
442
        //  enough) "Trailing-Slash Redirection". 
443
        if (name[strlen(name)-1] != '/')
444
        {
445
            sprintf(httpstate.url,
446
                    "http://%d.%d.%d.%d:%d%s/",
447
                    httpstate.host[0],
448
                    httpstate.host[1],
449
                    httpstate.host[2],
450
                    httpstate.host[3],
451
                    CYGNUM_NET_ATHTTPD_SERVEROPT_PORT,
452
                    tmp_url);
453
            cyg_httpd_send_error(CYG_HTTPD_STATUS_MOVED_PERMANENTLY);
454
            return;
455
        }
456
 
457
        // We are going to try to locate an index page in the directory we got
458
        //  in the URL. 
459
        cyg_httpd_append_homepage(file_name);
460
        if (file_name[strlen(file_name)-1] == '/')
461
        {
462
#ifdef CYGOPT_NET_ATHTTPD_USE_DIRLIST
463
            // No home page found, we are sending a directory listing.
464
            cyg_httpd_send_directory_listing(name);
465
#else
466
            cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
467
#endif
468
            return;
469
        }
470
        stat(file_name, &sp);
471
    }
472
 
473
    httpstate.last_modified = sp.st_mtime;
474
 
475
    // Let's see if we luck out and can send a 304.
476
    if ((httpstate.modified_since != -1) &&
477
                   (httpstate.modified_since >= httpstate.last_modified))
478
    {
479
        cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_MODIFIED);
480
        return;
481
    }
482
    else
483
        httpstate.status_code = CYG_HTTPD_STATUS_OK;
484
 
485
    // Here we'll look for an extension to the file. Consider the case where
486
    //  there might be more than one dot in the file name. We'll look for just
487
    //  the last one, then we'll check the extension.
488
    char *extension = rindex(file_name, '.');
489
    if (extension == NULL)
490
        httpstate.mime_type = 0;
491
    else
492
        httpstate.mime_type = cyg_httpd_find_mime_string(++extension);
493
 
494
    httpstate.payload_len  = sp.st_size;
495
    httpstate.mode &= ~CYG_HTTPD_MODE_NO_CACHE;
496
    cyg_int32 payload_size = cyg_httpd_format_header();
497
    if ((httpstate.mode & CYG_HTTPD_MODE_SEND_HEADER_ONLY) != 0)
498
    {
499
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
500
        diag_printf("Sending header only for URL: %s\n", file_name);
501
#endif    
502
        send(httpstate.sockets[httpstate.client_index].descriptor,
503
             httpstate.outbuffer,
504
             payload_size,
505
             0);
506
        return;
507
    }
508
 
509
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
510
    diag_printf("Sending file: %s\n", file_name);
511
#endif    
512
    fp = fopen(file_name, "r");
513
    if (fp == NULL)
514
    {
515
        // We should really read errno and send messages accordingly...
516
        cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
517
        return;
518
    }
519
 
520
    // Fill up the rest of the buffer and send it out.
521
    cyg_int32 bread = fread(httpstate.outbuffer + strlen(httpstate.outbuffer),
522
                            1,
523
                            CYG_HTTPD_MAXOUTBUFFER - payload_size,
524
                            fp);
525
    cyg_httpd_write(httpstate.outbuffer, payload_size + bread);
526
 
527
    ssize_t bytes_written = 0;
528
    sp.st_size -= bread;
529
    while (bytes_written < sp.st_size)
530
    {
531
        bread = fread(httpstate.outbuffer, 1, CYG_HTTPD_MAXOUTBUFFER, fp);
532
        bytes_written += cyg_httpd_write(httpstate.outbuffer, bread);
533
    }
534
 
535
    err = fclose(fp);
536
    if (err < 0)
537
        cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
538
}
539
#endif
540
 
541
cyg_int32
542
cyg_httpd_format_header(void)
543
{
544
    sprintf(httpstate.outbuffer, "HTTP/1.1 %d", httpstate.status_code);
545
    time_t time_val = time(NULL);
546
 
547
    // Error messages (i.e. with status other than OK, automatically add
548
    //  the no-cache header.
549
    switch (httpstate.status_code)
550
    {
551
    case CYG_HTTPD_STATUS_MOVED_PERMANENTLY:
552
        strcat(httpstate.outbuffer, " Moved Permanently\r\n");
553
        strcat(httpstate.outbuffer, "Location: ");
554
        strcat(httpstate.outbuffer, httpstate.url);
555
        strcat(httpstate.outbuffer, "\r\n");
556
        sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
557
                "Content-Length: %d\r\n",
558
                httpstate.payload_len);
559
        break;
560
    case CYG_HTTPD_STATUS_MOVED_TEMPORARILY:
561
        strcat(httpstate.outbuffer, " Found\r\n");
562
        strcat(httpstate.outbuffer, "Location: ");
563
        strcat(httpstate.outbuffer, httpstate.url);
564
        strcat(httpstate.outbuffer, "\r\n");
565
        sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
566
                "Content-Length: %d\r\n",
567
                httpstate.payload_len);
568
        break;
569
#ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
570
    case CYG_HTTPD_STATUS_NOT_AUTHORIZED:
571
        // A 401 error closes the connection right away.
572
        httpstate.mode |= CYG_HTTPD_MODE_CLOSE_CONN;
573
        strcat(httpstate.outbuffer, " Not Authorized\r\n");
574
 
575
        // Here we should set the proper header based on the authentication
576
        //  required (httpstate.needs_authMode) but for now, with only
577
        //  Basic Authentication supported, there is no need to do so.
578
        if (httpstate.needs_auth->auth_mode == CYG_HTTPD_AUTH_BASIC)
579
        {
580
            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
581
                    "WWW-Authenticate: Basic realm=\"%s\"\r\n",
582
                    httpstate.needs_auth->auth_domainname);
583
        }
584
        else
585
        {
586
            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
587
                     "WWW-Authenticate: Digest realm=\"%s\", ",
588
                     httpstate.needs_auth->auth_domainname);
589
            strftime(cyg_httpd_md5_nonce,
590
                     33,
591
                     TIME_FORMAT_RFC1123,
592
                     gmtime(&time_val));
593
            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
594
                    "nonce=\"%s\", ", cyg_httpd_md5_nonce);
595
            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
596
                    "opaque=\"%s\", ",
597
                    CYG_HTTPD_MD5_AUTH_OPAQUE);
598
            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
599
                    "stale=false, algorithm=%s, qop=\"%s\"\r\n",
600
                    CYG_HTTPD_MD5_AUTH_NAME,
601
                    CYG_HTTPD_MD5_AUTH_QOP);
602
        }
603
        break;
604
#endif
605
    case CYG_HTTPD_STATUS_NOT_MODIFIED:
606
        strcat(httpstate.outbuffer, " Not Modified\r\n");
607
        break;
608
    case CYG_HTTPD_STATUS_NOT_FOUND:
609
        strcat(httpstate.outbuffer, " Not Found\r\n");
610
        sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
611
                "Content-Length: %d\r\n",
612
                httpstate.payload_len);
613
        break;
614
    case CYG_HTTPD_STATUS_METHOD_NOT_ALLOWED:
615
        strcat(httpstate.outbuffer, " Method Not Allowed\r\n");
616
        break;
617
    default:
618
        strcat(httpstate.outbuffer, " OK\r\n");
619
        if ((httpstate.mode & CYG_HTTPD_MODE_TRANSFER_CHUNKED) == 0)
620
            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
621
                    "Content-Length: %d\r\n",
622
                    httpstate.payload_len);
623
        break;
624
    }
625
 
626
    strcat(httpstate.outbuffer, "Date: ");
627
    strftime(httpstate.outbuffer + strlen(httpstate.outbuffer),
628
             CYG_HTTPD_MAXOUTBUFFER - strlen(httpstate.outbuffer),
629
             TIME_FORMAT_RFC1123,
630
             gmtime(&time_val));
631
    strcat(httpstate.outbuffer, "\r\n");
632
 
633
    sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
634
            "Server: %s\r\n",
635
            CYGDAT_NET_ATHTTPD_SERVEROPT_SERVERID);
636
 
637
    if (httpstate.mode & CYG_HTTPD_MODE_CLOSE_CONN)
638
        strcat(httpstate.outbuffer, "Connection: close\r\n");
639
    else
640
        strcat(httpstate.outbuffer, "Connection: keep-alive\r\n");
641
 
642
    // When we cannot find the appropriate MIME type, we'll send a default type.
643
    if (httpstate.mime_type == 0)
644
        httpstate.mime_type = CYGDAT_NET_ATHTTPD_DEFAULT_MIME_TYPE;
645
    sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
646
            "Content-Type: %s\r\n",
647
            httpstate.mime_type);
648
 
649
    if (httpstate.mode & CYG_HTTPD_MODE_TRANSFER_CHUNKED)
650
        strcat(httpstate.outbuffer, "Transfer-Encoding: chunked\r\n");
651
 
652
    if (httpstate.mode & CYG_HTTPD_MODE_NO_CACHE)
653
        strcat(httpstate.outbuffer, "Cache-Control: no-cache\r\n");
654
 
655
    if (httpstate.last_modified != -1)
656
    {
657
        time_val = httpstate.last_modified;
658
        strcat(httpstate.outbuffer, "Last-Modified: ");
659
        strftime(httpstate.outbuffer + strlen(httpstate.outbuffer),
660
                 CYG_HTTPD_MAXOUTBUFFER - strlen(httpstate.outbuffer),
661
                 TIME_FORMAT_RFC1123,
662
                 gmtime(&time_val));
663
        strcat(httpstate.outbuffer, "\r\n");
664
 
665
#if (CYGOPT_NET_ATHTTPD_DOCUMENT_EXPIRATION_TIME != 0)                 
666
        time_val += CYGOPT_NET_ATHTTPD_DOCUMENT_EXPIRATION_TIME;
667
        strcat(httpstate.outbuffer, "Expires: ");
668
        strftime(httpstate.outbuffer + strlen(httpstate.outbuffer),
669
                 CYG_HTTPD_MAXOUTBUFFER - strlen(httpstate.outbuffer),
670
                 TIME_FORMAT_RFC1123,
671
                 gmtime(&time_val));
672
        strcat(httpstate.outbuffer, "\r\n");
673
#endif
674
    }
675
 
676
    // There must be 2 carriage returns between the header and the body, 
677
    //  so if you modify this function make sure that there is another 
678
    //  CRLF already terminating the buffer thus far.
679
    strcat(httpstate.outbuffer, "\r\n");
680
    return strlen(httpstate.outbuffer);
681
}
682
 
683
void
684
cyg_httpd_handle_method_GET(void)
685
{
686
#if defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER) ||\
687
                             defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL)
688
    // If the URL is a CGI script, there is a different directory...
689
    if (httpstate.url[0] == '/' &&
690
                    !strncmp(httpstate.url + 1,
691
                              CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR,
692
                              strlen(CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR)))
693
    {
694
        cyg_httpd_exec_cgi();
695
        return;
696
    }
697
    // If the OBJLOADER package is not loaded, then the request for a library
698
    //  will likely generate a 404.
699
#endif    
700
 
701
    // User defined handlers take precedence over other forms of response.
702
    handler h = cyg_httpd_find_handler();
703
    if (h != 0)
704
    {
705
        h(&httpstate);
706
        return;
707
    }
708
 
709
 
710
#ifdef CYGOPT_NET_ATHTTPD_USE_FS
711
    // No handler, we'll redirect to the file system.
712
    cyg_httpd_send_file(httpstate.url);
713
#else
714
    // If we do not have a file system, we look for the file within the 
715
    //  internal resources of the server. The user can add his/her own files
716
    //  to the table.
717
    if (strcmp(httpstate.url, "/") == 0)
718
    {
719
        int i;
720
        cyg_httpd_ires_table_entry *p;
721
        for (i = 0; i < sizeof(home_pages)/sizeof(char*); i++)
722
        {
723
            httpstate.url[1] = '\0';
724
            strcat(httpstate.url, home_pages[i]);
725
            p = cyg_httpd_find_ires(httpstate.url);
726
            if (p != NULL)
727
            {
728
                cyg_httpd_send_ires(p);
729
                return;
730
            }
731
        }
732
    }
733
    else
734
    {
735
        cyg_httpd_ires_table_entry *p = cyg_httpd_find_ires(httpstate.url);
736
        if (p != NULL)
737
        {
738
            cyg_httpd_send_ires(p);
739
            return;
740
        }
741
    }
742
    cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
743
#endif    
744
}
745
 
746
char*
747
cyg_httpd_get_URL(char* p)
748
{
749
    char* dest = httpstate.url;
750
 
751
    // First get rid of multiple leading slashes.
752
    while ((p[0] == '/') && (p[1] == '/'))
753
       p++;
754
 
755
    // Store the url, and check if there is a form result in it.
756
    while ((*p != ' ') && (*p != '?') &&
757
            ((dest - httpstate.url) <= CYG_HTTPD_MAXURL))
758
    {
759
        // Look for encoded characters in the URL.
760
        if (*p == '%')
761
        {
762
            p++;
763
            cyg_int8 ch = cyg_httpd_from_hex(*p++);
764
            if (ch == -1)
765
            {
766
                cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
767
                return (char*)0;
768
            }
769
            *dest = ch << 4;
770
            ch = cyg_httpd_from_hex(*p++);
771
            if (ch == -1)
772
            {
773
                cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
774
                return (char*)0;
775
            }
776
            *dest += ch;
777
            dest++;
778
        }
779
        else
780
            *dest++ = *p++;
781
    }
782
 
783
    // Terminate the file name...
784
    *dest = '\0';
785
 
786
    // The URL must start with a leading slash.
787
    if (httpstate.url[0] != '/')
788
    {
789
        cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
790
        return (char*)0;
791
    }
792
    return p;
793
}
794
 
795
char*
796
cyg_httpd_parse_POST(char* p)
797
{
798
    httpstate.method = CYG_HTTPD_METHOD_POST;
799
    char *cp = cyg_httpd_get_URL(p);
800
    if (cp == 0)
801
        return (char*)0;
802
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
803
    diag_printf("POST Request URL: %s\n", httpstate.url);
804
#endif    
805
 
806
    while (*cp++ != '\n');
807
    return cp;
808
}
809
 
810
char*
811
cyg_httpd_parse_GET(char* p)
812
{
813
    char *cp = cyg_httpd_get_URL(p);
814
    if (cp == 0)
815
        return 0;
816
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
817
    if ( httpstate.method == CYG_HTTPD_METHOD_GET)
818
        diag_printf("GET Request URL: %s\n", httpstate.url);
819
    else
820
        diag_printf("HEAD Request URL: %s\n", httpstate.url);
821
#endif    
822
 
823
    if (*cp == '?')
824
        // If we have a GET header with form variables we'll get the
825
        //  variables out of it and store them in the variable table.
826
        // Can we assume that HEAD request can have form variables?
827
        // That will be a yes until I learn otherwise.
828
        cp = cyg_httpd_store_form_data(++cp);
829
 
830
    // Run to end of line.
831
    while (*cp++ != '\n');
832
    return cp;
833
}
834
 
835
char*
836
cyg_httpd_process_header(char *p)
837
{
838
#ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
839
    // Clear the previous request's response. The client properly authenticated
840
    //  will always reinitialize this variable during the header parsing
841
    //  process. This variable is also commandeered to hold the hashed
842
    //  username:password duo in the basic authentication.
843
    cyg_httpd_md5_response[0] = '\0';
844
#endif
845
 
846
    // The deafult for HTTP 1.1 is keep-alive connections, unless specifically
847
    //  closed by the far end.
848
    httpstate.mode &= ~(CYG_HTTPD_MODE_CLOSE_CONN | CYG_HTTPD_MODE_FORM_DATA |\
849
                                        CYG_HTTPD_MODE_SEND_HEADER_ONLY);
850
    httpstate.modified_since = -1;
851
    httpstate.content_len = 0;
852
    while (p < httpstate.request_end)
853
    {
854
        if (strncasecmp("GET ", p, 4) == 0)
855
        {
856
            // We need separate flags for HEAD and SEND_HEADERS_ONLY since
857
            //  we can send a header only even in the case of a GET request
858
            //  (as a 304 response.)
859
            httpstate.method = CYG_HTTPD_METHOD_GET;
860
            httpstate.mode &= ~CYG_HTTPD_MODE_SEND_HEADER_ONLY;
861
            p = cyg_httpd_parse_GET(p + 4);
862
            if (p ==0)
863
                return (char*)0;
864
        }
865
        else if (strncasecmp("POST ", p, 5) == 0)
866
        {
867
            p = cyg_httpd_parse_POST(p + 5);
868
            if (p ==0)
869
                return (char*)0;
870
        }
871
        else if (strncasecmp("HEAD ", p, 5) == 0)
872
        {
873
            httpstate.method = CYG_HTTPD_METHOD_HEAD;
874
            httpstate.mode |= CYG_HTTPD_MODE_SEND_HEADER_ONLY;
875
            p = cyg_httpd_parse_GET(p + 5);
876
            if (p ==0)
877
                return (char*)0;
878
        }
879
        else if (strncasecmp(p, "Content-Length: ", 16) == 0)
880
        {
881
            p = strchr(p, ':') + 2;
882
            if (p)
883
                // In the case of a POST request, this is the total length of
884
                //  the payload, which might be spread across several frames.
885
                httpstate.content_len = atoi(p);
886
            while (*p++ != '\n');
887
        }
888
        else if (strncasecmp(p, "Content-Type: ", 14) == 0)
889
        {
890
            p = strchr(p, ':') + 2;
891
            if (p)
892
                // In the case of a POST request, this is the total length of
893
                //  the payload, which might be spread across several frames.
894
                if (strncasecmp(p,
895
                                "application/x-www-form-urlencoded",
896
                                33) == 0)
897
                    httpstate.mode |= CYG_HTTPD_MODE_FORM_DATA;
898
            while (*p++ != '\n');
899
        }
900
        else if (strncasecmp("Host:", p, 5) == 0)
901
        {
902
            p += 5;
903
            if (*p == ' ')
904
                p++;
905
            sscanf(p,
906
                   "%d.%d.%d.%d",
907
                   &httpstate.host[0],
908
                   &httpstate.host[1],
909
                   &httpstate.host[2],
910
                   &httpstate.host[3]);
911
            while (*p++ != '\n');
912
        }
913
        else if (strncasecmp("If-Modified-Since:", p, 18) == 0)
914
        {
915
            p += 18;
916
            if ( *p == ' ')
917
                p++;
918
            httpstate.modified_since = cyg_httpd_parse_date(p);
919
            while (*p++ != '\n');
920
        }
921
#ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
922
        else if (strncasecmp("Authorization:", p, 14) == 0)
923
        {
924
            p += 14;
925
            while (*p == ' ')
926
                p++;
927
            if (strncasecmp("Basic", p, 5) == 0)
928
            {
929
                p += 5;
930
                while (*p == ' ')
931
                    p++;
932
                cyg_int32 auth_data_length = 0;
933
                while (*p != '\n')
934
                {
935
                    // We are going to copy only up to 
936
                    //  AUTH_STORAGE_BUFFER_LENGTH characters to prevent
937
                    //  overflow of the cyg_httpd_md5_response variable.
938
                    if (auth_data_length < AUTH_STORAGE_BUFFER_LENGTH)
939
                        if ((*p != '\r') && (*p != ' '))
940
                            cyg_httpd_md5_response[auth_data_length++] = *p;
941
                    p++;
942
                }
943
                p++;
944
                cyg_httpd_md5_response[auth_data_length] = '\0';
945
            }
946
            else if (strncasecmp(p, "Digest", 6) == 0)
947
            {
948
                p += 6;
949
                while (*p == ' ')
950
                   p++;
951
                while (*p != '\n')
952
                {
953
                    if (strncasecmp(p, "realm=", 6) == 0)
954
                        p = cyg_httpd_digest_skip(p + 6);
955
                    else if (strncasecmp(p, "username=", 9) == 0)
956
                        p = cyg_httpd_digest_skip(p + 9);
957
                    else if (strncasecmp(p, "nonce=", 6) == 0)
958
                        p = cyg_httpd_digest_skip(p + 6);
959
                    else if (strncasecmp(p, "response=", 9) == 0)
960
                        p = cyg_httpd_digest_data(cyg_httpd_md5_response,
961
                                                  p + 9);
962
                    else if (strncasecmp(p, "cnonce=", 7) == 0)
963
                        p = cyg_httpd_digest_data(cyg_httpd_md5_cnonce, p + 7);
964
                    else if (strncasecmp(p, "qop=", 4) == 0)
965
                        p = cyg_httpd_digest_skip(p + 4);
966
                    else if (strncasecmp(p, "nc=", 3) == 0)
967
                        p = cyg_httpd_digest_data(cyg_httpd_md5_noncecount,
968
                                                  p + 3);
969
                    else if (strncasecmp(p, "algorithm=", 10) == 0)
970
                        p = cyg_httpd_digest_skip(p + 10);
971
                    else if (strncasecmp(p, "opaque=", 7) == 0)
972
                        p = cyg_httpd_digest_skip(p + 7);
973
                    else if (strncasecmp(p, "uri=", 4) == 0)
974
                        p = cyg_httpd_digest_skip(p + 4);
975
                    else
976
                        p++;
977
                }
978
                p++;
979
            }
980
            else
981
                while (*p++ != '\n');
982
        }
983
#endif // CYGOPT_NET_ATHTTPD_USE_AUTH
984
        else if (strncasecmp(p, "Connection:", 11) == 0)
985
        {
986
            p += 11;
987
            while (*p == ' ')
988
               p++;
989
            if (strncasecmp(p, "close", 5) == 0)
990
                httpstate.mode |= CYG_HTTPD_MODE_CLOSE_CONN;
991
            while (*p++ != '\n');
992
        }
993
        else
994
            // We'll just dump the rest of the line and move on to the next.
995
            while (*p++ != '\n');
996
    }
997
    return p;
998
}
999
 
1000
void
1001
cyg_httpd_process_method(void)
1002
{
1003
    char* p = httpstate.inbuffer;
1004
 
1005
    // Some browsers send an extra '\r\n' after the POST data that is not
1006
    //  accounted in the "Content-Length:" field. We are going to junk all
1007
    //  the leading returns and line carriages we find.
1008
    while ((*p == '\r') || (*p =='\n'))
1009
        p++;
1010
 
1011
    while (*p != '\0')
1012
    {
1013
        p = cyg_httpd_process_header(p);
1014
        if (p == 0)
1015
            return;
1016
 
1017
#ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
1018
        // Let's check that the requested URL is not inside some directory that 
1019
        //  needs authentication.
1020
        cyg_httpd_auth_table_entry* auth =
1021
                                  cyg_httpd_is_authenticated(httpstate.url);
1022
        if (auth != 0)
1023
        {
1024
            cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_AUTHORIZED);
1025
            return;
1026
        }
1027
#endif
1028
        switch (httpstate.method)
1029
        {
1030
            case CYG_HTTPD_METHOD_GET:
1031
            case CYG_HTTPD_METHOD_HEAD:
1032
                cyg_httpd_handle_method_GET();
1033
                break;
1034
            case CYG_HTTPD_METHOD_POST:
1035
                cyg_httpd_handle_method_POST();
1036
                return;
1037
                break;
1038
            default:
1039
                cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_IMPLEMENTED);
1040
                return;
1041
            break;
1042
        }
1043
    }
1044
}
1045
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.