1 /* =================================================================
5 * Handles the client requests.
7 * =================================================================
8 * ####ECOSGPLCOPYRIGHTBEGIN####
9 * -------------------------------------------
10 * This file is part of eCos, the Embedded Configurable Operating
12 * Copyright (C) 2005, 2007 eCosCentric Ltd.
14 * eCos is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 or (at your option)
19 * eCos is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with eCos; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 * As a special exception, if other files instantiate templates or
29 * use macros or inline functions from this file, or you compile this
30 * file and link it with other works to produce a work based on this
31 * file, this file does not by itself cause the resulting work to be
32 * covered by the GNU General Public License. However the source code
33 * for this file must still be made available in accordance with
34 * section (3) of the GNU General Public License.
36 * This exception does not invalidate any other reasons why a work
37 * based on this file might be covered by the GNU General Public
40 * -------------------------------------------
41 * ####ECOSGPLCOPYRIGHTEND####
42 * =================================================================
43 * #####DESCRIPTIONBEGIN####
45 * Author(s): Anthony Tonizzo (atonizzo@gmail.com)
46 * Contributors: Sergei Gavrikov (w3sg@SoftHome.net)
47 * Lars Povlsen (lpovlsen@vitesse.com)
52 * ####DESCRIPTIONEND####
54 * =================================================================
57 #include <pkgconf/hal.h>
58 #include <pkgconf/kernel.h>
59 #include <cyg/kernel/kapi.h> // Kernel API.
60 #include <cyg/infra/diag.h> // For diagnostic printing.
64 #include <cyg/hal/hal_tables.h>
65 #include <cyg/fileio/fileio.h>
66 #include <stdio.h> // sprintf().
69 #ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER
70 #include <cyg/objloader/elf.h>
71 #include <cyg/objloader/objelf.h>
74 #include <cyg/athttpd/http.h>
75 #include <cyg/athttpd/socket.h>
76 #include <cyg/athttpd/handler.h>
77 #include <cyg/athttpd/forms.h>
79 cyg_int32 debug_print = 0;
81 const char *day_of_week[7] = {"Sun", "Mon", "Tue", "Wed",
83 const char *month_of_year[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
84 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
85 const char *home_pages[] = {"index.html", "index.htm",
86 "default.html", "home.html"};
87 CYG_HAL_TABLE_BEGIN(cyg_httpd_mime_table, httpd_mime_table);
88 CYG_HAL_TABLE_END(cyg_httpd_mime_table_end, httpd_mime_table);
90 __externC cyg_httpd_mime_table_entry cyg_httpd_mime_table[];
91 __externC cyg_httpd_mime_table_entry cyg_httpd_mime_table_end[];
93 // Standard handlers added by default. Correspond to the most used extensions.
94 // The user can add his/her own later.
95 CYG_HTTPD_MIME_TABLE_ENTRY(hal_htm_entry, "htm",
96 "text/html; charset=iso-8859-1");
97 CYG_HTTPD_MIME_TABLE_ENTRY(hal_html_entry, "html",
98 "text/html; charset=iso-8859-1");
99 CYG_HTTPD_MIME_TABLE_ENTRY(hal_gif_entry, "gif", "image/gif");
100 CYG_HTTPD_MIME_TABLE_ENTRY(hal_jpg_entry, "jpg", "image/jpg");
101 CYG_HTTPD_MIME_TABLE_ENTRY(hal_png_entry, "png", "image/png");
102 CYG_HTTPD_MIME_TABLE_ENTRY(hal_css_entry, "css", "text/css");
103 CYG_HTTPD_MIME_TABLE_ENTRY(hal_js_entry, "js", "application/x-javascript");
106 cyg_httpd_send_error(cyg_int32 err_type)
108 httpstate.status_code = err_type;
110 // Errors pages close the socket and are never cached.
111 httpstate.mode |= CYG_HTTPD_MODE_NO_CACHE;
113 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
114 diag_printf("Sending error: %d\n", err_type);
117 #ifdef CYGOPT_NET_ATHTTPD_USE_FS
118 // Check if the user has defines his own error pages.
120 char file_name[CYG_HTTPD_MAXPATH];
121 strcpy(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR);
122 if (file_name[strlen(file_name)-1] != '/')
123 strcat(file_name, "/");
124 strcat(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ERRORDIR);
125 if (file_name[strlen(file_name)-1] != '/')
126 strcat(file_name, "/");
127 sprintf(file_name + strlen(file_name), "error_%d.html", err_type);
128 cyg_httpd_cleanup_filename(file_name);
129 cyg_int32 rc = stat(file_name, &sp);
132 char *extension = rindex(file_name, '.');
133 if (extension == NULL)
134 // No extension in the file name.
135 httpstate.mime_type = 0;
137 httpstate.mime_type = cyg_httpd_find_mime_string(++extension);
139 httpstate.payload_len = sp.st_size;
140 cyg_int32 header_length = cyg_httpd_format_header();
141 cyg_httpd_write(httpstate.outbuffer, header_length);
144 FILE *fp = fopen(file_name, "r");
148 ssize_t payload_size = fread(httpstate.outbuffer,
150 CYG_HTTPD_MAXOUTBUFFER,
152 while (payload_size > 0)
154 ssize_t bytes_written = cyg_httpd_write_chunked(httpstate.outbuffer,
156 if (bytes_written != payload_size)
159 payload_size = fread(httpstate.outbuffer,
161 CYG_HTTPD_MAXOUTBUFFER,
170 // Because the size of the frame is not known upfront (every error message
171 // is different and thus has different length) we use chunked frames to
172 // send the message out.
173 #if defined(CYGOPT_NET_ATHTTPD_CLOSE_CHUNKED_CONNECTIONS)
174 httpstate.mode |= CYG_HTTPD_MODE_CLOSE_CONN;
177 httpstate.mode |= CYG_HTTPD_MODE_TRANSFER_CHUNKED;
178 httpstate.status_code = err_type;
179 httpstate.last_modified = -1;
180 httpstate.mime_type = "text/html";
181 cyg_int32 header_length = cyg_httpd_format_header();
182 cyg_httpd_write(httpstate.outbuffer, header_length);
184 // If no file has been defined, send a simple notification. We must use
185 // chunked frames, because we do not know upfron the length of the
186 // packet we have to send.
187 strcpy(httpstate.outbuffer,
188 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n");
191 case CYG_HTTPD_STATUS_MOVED_PERMANENTLY:
192 strcat(httpstate.outbuffer,
193 "<html><head><title>301 Moved Permanently</title></head>\r\n"
194 "<body><h1>Moved Permanently</h1>\r\n"
195 "<p>The document has moved <a href=\"");
196 strcat(httpstate.outbuffer, httpstate.url);
197 strcat(httpstate.outbuffer, "\">here</a>.\r\n");
199 case CYG_HTTPD_STATUS_MOVED_TEMPORARILY:
200 strcat(httpstate.outbuffer,
201 "<html><head><title>302 Found</title></head>\r\n"
202 "<body><h1>Redirect</h1>\r\n"
203 "<p>Please continue <a href=\"");
204 strcat(httpstate.outbuffer, httpstate.url);
205 strcat(httpstate.outbuffer, "\">here</a>.\r\n");
207 case CYG_HTTPD_STATUS_NOT_AUTHORIZED:
208 strcat(httpstate.outbuffer,
209 "<html><head><title>401 Not Authorized</title></head>\r\n");
210 strcat(httpstate.outbuffer,
211 "<body><p>Authorization required to access this URL.</p>\r\n");
213 case CYG_HTTPD_STATUS_NOT_MODIFIED:
214 cyg_httpd_end_chunked();
216 case CYG_HTTPD_STATUS_NOT_FOUND:
217 strcat(httpstate.outbuffer,
218 "<html><head><title>404 Not Found</title></head>\r\n");
219 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
220 "<p>The requested URL: %s was not found on this server</p>\r\n",
223 case CYG_HTTPD_STATUS_SYSTEM_ERROR:
224 strcat(httpstate.outbuffer,
225 "<html><head><title>500 Server Error</title></head>\r\n");
226 strcat(httpstate.outbuffer,
227 "<p>The server encountered an unexpected condition that "
228 "prevented it from fulfilling the request"
229 " by the client</p>\r\n");
231 case CYG_HTTPD_STATUS_NOT_IMPLEMENTED:
232 strcat(httpstate.outbuffer,
233 "<html><head><title>501 Not Implemented</title></head>\r\n");
234 strcat(httpstate.outbuffer,
235 "<p>The method requested is not implemented</p>\r\n");
238 strcat(httpstate.outbuffer,
239 "<html><head><title>400 Bad Request</title></head>\r\n");
240 strcat(httpstate.outbuffer,
241 "<p>Bad request</p>\r\n");
245 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
246 "<hr>%s at %d.%d.%d.%d Port %d\r\n</body></html>\r\n",
247 CYGDAT_NET_ATHTTPD_SERVEROPT_SERVERID,
252 CYGNUM_NET_ATHTTPD_SERVEROPT_PORT);
254 cyg_httpd_write_chunked(httpstate.outbuffer, strlen(httpstate.outbuffer));
255 cyg_httpd_end_chunked();
258 // Return a time_t that is always UTC (aka GMT).
260 cyg_httpd_parse_date(char *time)
266 // We are going to get rid of the day of the week. This is always the first
267 // part of the string, separated by a blank.
268 time = strchr( time, ' ');
273 /// RFC1123. The date is in the format: Sun, 06 Nov 1994 08:49:37 GMT.
274 cyg_int32 rc = sscanf(time,
275 "%2d %3s %4d %2d:%2d:%2d GMT",
284 // RFC1036. The date is in the format: Sunday, 06-Nov-94 08:49:37 GMT.
286 "%2d-%3s-%2d %2d:%2d:%2d GMT",
296 rc = sscanf(time,"%3s %2d %2d:%2d:%2d %4d",
308 for (i = 0; i < sizeof(month_of_year); i++)
309 if (strcmp(month, month_of_year[i]) == 0)
312 if (tm_mod.tm_year > 1900)
313 tm_mod.tm_year -= 1900;
314 return mktime(&tm_mod);
320 // Finds the mime string into the mime_table associated with a specific
321 // extension. Returns the MIME type to send in the header, or NULL if the
322 // extension is not in the table.
324 cyg_httpd_find_mime_string(char *ext)
326 cyg_httpd_mime_table_entry *entry = cyg_httpd_mime_table;
328 while (entry != cyg_httpd_mime_table_end)
330 if (!strcmp((const char*)ext, entry->extension))
331 return entry->mime_string;
339 cyg_httpd_cleanup_filename(char *filename)
341 char *src = strstr(filename, "//");
344 strcpy(src + 1, src + 2);
345 src = strstr(filename, "//");
348 src = strstr(filename, "/./");
351 strcpy(src + 1, src + 3);
352 src = strstr(filename, "/./");
355 src = strstr(filename, "/../");
358 char *comp1 = filename, *comp2 = filename;
360 // Search the path component before this redirection.
361 while ((comp1 = strchr(comp1, '/')) != src)
364 strcpy(comp2, src + 4);
365 src = strstr(filename, "/../");
370 cyg_httpd_initialize(void)
372 httpstate.post_data = NULL;
373 httpstate.needs_auth = (cyg_httpd_auth_table_entry *)0;
378 cyg_httpd_append_homepage(char *root)
380 #ifdef CYGOPT_NET_ATHTTPD_USE_FS
384 cyg_int32 root_len = strlen(root);
385 for (i = 0; i < sizeof(home_pages)/sizeof(char*); i++)
387 root[root_len] = '\0';
388 sprintf(root + root_len, "%s", home_pages[i]);
389 cyg_int32 rc = stat(root, &sp);
396 #ifdef CYGDAT_NET_ATHTTPD_ALTERNATE_HOME
397 if (strcmp(root, "/") == 0)
398 // The client is trying to open the main index file.
399 strcat(root, CYGDAT_NET_ATHTTPD_ALTERNATE_HOME);
403 #ifdef CYGOPT_NET_ATHTTPD_USE_FS
405 cyg_httpd_send_file(char *name)
410 char file_name[CYG_HTTPD_MAXPATH];
412 strcpy(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR);
413 if (file_name[strlen(file_name)-1] != '/')
414 strcat(file_name, "/");
415 strcat(file_name, name);
416 cyg_httpd_cleanup_filename(file_name);
418 // Check if the file is in the file system. This will also give us the
419 // size of the file, to be used in the HTTP header.
420 cyg_int32 rc = stat(file_name, &sp);
423 // Before giving up, we make a last ditch attempt at finding a file
424 // within the internal resources of the server. The user can add
425 // his/her own files to the table.
426 cyg_httpd_ires_table_entry *p = cyg_httpd_find_ires(name);
429 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
430 diag_printf("Sending Internal Resource: %s\n", name);
432 cyg_httpd_send_ires(p);
435 cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
439 if (S_ISDIR(sp.st_mode))
441 char tmp_url[CYG_HTTPD_MAXURL];
442 strcpy(tmp_url, httpstate.url);
443 // Directories need a trialing slash, and if missing, we'll redirect
444 // the client to the right URL. This is called (appropriately
445 // enough) "Trailing-Slash Redirection".
446 if (name[strlen(name)-1] != '/')
448 sprintf(httpstate.url,
449 "http://%d.%d.%d.%d:%d%s/",
454 CYGNUM_NET_ATHTTPD_SERVEROPT_PORT,
456 cyg_httpd_send_error(CYG_HTTPD_STATUS_MOVED_PERMANENTLY);
460 // We are going to try to locate an index page in the directory we got
462 cyg_httpd_append_homepage(file_name);
463 if (file_name[strlen(file_name)-1] == '/')
465 #ifdef CYGOPT_NET_ATHTTPD_USE_DIRLIST
466 // No home page found, we are sending a directory listing.
467 cyg_httpd_send_directory_listing(name);
469 cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
473 stat(file_name, &sp);
476 httpstate.last_modified = sp.st_mtime;
478 // Let's see if we luck out and can send a 304.
479 if ((httpstate.modified_since != -1) &&
480 (httpstate.modified_since >= httpstate.last_modified))
482 cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_MODIFIED);
486 httpstate.status_code = CYG_HTTPD_STATUS_OK;
488 // Here we'll look for an extension to the file. Consider the case where
489 // there might be more than one dot in the file name. We'll look for just
490 // the last one, then we'll check the extension.
491 char *extension = rindex(file_name, '.');
492 if (extension == NULL)
493 httpstate.mime_type = 0;
495 httpstate.mime_type = cyg_httpd_find_mime_string(++extension);
497 httpstate.payload_len = sp.st_size;
498 httpstate.mode &= ~CYG_HTTPD_MODE_NO_CACHE;
499 cyg_int32 payload_size = cyg_httpd_format_header();
500 if ((httpstate.mode & CYG_HTTPD_MODE_SEND_HEADER_ONLY) != 0)
502 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
503 diag_printf("Sending header only for URL: %s\n", file_name);
505 send(httpstate.sockets[httpstate.client_index].descriptor,
512 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
513 diag_printf("Sending file: %s\n", file_name);
515 fp = fopen(file_name, "r");
518 // We should really read errno and send messages accordingly...
519 cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
523 // Fill up the rest of the buffer and send it out.
524 cyg_int32 bread = fread(httpstate.outbuffer + strlen(httpstate.outbuffer),
526 CYG_HTTPD_MAXOUTBUFFER - payload_size,
528 cyg_httpd_write(httpstate.outbuffer, payload_size + bread);
530 ssize_t bytes_written = 0;
532 while (bytes_written < sp.st_size)
534 bread = fread(httpstate.outbuffer, 1, CYG_HTTPD_MAXOUTBUFFER, fp);
535 bytes_written += cyg_httpd_write(httpstate.outbuffer, bread);
540 cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
545 cyg_httpd_format_header(void)
547 sprintf(httpstate.outbuffer, "HTTP/1.1 %d", httpstate.status_code);
548 time_t time_val = time(NULL);
550 // Error messages (i.e. with status other than OK, automatically add
551 // the no-cache header.
552 switch (httpstate.status_code)
554 case CYG_HTTPD_STATUS_MOVED_PERMANENTLY:
555 strcat(httpstate.outbuffer, " Moved Permanently\r\n");
556 strcat(httpstate.outbuffer, "Location: ");
557 strcat(httpstate.outbuffer, httpstate.url);
558 strcat(httpstate.outbuffer, "\r\n");
559 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
560 "Content-Length: %d\r\n",
561 httpstate.payload_len);
563 case CYG_HTTPD_STATUS_MOVED_TEMPORARILY:
564 strcat(httpstate.outbuffer, " Found\r\n");
565 strcat(httpstate.outbuffer, "Location: ");
566 strcat(httpstate.outbuffer, httpstate.url);
567 strcat(httpstate.outbuffer, "\r\n");
568 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
569 "Content-Length: %d\r\n",
570 httpstate.payload_len);
572 #ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
573 case CYG_HTTPD_STATUS_NOT_AUTHORIZED:
574 // A 401 error closes the connection right away.
575 httpstate.mode |= CYG_HTTPD_MODE_CLOSE_CONN;
576 strcat(httpstate.outbuffer, " Not Authorized\r\n");
578 // Here we should set the proper header based on the authentication
579 // required (httpstate.needs_authMode) but for now, with only
580 // Basic Authentication supported, there is no need to do so.
581 if (httpstate.needs_auth->auth_mode == CYG_HTTPD_AUTH_BASIC)
583 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
584 "WWW-Authenticate: Basic realm=\"%s\"\r\n",
585 httpstate.needs_auth->auth_domainname);
589 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
590 "WWW-Authenticate: Digest realm=\"%s\", ",
591 httpstate.needs_auth->auth_domainname);
592 strftime(cyg_httpd_md5_nonce,
596 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
597 "nonce=\"%s\", ", cyg_httpd_md5_nonce);
598 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
600 CYG_HTTPD_MD5_AUTH_OPAQUE);
601 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
602 "stale=false, algorithm=%s, qop=\"%s\"\r\n",
603 CYG_HTTPD_MD5_AUTH_NAME,
604 CYG_HTTPD_MD5_AUTH_QOP);
608 case CYG_HTTPD_STATUS_NOT_MODIFIED:
609 strcat(httpstate.outbuffer, " Not Modified\r\n");
611 case CYG_HTTPD_STATUS_NOT_FOUND:
612 strcat(httpstate.outbuffer, " Not Found\r\n");
613 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
614 "Content-Length: %d\r\n",
615 httpstate.payload_len);
617 case CYG_HTTPD_STATUS_METHOD_NOT_ALLOWED:
618 strcat(httpstate.outbuffer, " Method Not Allowed\r\n");
621 strcat(httpstate.outbuffer, " OK\r\n");
622 if ((httpstate.mode & CYG_HTTPD_MODE_TRANSFER_CHUNKED) == 0)
623 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
624 "Content-Length: %d\r\n",
625 httpstate.payload_len);
629 strcat(httpstate.outbuffer, "Date: ");
630 strftime(httpstate.outbuffer + strlen(httpstate.outbuffer),
631 CYG_HTTPD_MAXOUTBUFFER - strlen(httpstate.outbuffer),
634 strcat(httpstate.outbuffer, "\r\n");
636 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
638 CYGDAT_NET_ATHTTPD_SERVEROPT_SERVERID);
640 if (httpstate.mode & CYG_HTTPD_MODE_CLOSE_CONN)
641 strcat(httpstate.outbuffer, "Connection: close\r\n");
643 strcat(httpstate.outbuffer, "Connection: keep-alive\r\n");
645 // When we cannot find the appropriate MIME type, we'll send a default type.
646 if (httpstate.mime_type == 0)
647 httpstate.mime_type = CYGDAT_NET_ATHTTPD_DEFAULT_MIME_TYPE;
648 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
649 "Content-Type: %s\r\n",
650 httpstate.mime_type);
652 if (httpstate.mode & CYG_HTTPD_MODE_TRANSFER_CHUNKED)
653 strcat(httpstate.outbuffer, "Transfer-Encoding: chunked\r\n");
655 if (httpstate.mode & CYG_HTTPD_MODE_NO_CACHE)
656 strcat(httpstate.outbuffer, "Cache-Control: no-cache\r\n");
658 if (httpstate.last_modified != -1)
660 time_val = httpstate.last_modified;
661 strcat(httpstate.outbuffer, "Last-Modified: ");
662 strftime(httpstate.outbuffer + strlen(httpstate.outbuffer),
663 CYG_HTTPD_MAXOUTBUFFER - strlen(httpstate.outbuffer),
666 strcat(httpstate.outbuffer, "\r\n");
668 #if (CYGOPT_NET_ATHTTPD_DOCUMENT_EXPIRATION_TIME != 0)
669 time_val += CYGOPT_NET_ATHTTPD_DOCUMENT_EXPIRATION_TIME;
670 strcat(httpstate.outbuffer, "Expires: ");
671 strftime(httpstate.outbuffer + strlen(httpstate.outbuffer),
672 CYG_HTTPD_MAXOUTBUFFER - strlen(httpstate.outbuffer),
675 strcat(httpstate.outbuffer, "\r\n");
679 // There must be 2 carriage returns between the header and the body,
680 // so if you modify this function make sure that there is another
681 // CRLF already terminating the buffer thus far.
682 strcat(httpstate.outbuffer, "\r\n");
683 return strlen(httpstate.outbuffer);
687 cyg_httpd_handle_method_GET(void)
689 #if defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER) ||\
690 defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL)
691 // If the URL is a CGI script, there is a different directory...
692 if (httpstate.url[0] == '/' &&
693 !strncmp(httpstate.url + 1,
694 CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR,
695 strlen(CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR)))
697 cyg_httpd_exec_cgi();
700 // If the OBJLOADER package is not loaded, then the request for a library
701 // will likely generate a 404.
704 // User defined handlers take precedence over other forms of response.
705 handler h = cyg_httpd_find_handler();
713 #ifdef CYGOPT_NET_ATHTTPD_USE_FS
714 // No handler, we'll redirect to the file system.
715 cyg_httpd_send_file(httpstate.url);
717 // If we do not have a file system, we look for the file within the
718 // internal resources of the server. The user can add his/her own files
720 if (strcmp(httpstate.url, "/") == 0)
723 cyg_httpd_ires_table_entry *p;
724 for (i = 0; i < sizeof(home_pages)/sizeof(char*); i++)
726 httpstate.url[1] = '\0';
727 strcat(httpstate.url, home_pages[i]);
728 p = cyg_httpd_find_ires(httpstate.url);
731 cyg_httpd_send_ires(p);
738 cyg_httpd_ires_table_entry *p = cyg_httpd_find_ires(httpstate.url);
741 cyg_httpd_send_ires(p);
745 cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
750 cyg_httpd_get_URL(char* p)
752 char* dest = httpstate.url;
754 // First get rid of multiple leading slashes.
755 while ((p[0] == '/') && (p[1] == '/'))
758 // Store the url, and check if there is a form result in it.
759 while ((*p != ' ') && (*p != '?') &&
760 ((dest - httpstate.url) <= CYG_HTTPD_MAXURL))
762 // Look for encoded characters in the URL.
766 cyg_int8 ch = cyg_httpd_from_hex(*p++);
769 cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
773 ch = cyg_httpd_from_hex(*p++);
776 cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
786 // Terminate the file name...
789 // The URL must start with a leading slash.
790 if (httpstate.url[0] != '/')
792 cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
799 cyg_httpd_parse_POST(char* p)
801 httpstate.method = CYG_HTTPD_METHOD_POST;
802 char *cp = cyg_httpd_get_URL(p);
805 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
806 diag_printf("POST Request URL: %s\n", httpstate.url);
809 while (*cp++ != '\n');
814 cyg_httpd_parse_GET(char* p)
816 char *cp = cyg_httpd_get_URL(p);
819 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
820 if ( httpstate.method == CYG_HTTPD_METHOD_GET)
821 diag_printf("GET Request URL: %s\n", httpstate.url);
823 diag_printf("HEAD Request URL: %s\n", httpstate.url);
827 // If we have a GET header with form variables we'll get the
828 // variables out of it and store them in the variable table.
829 // Can we assume that HEAD request can have form variables?
830 // That will be a yes until I learn otherwise.
831 cp = cyg_httpd_store_form_data(++cp);
833 // Run to end of line.
834 while (*cp++ != '\n');
839 cyg_httpd_process_header(char *p)
841 #ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
842 // Clear the previous request's response. The client properly authenticated
843 // will always reinitialize this variable during the header parsing
844 // process. This variable is also commandeered to hold the hashed
845 // username:password duo in the basic authentication.
846 cyg_httpd_md5_response[0] = '\0';
849 // The deafult for HTTP 1.1 is keep-alive connections, unless specifically
850 // closed by the far end.
851 httpstate.mode &= ~(CYG_HTTPD_MODE_CLOSE_CONN | CYG_HTTPD_MODE_FORM_DATA |\
852 CYG_HTTPD_MODE_SEND_HEADER_ONLY);
853 httpstate.modified_since = -1;
854 httpstate.content_len = 0;
855 while (p < httpstate.request_end)
857 if (strncasecmp("GET ", p, 4) == 0)
859 // We need separate flags for HEAD and SEND_HEADERS_ONLY since
860 // we can send a header only even in the case of a GET request
861 // (as a 304 response.)
862 httpstate.method = CYG_HTTPD_METHOD_GET;
863 httpstate.mode &= ~CYG_HTTPD_MODE_SEND_HEADER_ONLY;
864 p = cyg_httpd_parse_GET(p + 4);
868 else if (strncasecmp("POST ", p, 5) == 0)
870 p = cyg_httpd_parse_POST(p + 5);
874 else if (strncasecmp("HEAD ", p, 5) == 0)
876 httpstate.method = CYG_HTTPD_METHOD_HEAD;
877 httpstate.mode |= CYG_HTTPD_MODE_SEND_HEADER_ONLY;
878 p = cyg_httpd_parse_GET(p + 5);
882 else if (strncasecmp(p, "Content-Length: ", 16) == 0)
884 p = strchr(p, ':') + 2;
886 // In the case of a POST request, this is the total length of
887 // the payload, which might be spread across several frames.
888 httpstate.content_len = atoi(p);
889 while (*p++ != '\n');
891 else if (strncasecmp(p, "Content-Type: ", 14) == 0)
893 p = strchr(p, ':') + 2;
895 // In the case of a POST request, this is the total length of
896 // the payload, which might be spread across several frames.
898 "application/x-www-form-urlencoded",
900 httpstate.mode |= CYG_HTTPD_MODE_FORM_DATA;
901 while (*p++ != '\n');
903 else if (strncasecmp("Host:", p, 5) == 0)
914 while (*p++ != '\n');
916 else if (strncasecmp("If-Modified-Since:", p, 18) == 0)
921 httpstate.modified_since = cyg_httpd_parse_date(p);
922 while (*p++ != '\n');
924 #ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
925 else if (strncasecmp("Authorization:", p, 14) == 0)
930 if (strncasecmp("Basic", p, 5) == 0)
935 cyg_int32 auth_data_length = 0;
938 // We are going to copy only up to
939 // AUTH_STORAGE_BUFFER_LENGTH characters to prevent
940 // overflow of the cyg_httpd_md5_response variable.
941 if (auth_data_length < AUTH_STORAGE_BUFFER_LENGTH)
942 if ((*p != '\r') && (*p != ' '))
943 cyg_httpd_md5_response[auth_data_length++] = *p;
947 cyg_httpd_md5_response[auth_data_length] = '\0';
949 else if (strncasecmp(p, "Digest", 6) == 0)
956 if (strncasecmp(p, "realm=", 6) == 0)
957 p = cyg_httpd_digest_skip(p + 6);
958 else if (strncasecmp(p, "username=", 9) == 0)
959 p = cyg_httpd_digest_skip(p + 9);
960 else if (strncasecmp(p, "nonce=", 6) == 0)
961 p = cyg_httpd_digest_skip(p + 6);
962 else if (strncasecmp(p, "response=", 9) == 0)
963 p = cyg_httpd_digest_data(cyg_httpd_md5_response,
965 else if (strncasecmp(p, "cnonce=", 7) == 0)
966 p = cyg_httpd_digest_data(cyg_httpd_md5_cnonce, p + 7);
967 else if (strncasecmp(p, "qop=", 4) == 0)
968 p = cyg_httpd_digest_skip(p + 4);
969 else if (strncasecmp(p, "nc=", 3) == 0)
970 p = cyg_httpd_digest_data(cyg_httpd_md5_noncecount,
972 else if (strncasecmp(p, "algorithm=", 10) == 0)
973 p = cyg_httpd_digest_skip(p + 10);
974 else if (strncasecmp(p, "opaque=", 7) == 0)
975 p = cyg_httpd_digest_skip(p + 7);
976 else if (strncasecmp(p, "uri=", 4) == 0)
977 p = cyg_httpd_digest_skip(p + 4);
984 while (*p++ != '\n');
986 #endif // CYGOPT_NET_ATHTTPD_USE_AUTH
987 else if (strncasecmp(p, "Connection:", 11) == 0)
992 if (strncasecmp(p, "close", 5) == 0)
993 httpstate.mode |= CYG_HTTPD_MODE_CLOSE_CONN;
994 while (*p++ != '\n');
997 // We'll just dump the rest of the line and move on to the next.
998 while (*p++ != '\n');
1004 cyg_httpd_process_method(void)
1006 char* p = httpstate.inbuffer;
1008 // Some browsers send an extra '\r\n' after the POST data that is not
1009 // accounted in the "Content-Length:" field. We are going to junk all
1010 // the leading returns and line carriages we find.
1011 while ((*p == '\r') || (*p =='\n'))
1016 p = cyg_httpd_process_header(p);
1020 #ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
1021 // Let's check that the requested URL is not inside some directory that
1022 // needs authentication.
1023 cyg_httpd_auth_table_entry* auth =
1024 cyg_httpd_is_authenticated(httpstate.url);
1027 cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_AUTHORIZED);
1031 switch (httpstate.method)
1033 case CYG_HTTPD_METHOD_GET:
1034 case CYG_HTTPD_METHOD_HEAD:
1035 cyg_httpd_handle_method_GET();
1037 case CYG_HTTPD_METHOD_POST:
1038 cyg_httpd_handle_method_POST();
1042 cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_IMPLEMENTED);