Mercurial > ecos
annotate packages/net/httpd/current/src/httpd.c @ 1240:eeb14eae974b
* src/httpd.c (cyg_httpd_server): Removed unused variable.
* doc/httpd.sgml: Updated documentation for previous change.
* include/httpd.h: changed prototype of cyg_httpd_send_html and
cyg_httpd_send_data to match implementation.
| author | asl |
|---|---|
| date | Tue, 23 Sep 2003 11:40:14 +0000 |
| parents | 657f409c5dfe |
| children | 970d06598f83 |
| rev | line source |
|---|---|
| 468 | 1 /* ================================================================= |
| 2 * | |
| 3 * httpd.c | |
| 4 * | |
| 5 * A simple embedded HTTP server | |
| 6 * | |
| 7 * ================================================================= | |
| 8 * ####ECOSGPLCOPYRIGHTBEGIN#### | |
| 9 * ------------------------------------------- | |
| 10 * This file is part of eCos, the Embedded Configurable Operating | |
| 11 * System. | |
| 12 * Copyright (C) 2002 Nick Garnett. | |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
13 * Copyright (C) 2003 Andrew Lunn. |
| 468 | 14 * |
| 15 * eCos is free software; you can redistribute it and/or modify it | |
| 16 * under the terms of the GNU General Public License as published by | |
| 17 * the Free Software Foundation; either version 2 or (at your option) | |
| 18 * any later version. | |
| 19 * | |
| 20 * eCos is distributed in the hope that it will be useful, but | |
| 21 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 23 * General Public License for more details. | |
| 24 * | |
| 25 * You should have received a copy of the GNU General Public License | |
| 26 * along with eCos; if not, write to the Free Software Foundation, | |
| 27 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
| 28 * | |
| 29 * As a special exception, if other files instantiate templates or | |
| 30 * use macros or inline functions from this file, or you compile this | |
| 31 * file and link it with other works to produce a work based on this | |
| 32 * file, this file does not by itself cause the resulting work to be | |
| 33 * covered by the GNU General Public License. However the source code | |
| 34 * for this file must still be made available in accordance with | |
| 35 * section (3) of the GNU General Public License. | |
| 36 * | |
| 37 * This exception does not invalidate any other reasons why a work | |
| 38 * based on this file might be covered by the GNU General Public | |
| 39 * License. | |
| 40 * | |
| 41 * ------------------------------------------- | |
| 42 * ####ECOSGPLCOPYRIGHTEND#### | |
| 43 * ================================================================= | |
| 44 * #####DESCRIPTIONBEGIN#### | |
| 45 * | |
| 46 * Author(s): nickg@calivar.com | |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
47 * Contributors: nickg@calivar.com, Andrew.lunn@ascom.ch |
| 468 | 48 * Date: 2002-10-14 |
| 49 * Purpose: | |
| 50 * Description: | |
| 51 * | |
| 52 * ####DESCRIPTIONEND#### | |
| 53 * | |
| 54 * ================================================================= | |
| 55 */ | |
| 56 | |
| 57 #include <pkgconf/system.h> | |
| 58 #include <pkgconf/isoinfra.h> | |
| 59 #include <pkgconf/httpd.h> | |
| 60 | |
| 61 #include <cyg/infra/cyg_trac.h> /* tracing macros */ | |
| 62 #include <cyg/infra/cyg_ass.h> /* assertion macros */ | |
| 63 | |
| 64 #include <unistd.h> | |
| 65 #include <fcntl.h> | |
| 66 #include <sys/stat.h> | |
| 67 #include <stdio.h> | |
| 68 #include <errno.h> | |
| 69 #include <string.h> | |
| 70 | |
| 71 #include <network.h> | |
| 72 #include <arpa/inet.h> | |
| 73 | |
| 74 #include <cyg/httpd/httpd.h> | |
| 75 | |
| 76 /* ================================================================= */ | |
| 77 | |
| 78 #if 0 | |
| 79 #define HTTPD_DIAG diag_printf | |
| 80 #else | |
| 81 #define HTTPD_DIAG(...) | |
| 82 #endif | |
| 83 | |
| 84 /* ================================================================= */ | |
| 85 /* Server socket address and file descriptor. | |
| 86 */ | |
| 87 | |
| 88 static struct sockaddr_in server_address; | |
| 89 | |
| 90 static int server_socket = -1; | |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
91 #ifdef CYGPKG_NET_INET6 |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
92 static int server_socket6 = -1; |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
93 static struct sockaddr_in6 server_address6; |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
94 #endif |
| 468 | 95 |
| 96 /* ================================================================= */ | |
| 97 /* Thread stacks, etc. | |
| 98 */ | |
| 99 | |
| 100 static cyg_uint8 httpd_stacks[CYGNUM_HTTPD_THREAD_COUNT] | |
| 101 [CYGNUM_HAL_STACK_SIZE_MINIMUM+ | |
| 102 CYGNUM_HTTPD_SERVER_BUFFER_SIZE+ | |
| 103 CYGNUM_HTTPD_THREAD_STACK_SIZE]; | |
| 104 | |
| 105 static cyg_handle_t httpd_thread[CYGNUM_HTTPD_THREAD_COUNT]; | |
| 106 | |
| 107 static cyg_thread httpd_thread_object[CYGNUM_HTTPD_THREAD_COUNT]; | |
| 108 | |
| 109 /* ================================================================= */ | |
| 110 /* Filename lookup table | |
| 111 */ | |
| 112 | |
| 113 CYG_HAL_TABLE_BEGIN( cyg_httpd_table, httpd_table ); | |
| 114 CYG_HAL_TABLE_END( cyg_httpd_table_end, httpd_table ); | |
| 115 | |
| 116 __externC cyg_httpd_table_entry cyg_httpd_table[]; | |
| 117 __externC cyg_httpd_table_entry cyg_httpd_table_end[]; | |
| 118 | |
| 119 /* ================================================================= */ | |
| 120 /* Page not found message | |
| 121 */ | |
| 122 | |
| 123 static char cyg_httpd_not_found[] = | |
| 124 "<head><title>Page Not found</title></head>\n" | |
| 125 "<body><h2>The requested URL was not found on this server.</h2></body>\n"; | |
| 126 | |
| 127 /* ================================================================= */ | |
| 128 /* Simple pattern matcher for filenames | |
| 129 * | |
| 130 * This performs a simple pattern match between the given name and the | |
| 131 * pattern. At present the only matching supported is either exact, or | |
| 132 * if the pattern ends in * then that matches all remaining | |
| 133 * characters. At some point we might want to implement a more | |
| 134 * complete regular expression parser here. | |
| 135 */ | |
| 136 | |
| 137 static cyg_bool match( char *name, char *pattern ) | |
| 138 { | |
| 139 while( *name != 0 && *pattern != 0 && *name == *pattern ) | |
| 140 name++, pattern++; | |
| 141 | |
| 142 if( *name == 0 && *pattern == 0 ) | |
| 143 return true; | |
| 144 | |
| 145 if( *pattern == '*' ) | |
| 146 return true; | |
| 147 | |
| 148 return false; | |
| 149 } | |
| 150 | |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
151 |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
152 /* ================================================================= */ |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
153 /* Main processing function */ |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
154 /* */ |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
155 /* Reads the HTTP header, look it up in the table and calls the */ |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
156 /* handler. */ |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
157 |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
158 static void cyg_httpd_process( int client_socket, struct sockaddr *client_address ) |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
159 { |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
160 int calen = sizeof(*client_address); |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
161 int nlc = 0; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
162 char request[CYGNUM_HTTPD_SERVER_BUFFER_SIZE]; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
163 FILE *client; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
164 cyg_httpd_table_entry *entry = cyg_httpd_table; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
165 char *filename; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
166 char *formdata = NULL; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
167 char *p; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
168 cyg_bool success = false; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
169 char name[64]; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
170 char port[10]; |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
171 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
172 getnameinfo(client_address, calen, name, sizeof(name), |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
173 port, sizeof(port), NI_NUMERICHOST|NI_NUMERICSERV); |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
174 HTTPD_DIAG("Connection from %s[%s]\n",name,port); |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
175 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
176 /* Convert the file descriptor to a C library FILE object so |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
177 * we can use fprintf() and friends on it. |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
178 */ |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
179 client = fdopen( client_socket, "r+"); |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
180 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
181 /* We are really only interested in the first line. |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
182 */ |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
183 fgets( request, sizeof(request), client ); |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
184 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
185 HTTPD_DIAG("Request >%s<\n", request ); |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
186 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
187 /* Absorb the rest of the header. We nibble it away a |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
188 * character at a time like this to avoid having to define |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
189 * another buffer to read lines into. If we ever need to take |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
190 * more interest in the header fields, we will need to be a |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
191 * lot more sophisticated than this. |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
192 */ |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
193 do{ |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
194 int c = getc( client ); |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
195 HTTPD_DIAG("%c",c); |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
196 if( c == '\n' ) |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
197 nlc++; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
198 else if( c != '\r' ) |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
199 nlc = 0; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
200 } while(nlc < 2); |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
201 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
202 /* Extract the filename and any form data being returned. |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
203 * We know that the "GET " request takes 4 bytes. |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
204 * TODO: handle POST type requests as well as GET's. |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
205 */ |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
206 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
207 filename = p = request+4; |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
208 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
209 /* Now scan the filename until we hit a space or a '?'. If we |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
210 * end on a '?' then the rest is a form request. Put NULs at |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
211 * the end of each string. |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
212 */ |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
213 while( *p != ' ' && *p != '?' ) |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
214 p++; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
215 if( *p == '?' ) |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
216 formdata = p+1; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
217 *p = 0; |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
218 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
219 if( formdata != NULL ) |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
220 { |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
221 while( *p != ' ' ) |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
222 p++; |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
223 *p = 0; |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
224 } |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
225 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
226 HTTPD_DIAG("Request filename >%s< formdata >%s<\n",filename,formdata?formdata:"-NULL-"); |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
227 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
228 HTTPD_DIAG("table: %08x...%08x\n",cyg_httpd_table, cyg_httpd_table_end); |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
229 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
230 /* Now scan the table for a matching entry. If we find one |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
231 * call the handler routine. If that returns true then we |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
232 * terminate the scan, otherwise we keep looking. |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
233 */ |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
234 while( entry != cyg_httpd_table_end ) |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
235 { |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
236 HTTPD_DIAG("try %08x: %s\n", entry, entry->pattern); |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
237 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
238 if( match( filename, entry->pattern ) ) |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
239 { |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
240 if( (success = entry->handler( client, filename, formdata, entry->arg )) ) |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
241 break; |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
242 } |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
243 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
244 entry++; |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
245 } |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
246 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
247 /* If we failed to find a match in the table, send a "not |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
248 * found" response. |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
249 * TODO: add an optional fallback to go look for files in |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
250 * some filesystem, somewhere. |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
251 */ |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
252 if( !success ) |
|
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
253 cyg_httpd_send_html( client, NULL, NULL, cyg_httpd_not_found ); |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
254 |
|
1053
657f409c5dfe
* src/httpd.c: Fixed a problem with closing the client socket --
nickg
parents:
1008
diff
changeset
|
255 fclose(client); |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
256 } |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
257 |
| 468 | 258 /* ================================================================= */ |
| 259 /* Main HTTP server | |
| 260 * | |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
261 * This just loops, collects client connections, and calls the main |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
262 * process function on the connects*/ |
| 468 | 263 |
| 264 static void cyg_httpd_server( cyg_addrword_t arg ) | |
| 265 { | |
| 266 do | |
| 267 { | |
| 268 int client_socket; | |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
269 struct sockaddr client_address; |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
270 int calen = sizeof(client_address); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
271 fd_set readfds; |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
272 int n; |
| 468 | 273 |
| 274 /* Wait for a connection. | |
| 275 */ | |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
276 FD_ZERO(&readfds); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
277 FD_SET(server_socket, &readfds); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
278 #ifdef CYGPKG_NET_INET6 |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
279 FD_SET(server_socket6, &readfds); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
280 n = (server_socket > server_socket6 ? server_socket : server_socket6) + 1; |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
281 #else |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
282 n = server_socket + 1; |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
283 #endif |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
284 select(n,&readfds,NULL,NULL,NULL); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
285 if (FD_ISSET(server_socket, &readfds)) { |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
286 client_socket = accept( server_socket, &client_address, &calen ); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
287 cyg_httpd_process(client_socket, &client_address); |
| 468 | 288 } |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
289 #ifdef CYGPKG_NET_INET6 |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
290 if (FD_ISSET(server_socket6, &readfds)) { |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
291 client_socket = accept( server_socket6, &client_address, &calen ); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
292 cyg_httpd_process(client_socket, &client_address); |
| 468 | 293 } |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
294 #endif |
| 468 | 295 } while(1); |
| 296 } | |
| 297 | |
| 298 /* ================================================================= */ | |
| 299 /* Initialization thread | |
| 300 * | |
| 301 * Optionally delay for a time before getting the network | |
| 302 * running. Then create and bind the server socket and put it into | |
| 303 * listen mode. Spawn any further server threads, then enter server | |
| 304 * mode. | |
| 305 */ | |
| 306 | |
| 307 static void cyg_httpd_init(cyg_addrword_t arg) | |
| 308 { | |
| 309 int i; | |
| 310 int err = 0; | |
| 311 | |
| 312 /* Delay for a configurable length of time to give the application | |
| 313 * a chance to get going, or even complete, without interference | |
| 314 * from the HTTPD. | |
| 315 */ | |
| 316 if( CYGNUM_HTTPD_SERVER_DELAY > 0 ) | |
| 317 { | |
| 318 cyg_thread_delay( CYGNUM_HTTPD_SERVER_DELAY ); | |
| 319 } | |
| 320 | |
| 321 server_address.sin_family = AF_INET; | |
| 322 server_address.sin_len = sizeof(server_address); | |
| 323 server_address.sin_addr.s_addr = INADDR_ANY; | |
| 324 server_address.sin_port = htons(CYGNUM_HTTPD_SERVER_PORT); | |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
325 #ifdef CYGPKG_NET_INET6 |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
326 server_address6.sin6_family = AF_INET6; |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
327 server_address6.sin6_len = sizeof(server_address6); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
328 server_address6.sin6_addr = in6addr_any; |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
329 server_address6.sin6_port = htons(CYGNUM_HTTPD_SERVER_PORT); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
330 #endif |
| 468 | 331 /* Get the network going. This is benign if the application has |
| 332 * already done this. | |
| 333 */ | |
| 334 init_all_network_interfaces(); | |
| 335 | |
| 336 /* Create and bind the server socket. | |
| 337 */ | |
| 338 server_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); | |
| 339 CYG_ASSERT( server_socket > 0, "Socket create failed"); | |
| 340 | |
| 341 err = bind( server_socket, (struct sockaddr *)&server_address, | |
| 342 sizeof(server_address) ); | |
| 343 CYG_ASSERT( err == 0, "bind() returned error"); | |
| 344 | |
| 345 err = listen( server_socket, SOMAXCONN ); | |
| 346 CYG_ASSERT( err == 0, "listen() returned error" ); | |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
347 #ifdef CYGPKG_NET_INET6 |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
348 server_socket6 = socket( AF_INET6, SOCK_STREAM, IPPROTO_TCP ); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
349 CYG_ASSERT( server_socket6 > 0, "Socket AF_INET6 create failed"); |
| 468 | 350 |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
351 err = bind( server_socket6, (struct sockaddr *)&server_address6, |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
352 sizeof(server_address6) ); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
353 CYG_ASSERT( err == 0, "bind(AF_INET6) returned error"); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
354 |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
355 err = listen( server_socket6, SOMAXCONN ); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
356 CYG_ASSERT( err == 0, "listen(AF_INET6) returned error" ); |
|
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
357 #endif |
| 468 | 358 /* If we are configured to have more than one server thread, |
| 359 * create them now. | |
| 360 */ | |
| 361 for( i = 1; i < CYGNUM_HTTPD_THREAD_COUNT; i++ ) | |
| 362 { | |
| 363 cyg_thread_create( CYGNUM_HTTPD_THREAD_PRIORITY, | |
| 364 cyg_httpd_server, | |
| 365 0, | |
| 366 "HTTPD", | |
| 367 &httpd_stacks[i][0], | |
| 368 sizeof(httpd_stacks[i]), | |
| 369 &httpd_thread[i], | |
| 370 &httpd_thread_object[i] | |
| 371 ); | |
| 372 | |
| 373 cyg_thread_resume( httpd_thread[i] ); | |
| 374 } | |
| 375 | |
| 376 /* Now go be a server ourself. | |
| 377 */ | |
| 378 cyg_httpd_server(arg); | |
| 379 } | |
| 380 | |
| 381 /* ================================================================= */ | |
| 382 /* System initializer | |
| 383 * | |
| 384 * This is called from the static constructor in init.cxx. It spawns | |
| 385 * the main server thread and makes it ready to run. | |
| 386 */ | |
| 387 | |
| 388 __externC void cyg_httpd_startup(void) | |
| 389 { | |
| 390 cyg_thread_create( CYGNUM_HTTPD_THREAD_PRIORITY, | |
| 391 cyg_httpd_init, | |
| 392 0, | |
| 393 "HTTPD", | |
| 394 &httpd_stacks[0][0], | |
| 395 sizeof(httpd_stacks[0]), | |
| 396 &httpd_thread[0], | |
| 397 &httpd_thread_object[0] | |
| 398 ); | |
| 399 | |
| 400 cyg_thread_resume( httpd_thread[0] ); | |
| 401 } | |
| 402 | |
| 403 /* ================================================================= */ | |
| 404 /* HTTP protocol handling | |
| 405 * | |
| 406 * cyg_http_start() generates an HTTP header with the given content | |
| 407 * type and, if non-zero, length. | |
| 408 * cyg_http_finish() just adds a couple of newlines for luck and | |
| 409 * flushes the stream. | |
| 410 */ | |
| 411 | |
| 412 __externC void cyg_http_start( FILE *client, char *content_type, | |
| 413 int content_length ) | |
| 414 { | |
| 415 fputs( "HTTP/1.1 200 OK\n" | |
| 416 "Server: " CYGDAT_HTTPD_SERVER_ID, | |
| 417 client ); | |
| 418 | |
| 419 if( content_type != NULL ) | |
| 420 fprintf( client,"Content-type: %s\n", content_type ); | |
| 421 | |
| 422 if( content_length != 0 ) | |
| 423 fprintf( client, "Content-length: %d\n", content_length ); | |
| 424 | |
| 425 fputs( "Connection: close\n" | |
| 426 "\n", | |
| 427 client ); | |
| 428 } | |
| 429 | |
| 430 __externC void cyg_http_finish( FILE *client ) | |
| 431 { | |
| 432 fputs( "\n\n", client ); | |
| 433 fflush( client ); | |
| 434 } | |
| 435 | |
| 436 | |
| 437 /* ================================================================= */ | |
| 438 /* HTML tag generation | |
| 439 * | |
| 440 * These functions generate standard HTML begin and end tags. By using | |
| 441 * these rather than direct printf()s we help to reduce the number of | |
| 442 * distinct strings present in the executable. | |
| 443 */ | |
| 444 | |
| 445 __externC void cyg_html_tag_begin( FILE *client, char *tag, char *attr ) | |
| 446 { | |
| 447 char *pad = ""; | |
| 448 | |
| 449 if( attr == NULL ) | |
| 450 attr = pad; | |
| 451 else if( attr[0] != 0 ) | |
| 452 pad = " "; | |
| 453 | |
| 454 fprintf(client, "<%s%s%s>\n",tag,pad,attr); | |
| 455 } | |
| 456 | |
| 457 __externC void cyg_html_tag_end( FILE *client, char *tag ) | |
| 458 { | |
| 459 fprintf( client, "<%s%s%s>\n","/",tag,""); | |
| 460 } | |
| 461 | |
| 462 /* ================================================================= */ | |
| 463 /* Parse form request data | |
| 464 * | |
| 465 * Given a form response string, we parse it into an argv/environment | |
| 466 * style array of "name=value" strings. We also convert any '+' | |
| 467 * separators back into spaces. | |
| 468 * | |
| 469 * TODO: also translate any %xx escape sequences back into real | |
| 470 * characters. | |
| 471 */ | |
| 472 | |
| 473 __externC void cyg_formdata_parse( char *data, char *list[], int size ) | |
| 474 { | |
| 475 char *p = data; | |
| 476 int i = 0; | |
| 477 | |
| 478 list[i] = p; | |
| 479 | |
|
1008
4ca8a5f30c03
* src/monitor.c (cyg_monitor_network): Added IPv6 information to
asl
parents:
468
diff
changeset
|
480 while( p && *p != 0 && i < size-1 ) |
| 468 | 481 { |
| 482 if( *p == '&' ) | |
| 483 { | |
| 484 *p++ = 0; | |
| 485 list[++i] = p; | |
| 486 continue; | |
| 487 } | |
| 488 if( *p == '+' ) | |
| 489 *p = ' '; | |
| 490 p++; | |
| 491 } | |
| 492 | |
| 493 list[++i] = 0; | |
| 494 } | |
| 495 | |
| 496 /* ----------------------------------------------------------------- */ | |
| 497 /* Search for a form response value | |
| 498 * | |
| 499 * Search a form response list generated by cyg_formdata_parse() for | |
| 500 * the named element. If it is found a pointer to the value part is | |
| 501 * returned. If it is not found a NULL pointer is returned. | |
| 502 */ | |
| 503 | |
| 504 __externC char *cyg_formlist_find( char *list[], char *name ) | |
| 505 { | |
| 506 while( *list != 0 ) | |
| 507 { | |
| 508 char *p = *list; | |
| 509 char *q = name; | |
| 510 | |
| 511 while( *p == *q ) | |
| 512 p++, q++; | |
| 513 | |
| 514 if( *q == 0 && *p == '=' ) | |
| 515 return p+1; | |
| 516 | |
| 517 list++; | |
| 518 } | |
| 519 | |
| 520 return 0; | |
| 521 } | |
| 522 | |
| 523 /* ================================================================= */ | |
| 524 /* Predefined page handlers | |
| 525 */ | |
| 526 | |
| 527 /* ----------------------------------------------------------------- */ | |
| 528 /* Send an HTML page from a single string | |
| 529 * | |
| 530 * This just sends the string passed as the argument with an HTTP | |
| 531 * header that describes it as HTML. This is useful for sending | |
| 532 * straightforward static web content. | |
| 533 */ | |
| 534 | |
| 535 __externC cyg_bool cyg_httpd_send_html( FILE *client, char *filename, | |
| 536 char *request, void *arg ) | |
| 537 { | |
| 538 html_begin( client ); | |
| 539 | |
| 540 fwrite( arg, 1, strlen((char *)arg), client ); | |
| 541 | |
| 542 html_end( client ); | |
| 543 | |
| 544 return true; | |
| 545 } | |
| 546 | |
| 547 /* ----------------------------------------------------------------- */ | |
| 548 /* Send arbitrary data | |
| 549 * | |
| 550 * This takes a pointer to a cyg_httpd_data structure as the argument | |
| 551 * and sends the data therein after a header that uses the content | |
| 552 * type and size from the structure. This is useful for non-HTML data | |
| 553 * such a images. | |
| 554 */ | |
| 555 | |
| 556 __externC cyg_bool cyg_httpd_send_data( FILE *client, char *filename, | |
| 557 char *request, void *arg ) | |
| 558 { | |
| 559 cyg_httpd_data *data = (cyg_httpd_data *)arg; | |
| 560 | |
| 561 cyg_http_start( client, data->content_type, data->content_length ); | |
| 562 | |
| 563 fwrite( data->data, 1, data->content_length, client ); | |
| 564 | |
| 565 return true; | |
| 566 } | |
| 567 | |
| 568 /* ----------------------------------------------------------------- */ | |
| 569 /* end of httpd.c */ |
