Mercurial > ecos
annotate packages/net/athttpd/current/src/http.c @ 3292:7f8e529b4d82 default tip
Fix FREESCALE_EDMA_NBYTES_MLOFFYES_MLOFF() so it works with negative offsets.
| author | vae |
|---|---|
| date | Wed, 29 Apr 2015 23:31:48 +0000 |
| parents | 74dbf4c3f2e1 |
| children |
| rev | line source |
|---|---|
| 2250 | 1 /* ================================================================= |
| 2 * | |
| 3 * http.c | |
| 4 * | |
| 5 * Handles the client requests. | |
| 6 * | |
| 7 * ================================================================= | |
|
2729
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
8 * ####ECOSGPLCOPYRIGHTBEGIN#### |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
9 * ------------------------------------------- |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
10 * This file is part of eCos, the Embedded Configurable Operating System. |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
11 * Copyright (C) 2005, 2007 Free Software Foundation, Inc. |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
12 * |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
13 * eCos is free software; you can redistribute it and/or modify it under |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
14 * the terms of the GNU General Public License as published by the Free |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
15 * Software Foundation; either version 2 or (at your option) any later |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
16 * version. |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
17 * |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
18 * eCos is distributed in the hope that it will be useful, but WITHOUT |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
20 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
21 * for more details. |
| 2250 | 22 * |
|
2729
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
23 * You should have received a copy of the GNU General Public License |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
24 * along with eCos; if not, write to the Free Software Foundation, Inc., |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
26 * |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
27 * As a special exception, if other files instantiate templates or use |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
28 * macros or inline functions from this file, or you compile this file |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
29 * and link it with other works to produce a work based on this file, |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
30 * this file does not by itself cause the resulting work to be covered by |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
31 * the GNU General Public License. However the source code for this file |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
32 * must still be made available in accordance with section (3) of the GNU |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
33 * General Public License v2. |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
34 * |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
35 * This exception does not invalidate any other reasons why a work based |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
36 * on this file might be covered by the GNU General Public License. |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
37 * ------------------------------------------- |
|
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2485
diff
changeset
|
38 * ####ECOSGPLCOPYRIGHTEND#### |
| 2250 | 39 * ================================================================= |
| 40 * #####DESCRIPTIONBEGIN#### | |
| 41 * | |
| 42 * Author(s): Anthony Tonizzo (atonizzo@gmail.com) | |
| 2265 | 43 * Contributors: Sergei Gavrikov (w3sg@SoftHome.net) |
| 2326 | 44 * Lars Povlsen (lpovlsen@vitesse.com) |
| 2250 | 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 | |
| 2326 | 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"}; | |
| 2250 | 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"); | |
| 2326 | 98 CYG_HTTPD_MIME_TABLE_ENTRY(hal_png_entry, "png", "image/png"); |
| 2250 | 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; | |
| 2326 | 106 |
| 107 // Errors pages close the socket and are never cached. | |
| 108 httpstate.mode |= CYG_HTTPD_MODE_NO_CACHE; | |
| 2250 | 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 | |
| 2265 | 145 ssize_t payload_size = fread(httpstate.outbuffer, |
| 146 1, | |
| 147 CYG_HTTPD_MAXOUTBUFFER, | |
| 148 fp); | |
| 2250 | 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 | |
| 2326 | 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 | |
| 2250 | 173 |
| 2326 | 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, | |
| 2250 | 185 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"); |
| 186 switch (err_type) | |
| 187 { | |
| 188 case CYG_HTTPD_STATUS_MOVED_PERMANENTLY: | |
| 2326 | 189 strcat(httpstate.outbuffer, |
| 2250 | 190 "<html><head><title>301 Moved Permanently</title></head>\r\n" |
| 191 "<body><h1>Moved Permanently</h1>\r\n" | |
| 2326 | 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"); | |
| 2250 | 203 break; |
| 204 case CYG_HTTPD_STATUS_NOT_AUTHORIZED: | |
| 2326 | 205 strcat(httpstate.outbuffer, |
| 2250 | 206 "<html><head><title>401 Not Authorized</title></head>\r\n"); |
| 2326 | 207 strcat(httpstate.outbuffer, |
| 208 "<body><p>Authorization required to access this URL.</p>\r\n"); | |
| 2250 | 209 break; |
| 210 case CYG_HTTPD_STATUS_NOT_MODIFIED: | |
| 2326 | 211 cyg_httpd_end_chunked(); |
| 212 return; | |
| 2250 | 213 case CYG_HTTPD_STATUS_NOT_FOUND: |
| 2326 | 214 strcat(httpstate.outbuffer, |
| 2250 | 215 "<html><head><title>404 Not Found</title></head>\r\n"); |
| 2326 | 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); | |
| 2250 | 219 break; |
| 220 case CYG_HTTPD_STATUS_SYSTEM_ERROR: | |
| 2326 | 221 strcat(httpstate.outbuffer, |
| 2250 | 222 "<html><head><title>500 Server Error</title></head>\r\n"); |
| 2326 | 223 strcat(httpstate.outbuffer, |
| 2250 | 224 "<p>The server encountered an unexpected condition that " |
| 2326 | 225 "prevented it from fulfilling the request" |
| 226 " by the client</p>\r\n"); | |
| 2250 | 227 break; |
| 228 case CYG_HTTPD_STATUS_NOT_IMPLEMENTED: | |
| 2326 | 229 strcat(httpstate.outbuffer, |
| 2250 | 230 "<html><head><title>501 Not Implemented</title></head>\r\n"); |
| 2326 | 231 strcat(httpstate.outbuffer, |
| 232 "<p>The method requested is not implemented</p>\r\n"); | |
| 2250 | 233 break; |
| 234 default: | |
| 2326 | 235 strcat(httpstate.outbuffer, |
| 2250 | 236 "<html><head><title>400 Bad Request</title></head>\r\n"); |
| 2326 | 237 strcat(httpstate.outbuffer, |
| 238 "<p>Bad request</p>\r\n"); | |
| 2250 | 239 break; |
| 240 } | |
| 241 | |
| 2326 | 242 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer), |
| 243 "<hr>%s at %d.%d.%d.%d Port %d\r\n</body></html>\r\n", | |
| 2250 | 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 | |
| 2326 | 251 cyg_httpd_write_chunked(httpstate.outbuffer, strlen(httpstate.outbuffer)); |
| 252 cyg_httpd_end_chunked(); | |
| 2250 | 253 } |
| 254 | |
| 2326 | 255 // Return a time_t that is always UTC (aka GMT). |
| 2250 | 256 time_t |
| 257 cyg_httpd_parse_date(char *time) | |
| 258 { | |
| 259 int i; | |
| 260 char month[4]; | |
| 261 struct tm tm_mod; | |
| 262 | |
| 2265 | 263 // We are going to get rid of the day of the week. This is always the first |
| 2250 | 264 // part of the string, separated by a blank. |
| 2326 | 265 time = strchr( time, ' '); |
| 266 if ( time == NULL) | |
| 2250 | 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 { | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
292 // asctime(). |
| 2250 | 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 | |
| 2265 | 319 // extension is not in the table. |
| 2250 | 320 char* |
| 2265 | 321 cyg_httpd_find_mime_string(char *ext) |
| 2250 | 322 { |
| 323 cyg_httpd_mime_table_entry *entry = cyg_httpd_mime_table; | |
| 324 | |
| 325 while (entry != cyg_httpd_mime_table_end) | |
| 326 { | |
| 2326 | 327 if (!strcmp((const char*)ext, entry->extension)) |
| 2250 | 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 { | |
| 2326 | 338 char *src = strstr(filename, "//"); |
| 2250 | 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 } | |
| 2326 | 364 } |
| 2250 | 365 |
| 366 cyg_int32 | |
| 367 cyg_httpd_initialize(void) | |
| 368 { | |
| 2326 | 369 httpstate.post_data = NULL; |
| 2250 | 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 { | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
445 sprintf(httpstate.url, |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
446 "http://%d.%d.%d.%d:%d%s/", |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
447 httpstate.host[0], |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
448 httpstate.host[1], |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
449 httpstate.host[2], |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
450 httpstate.host[3], |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
451 CYGNUM_NET_ATHTTPD_SERVEROPT_PORT, |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
452 tmp_url); |
| 2250 | 453 cyg_httpd_send_error(CYG_HTTPD_STATUS_MOVED_PERMANENTLY); |
| 454 return; | |
| 455 } | |
| 456 | |
| 2265 | 457 // We are going to try to locate an index page in the directory we got |
| 458 // in the URL. | |
| 2250 | 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; | |
| 2326 | 474 |
| 2250 | 475 // Let's see if we luck out and can send a 304. |
| 476 if ((httpstate.modified_since != -1) && | |
| 2326 | 477 (httpstate.modified_since >= httpstate.last_modified)) |
| 2250 | 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 | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
485 // Here we'll look for an extension to the file. Consider the case where |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
486 // there might be more than one dot in the file name. We'll look for just |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
487 // the last one, then we'll check the extension. |
| 2250 | 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; | |
| 2326 | 495 httpstate.mode &= ~CYG_HTTPD_MODE_NO_CACHE; |
| 2250 | 496 cyg_int32 payload_size = cyg_httpd_format_header(); |
| 2326 | 497 if ((httpstate.mode & CYG_HTTPD_MODE_SEND_HEADER_ONLY) != 0) |
| 2250 | 498 { |
| 2326 | 499 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1 |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
500 diag_printf("Sending header only for URL: %s\n", file_name); |
| 2326 | 501 #endif |
| 2250 | 502 send(httpstate.sockets[httpstate.client_index].descriptor, |
| 503 httpstate.outbuffer, | |
| 504 payload_size, | |
| 505 0); | |
| 506 return; | |
| 507 } | |
| 508 | |
| 2326 | 509 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1 |
| 510 diag_printf("Sending file: %s\n", file_name); | |
| 511 #endif | |
| 2250 | 512 fp = fopen(file_name, "r"); |
| 2326 | 513 if (fp == NULL) |
| 2250 | 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) | |
| 2326 | 530 { |
| 531 bread = fread(httpstate.outbuffer, 1, CYG_HTTPD_MAXOUTBUFFER, fp); | |
| 532 bytes_written += cyg_httpd_write(httpstate.outbuffer, bread); | |
| 533 } | |
| 2250 | 534 |
| 535 err = fclose(fp); | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
536 if (err < 0) |
| 2250 | 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"); | |
| 2326 | 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"); | |
| 2250 | 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), | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
587 "WWW-Authenticate: Digest realm=\"%s\", ", |
| 2250 | 588 httpstate.needs_auth->auth_domainname); |
| 2326 | 589 strftime(cyg_httpd_md5_nonce, |
| 590 33, | |
| 591 TIME_FORMAT_RFC1123, | |
| 592 gmtime(&time_val)); | |
| 2250 | 593 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer), |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
594 "nonce=\"%s\", ", cyg_httpd_md5_nonce); |
| 2250 | 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, | |
| 2326 | 601 CYG_HTTPD_MD5_AUTH_QOP); |
| 2250 | 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 | |
| 2326 | 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 | |
| 2250 | 633 sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer), |
| 2326 | 634 "Server: %s\r\n", |
| 635 CYGDAT_NET_ATHTTPD_SERVEROPT_SERVERID); | |
| 2250 | 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 | |
| 2326 | 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); | |
| 2250 | 648 |
| 649 if (httpstate.mode & CYG_HTTPD_MODE_TRANSFER_CHUNKED) | |
| 650 strcat(httpstate.outbuffer, "Transfer-Encoding: chunked\r\n"); | |
| 651 | |
| 2326 | 652 if (httpstate.mode & CYG_HTTPD_MODE_NO_CACHE) |
| 653 strcat(httpstate.outbuffer, "Cache-Control: no-cache\r\n"); | |
| 654 | |
| 2250 | 655 if (httpstate.last_modified != -1) |
| 656 { | |
| 657 time_val = httpstate.last_modified; | |
| 2326 | 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 | |
| 2250 | 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 { | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
686 #if defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER) ||\ |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
687 defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL) |
| 2250 | 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 | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
701 // User defined handlers take precedence over other forms of response. |
|
2449
4631139fc774
* doc/athttpd.sgml: added an example of a tcl script.
jlarmour
parents:
2326
diff
changeset
|
702 handler h = cyg_httpd_find_handler(); |
|
4631139fc774
* doc/athttpd.sgml: added an example of a tcl script.
jlarmour
parents:
2326
diff
changeset
|
703 if (h != 0) |
|
4631139fc774
* doc/athttpd.sgml: added an example of a tcl script.
jlarmour
parents:
2326
diff
changeset
|
704 { |
|
4631139fc774
* doc/athttpd.sgml: added an example of a tcl script.
jlarmour
parents:
2326
diff
changeset
|
705 h(&httpstate); |
|
4631139fc774
* doc/athttpd.sgml: added an example of a tcl script.
jlarmour
parents:
2326
diff
changeset
|
706 return; |
|
4631139fc774
* doc/athttpd.sgml: added an example of a tcl script.
jlarmour
parents:
2326
diff
changeset
|
707 } |
|
4631139fc774
* doc/athttpd.sgml: added an example of a tcl script.
jlarmour
parents:
2326
diff
changeset
|
708 |
|
4631139fc774
* doc/athttpd.sgml: added an example of a tcl script.
jlarmour
parents:
2326
diff
changeset
|
709 |
| 2250 | 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 != '?') && | |
| 2326 | 757 ((dest - httpstate.url) <= CYG_HTTPD_MAXURL)) |
| 2250 | 758 { |
| 759 // Look for encoded characters in the URL. | |
| 760 if (*p == '%') | |
| 761 { | |
| 762 p++; | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
763 cyg_int8 ch = cyg_httpd_from_hex(*p++); |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
764 if (ch == -1) |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
765 { |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
766 cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST); |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
767 return (char*)0; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
768 } |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
769 *dest = ch << 4; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
770 ch = cyg_httpd_from_hex(*p++); |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
771 if (ch == -1) |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
772 { |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
773 cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST); |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
774 return (char*)0; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
775 } |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
776 *dest += ch; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
777 dest++; |
| 2250 | 778 } |
| 779 else | |
| 780 *dest++ = *p++; | |
| 781 } | |
| 782 | |
| 783 // Terminate the file name... | |
| 784 *dest = '\0'; | |
| 785 | |
| 2326 | 786 // The URL must start with a leading slash. |
| 2250 | 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 { | |
| 2326 | 798 httpstate.method = CYG_HTTPD_METHOD_POST; |
| 799 char *cp = cyg_httpd_get_URL(p); | |
| 800 if (cp == 0) | |
| 801 return (char*)0; | |
| 2250 | 802 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1 |
| 803 diag_printf("POST Request URL: %s\n", httpstate.url); | |
| 804 #endif | |
| 805 | |
| 2326 | 806 while (*cp++ != '\n'); |
| 807 return cp; | |
| 2250 | 808 } |
| 809 | |
| 810 char* | |
| 811 cyg_httpd_parse_GET(char* p) | |
| 812 { | |
| 2326 | 813 char *cp = cyg_httpd_get_URL(p); |
| 814 if (cp == 0) | |
| 815 return 0; | |
| 2250 | 816 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1 |
| 2326 | 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); | |
| 2250 | 821 #endif |
| 2326 | 822 |
| 823 if (*cp == '?') | |
| 2250 | 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. | |
| 2326 | 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); | |
| 2250 | 829 |
| 2326 | 830 // Run to end of line. |
| 831 while (*cp++ != '\n'); | |
| 832 return cp; | |
| 2250 | 833 } |
| 834 | |
| 835 char* | |
| 2326 | 836 cyg_httpd_process_header(char *p) |
| 2250 | 837 { |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
838 #ifdef CYGOPT_NET_ATHTTPD_USE_AUTH |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
839 // Clear the previous request's response. The client properly authenticated |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
840 // will always reinitialize this variable during the header parsing |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
841 // process. This variable is also commandeered to hold the hashed |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
842 // username:password duo in the basic authentication. |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
843 cyg_httpd_md5_response[0] = '\0'; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
844 #endif |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
845 |
| 2250 | 846 // The deafult for HTTP 1.1 is keep-alive connections, unless specifically |
| 847 // closed by the far end. | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
848 httpstate.mode &= ~(CYG_HTTPD_MODE_CLOSE_CONN | CYG_HTTPD_MODE_FORM_DATA |\ |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
849 CYG_HTTPD_MODE_SEND_HEADER_ONLY); |
| 2250 | 850 httpstate.modified_since = -1; |
| 2326 | 851 httpstate.content_len = 0; |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
852 while (p < httpstate.request_end) |
| 2250 | 853 { |
| 2326 | 854 if (strncasecmp("GET ", p, 4) == 0) |
| 2250 | 855 { |
| 2326 | 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); | |
| 2250 | 862 if (p ==0) |
| 2326 | 863 return (char*)0; |
| 2250 | 864 } |
| 2326 | 865 else if (strncasecmp("POST ", p, 5) == 0) |
| 2250 | 866 { |
| 2326 | 867 p = cyg_httpd_parse_POST(p + 5); |
| 2250 | 868 if (p ==0) |
| 2326 | 869 return (char*)0; |
| 2250 | 870 } |
| 2326 | 871 else if (strncasecmp("HEAD ", p, 5) == 0) |
| 2250 | 872 { |
| 2326 | 873 httpstate.method = CYG_HTTPD_METHOD_HEAD; |
| 874 httpstate.mode |= CYG_HTTPD_MODE_SEND_HEADER_ONLY; | |
| 875 p = cyg_httpd_parse_GET(p + 5); | |
| 2250 | 876 if (p ==0) |
| 2326 | 877 return (char*)0; |
| 2250 | 878 } |
| 879 else if (strncasecmp(p, "Content-Length: ", 16) == 0) | |
| 880 { | |
| 2326 | 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'); | |
| 2250 | 899 } |
| 900 else if (strncasecmp("Host:", p, 5) == 0) | |
| 901 { | |
| 902 p += 5; | |
| 2326 | 903 if (*p == ' ') |
| 2250 | 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]); | |
| 2326 | 911 while (*p++ != '\n'); |
| 2250 | 912 } |
| 913 else if (strncasecmp("If-Modified-Since:", p, 18) == 0) | |
| 914 { | |
| 915 p += 18; | |
| 2326 | 916 if ( *p == ' ') |
| 2250 | 917 p++; |
| 918 httpstate.modified_since = cyg_httpd_parse_date(p); | |
| 2326 | 919 while (*p++ != '\n'); |
| 2250 | 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++; | |
| 2326 | 927 if (strncasecmp("Basic", p, 5) == 0) |
| 2250 | 928 { |
| 929 p += 5; | |
| 930 while (*p == ' ') | |
| 931 p++; | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
932 cyg_int32 auth_data_length = 0; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
933 while (*p != '\n') |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
934 { |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
935 // We are going to copy only up to |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
936 // AUTH_STORAGE_BUFFER_LENGTH characters to prevent |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
937 // overflow of the cyg_httpd_md5_response variable. |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
938 if (auth_data_length < AUTH_STORAGE_BUFFER_LENGTH) |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
939 if ((*p != '\r') && (*p != ' ')) |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
940 cyg_httpd_md5_response[auth_data_length++] = *p; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
941 p++; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
942 } |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
943 p++; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
944 cyg_httpd_md5_response[auth_data_length] = '\0'; |
| 2250 | 945 } |
| 946 else if (strncasecmp(p, "Digest", 6) == 0) | |
| 947 { | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
948 p += 6; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
949 while (*p == ' ') |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
950 p++; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
951 while (*p != '\n') |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
952 { |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
953 if (strncasecmp(p, "realm=", 6) == 0) |
| 2250 | 954 p = cyg_httpd_digest_skip(p + 6); |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
955 else if (strncasecmp(p, "username=", 9) == 0) |
| 2250 | 956 p = cyg_httpd_digest_skip(p + 9); |
| 957 else if (strncasecmp(p, "nonce=", 6) == 0) | |
| 958 p = cyg_httpd_digest_skip(p + 6); | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
959 else if (strncasecmp(p, "response=", 9) == 0) |
| 2250 | 960 p = cyg_httpd_digest_data(cyg_httpd_md5_response, |
| 961 p + 9); | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
962 else if (strncasecmp(p, "cnonce=", 7) == 0) |
| 2250 | 963 p = cyg_httpd_digest_data(cyg_httpd_md5_cnonce, p + 7); |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
964 else if (strncasecmp(p, "qop=", 4) == 0) |
| 2250 | 965 p = cyg_httpd_digest_skip(p + 4); |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
966 else if (strncasecmp(p, "nc=", 3) == 0) |
| 2250 | 967 p = cyg_httpd_digest_data(cyg_httpd_md5_noncecount, |
| 968 p + 3); | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
969 else if (strncasecmp(p, "algorithm=", 10) == 0) |
| 2250 | 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); | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
975 else |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
976 p++; |
| 2250 | 977 } |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
978 p++; |
| 2250 | 979 } |
| 980 else | |
| 2326 | 981 while (*p++ != '\n'); |
| 2250 | 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; | |
| 2326 | 991 while (*p++ != '\n'); |
| 2250 | 992 } |
| 993 else | |
| 994 // We'll just dump the rest of the line and move on to the next. | |
| 2326 | 995 while (*p++ != '\n'); |
| 2250 | 996 } |
| 2326 | 997 return p; |
| 2250 | 998 } |
| 999 | |
| 2326 | 1000 void |
| 2250 | 1001 cyg_httpd_process_method(void) |
| 1002 { | |
| 2326 | 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++; | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1010 |
| 2326 | 1011 while (*p != '\0') |
| 2250 | 1012 { |
| 2326 | 1013 p = cyg_httpd_process_header(p); |
| 1014 if (p == 0) | |
| 1015 return; | |
|
2485
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1016 |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1017 #ifdef CYGOPT_NET_ATHTTPD_USE_AUTH |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1018 // Let's check that the requested URL is not inside some directory that |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1019 // needs authentication. |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1020 cyg_httpd_auth_table_entry* auth = |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1021 cyg_httpd_is_authenticated(httpstate.url); |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1022 if (auth != 0) |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1023 { |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1024 cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_AUTHORIZED); |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1025 return; |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1026 } |
|
0e9d1d1df4a0
* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
asl
parents:
2449
diff
changeset
|
1027 #endif |
| 2326 | 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 } | |
| 2250 | 1044 } |
| 1045 |
