00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00094
00095 #include <cfg/arch.h>
00096
00097 #include <string.h>
00098 #include <stdlib.h>
00099 #include <memdebug.h>
00100
00101 #include <io.h>
00102 #include <ctype.h>
00103 #include <stdio.h>
00104 #include <sys/types.h>
00105 #include <unistd.h>
00106 #include <fcntl.h>
00107 #include <memdebug.h>
00108
00109 #include <sys/heap.h>
00110 #include <sys/version.h>
00111
00112 #include <pro/httpd.h>
00113 #include <pro/ssi.h>
00114 #include "httpd_p.h"
00115 #include "dencode.h"
00116
00117 #define BUFSIZE 512
00118
00119 #define MIN(a,b) (a<b?a:b)
00120
00121 #define SSI_TYPE_FILE 0x01
00122 #define SSI_TYPE_VIRTUAL 0x02
00123 #define SSI_TYPE_EXEC 0x03
00124
00125 static prog_char rsp_not_found_P[] = "404 Not found: %s\r\n";
00126 static prog_char rsp_intern_err_P[] = "500 Internal error\r\n";
00127 static prog_char rsp_bad_req_P[] = "400 Bad request\r\n";
00128
00129 extern char *cgiBinPath;
00130
00141 static void NutSsiProcessFile(FILE * stream, char *filename)
00142 {
00143 int fd;
00144 int n;
00145 char *data;
00146 int size;
00147 long file_len;
00148
00149 fd = _open(filename, _O_BINARY | _O_RDONLY);
00150
00151 if (fd == -1) {
00152 fprintf_P(stream, rsp_not_found_P, filename);
00153 return;
00154 }
00155
00156 file_len = _filelength(fd);
00157
00158 size = 512;
00159 if ((data = malloc(size)) != NULL) {
00160 while (file_len) {
00161 if (file_len < 512L)
00162 size = (int) file_len;
00163
00164 n = _read(fd, data, size);
00165 if (fwrite(data, 1, n, stream) == 0)
00166 break;
00167 file_len -= (long) n;
00168 }
00169 free(data);
00170 }
00171
00172 _close(fd);
00173 }
00174
00175
00189 static void NutSsiProcessVirtual(FILE * stream, char *url, char* http_root, REQUEST *orig_req)
00190 {
00191 int fd;
00192 int i;
00193 int n;
00194 char *data;
00195 int size;
00196 long file_len;
00197 char *filename = NULL;
00198 void (*handler)(FILE *stream, int fd, int file_len, char *http_root, REQUEST *req);
00199 char *cp;
00200 REQUEST * req;
00201 CONST char *cgi_bin = cgiBinPath ? cgiBinPath : "cgi-bin/";
00202 CONST char * tmp;
00203 size_t len;
00204
00205 tmp = cgi_bin;
00206 if (NutDecodePath(url) == 0) {
00207 fprintf_P(stream, rsp_bad_req_P);
00208 return;
00209 }
00210
00211
00212
00213
00214 while (tmp) {
00215
00216 while (*cgi_bin == ';')
00217 cgi_bin++;
00218
00219 for (len = 0, cp = (char *)cgi_bin; *cp && *cp != ';'; len++, cp++);
00220 tmp = cgi_bin;
00221 if (len && strncasecmp(url, tmp, len) == 0) {
00222 if ((req = calloc(1, sizeof(REQUEST))) == 0) {
00223 fprintf_P(stream, rsp_intern_err_P);
00224 return;
00225 }
00226 req->req_method = METHOD_GET;
00227 req->req_version = orig_req->req_version;
00228 req->req_length = 0;
00229
00230 if (orig_req->req_agent != NULL) {
00231 if ((req->req_agent = strdup(orig_req->req_agent)) == NULL) {
00232 fprintf_P(stream, rsp_intern_err_P);
00233 DestroyRequestInfo(req);
00234 return;
00235 }
00236 }
00237 if (orig_req->req_cookie!= NULL) {
00238 if ((req->req_cookie = strdup(orig_req->req_cookie)) == NULL) {
00239 fprintf_P(stream, rsp_intern_err_P);
00240 DestroyRequestInfo(req);
00241 return;
00242 }
00243 }
00244 if ((cp = strchr(url, '?')) != 0) {
00245 *cp++ = 0;
00246 if (strcmp(cp, "$QUERY_STRING") == 0) {
00247 uint16_t size;
00248 size = 1;
00249 for (i = 0; i < orig_req->req_numqptrs*2; i ++) {
00250 size += strlen(orig_req->req_qptrs[i]) + 1;
00251 }
00252 if ((req->req_query = malloc(size)) == NULL) {
00253 fprintf_P(stream, rsp_intern_err_P);
00254 DestroyRequestInfo(req);
00255 return;
00256 }
00257 req->req_query[0] = 0;
00258 for (i = 0; i < (orig_req->req_numqptrs * 2); i++) {
00259 if(i) {
00260 strcat (req->req_query, "&");
00261 }
00262 strcat (req->req_query, orig_req->req_qptrs[i]);
00263 strcat (req->req_query, "=");
00264 i++;
00265 strcat (req->req_query, orig_req->req_qptrs[i]);
00266 }
00267
00268 } else {
00269 if ((req->req_query = strdup(cp)) == NULL) {
00270 fprintf_P(stream, rsp_intern_err_P);
00271 DestroyRequestInfo(req);
00272 return;
00273 }
00274 }
00275 NutHttpProcessQueryString(req);
00276 }
00277 if ((req->req_url = strdup(url)) == NULL) {
00278 fprintf_P(stream, rsp_intern_err_P);
00279 DestroyRequestInfo(req);
00280 return;
00281 }
00282 NutCgiProcessRequest(stream, req, len);
00283 DestroyRequestInfo(req);
00284 return;
00285 }
00286 cgi_bin += len;
00287 if (*cgi_bin == '\0') {
00288 break;
00289 }
00290 }
00291
00292
00293
00294
00295
00296 for (n = 0, fd = -1; default_files[n]; n++) {
00297 filename = CreateFilePath(url, default_files[n]);
00298 if (filename == NULL) {
00299 fprintf_P(stream, rsp_intern_err_P);
00300 return;
00301 }
00302
00303
00304
00305
00306
00307
00308 if ((fd = _open(filename, _O_BINARY | _O_RDONLY)) != -1) {
00309 if (_filelength(fd)) {
00310 break;
00311 }
00312 _close(fd);
00313 }
00314 free(filename);
00315 }
00316 if (fd == -1) {
00317 fprintf_P(stream, rsp_not_found_P, filename);
00318 return;
00319 }
00320
00321 file_len = _filelength(fd);
00322 handler = NutGetMimeHandler(filename);
00323 free(filename);
00324
00325 if (handler == NULL) {
00326 size = 512;
00327 if ((data = malloc(size)) != NULL) {
00328 while (file_len) {
00329 if (file_len < 512L) {
00330 size = (int) file_len;
00331 }
00332
00333 n = _read(fd, data, size);
00334 if (fwrite(data, 1, n, stream) == 0) {
00335 break;
00336 }
00337 file_len -= (long) n;
00338 }
00339 free(data);
00340 }
00341 } else handler(stream, fd, file_len, http_root, orig_req);
00342 _close(fd);
00343 return;
00344 }
00345
00358 static void NutSsiSkipWhitespace(char *buffer, uint16_t *pos, uint16_t end)
00359 {
00360 while ((*pos < end) && (
00361 (buffer[*pos] == '\n') || (buffer[*pos] == '\r') ||
00362 (buffer[*pos] == '\t') || (buffer[*pos] == ' ')))
00363 (*pos) ++;
00364 }
00365
00384 static uint8_t NutSsiCheckForSsi(FILE *stream, char *buffer, uint16_t end, char* http_root, REQUEST *req)
00385 {
00386 uint16_t pos = 4;
00387 char * filename;
00388 uint8_t type;
00389
00390 pos = 4;
00391 NutSsiSkipWhitespace(buffer, &pos, end);
00392 if (pos == end) return 0;
00393
00394 if (strncasecmp(&buffer[pos], "#include", 8) == 0) {
00395 pos += 8;
00396 type = SSI_TYPE_VIRTUAL;
00397 } else
00398 if (strncasecmp(&buffer[pos], "#exec", 5) == 0) {
00399 pos += 5;
00400 type = SSI_TYPE_EXEC;
00401 } else return 0;
00402 if (pos >= end) return 0;
00403
00404 NutSsiSkipWhitespace(buffer, &pos, end);
00405 if (pos == end) return 0;
00406
00407 if (type == SSI_TYPE_VIRTUAL) {
00408 if (strncasecmp(&buffer[pos], "virtual", 7) == 0) {
00409 pos += 7;
00410 } else
00411 if (strncasecmp(&buffer[pos], "file", 4) == 0) {
00412 pos += 4;
00413 type = SSI_TYPE_FILE;
00414 } else return 0;
00415 } else {
00416 if (strncasecmp(&buffer[pos], "cgi", 3) == 0) {
00417 pos += 3;
00418 } else return 0;
00419 }
00420 if (pos >= end) return 0;
00421
00422 NutSsiSkipWhitespace(buffer, &pos, end);
00423 if (pos == end) return 0;
00424
00425 if (buffer[pos] != '=') return 0;
00426 pos ++;
00427
00428 NutSsiSkipWhitespace(buffer, &pos, end);
00429 if (pos == end) return 0;
00430
00431 if (buffer[pos] == '"') {
00432 pos ++;
00433 if (pos == end) return 0;
00434 filename = &buffer[pos];
00435 while (buffer[pos] != '"') {
00436 pos ++;
00437 if (pos == end) return 0;
00438 }
00439 buffer[pos] = '\0';
00440 switch (type) {
00441 case SSI_TYPE_FILE:
00442 NutSsiProcessFile(stream, filename);
00443 break;
00444 case SSI_TYPE_VIRTUAL:
00445 NutSsiProcessVirtual(stream, filename, http_root, req);
00446 break;
00447 case SSI_TYPE_EXEC:
00448 NutSsiProcessVirtual(stream, filename, http_root, req);
00449 break;
00450 }
00451 }
00452 return 1;
00453 }
00454
00474 static void NutHttpProcessSHTML(FILE * stream, int fd, int file_len, char* http_root, REQUEST *req)
00475 {
00476 char * buffer;
00477 uint8_t in_comment;
00478 int buffsize;
00479 int fpos;
00480 int n;
00481 char *index;
00482 uint8_t found;
00483 buffsize = MIN(BUFSIZE, file_len);
00484 buffer = malloc(buffsize+1);
00485 in_comment = 0;
00486 fpos = 0;
00487 while (file_len != fpos) {
00488 memset(buffer, 0, buffsize+1);
00489 n = _read(fd, buffer, MIN(buffsize, file_len-fpos));
00490
00491 if (!in_comment) {
00492
00493 index = strstr(buffer, "<!--");
00494 if (index == NULL) {
00495 if (file_len > buffsize) {
00496 fwrite(buffer, 1, MIN(buffsize-100, n), stream);
00497 fpos += MIN(buffsize-100, n);
00498 _seek(fd, fpos, SEEK_SET);
00499 } else {
00500 fwrite(buffer, 1, n, stream);
00501 fpos += n;
00502 }
00503
00504 } else {
00505 found = (int)index - (int)buffer;
00506 fwrite (buffer, 1, found, stream);
00507 fpos += found;
00508 _seek(fd, fpos, SEEK_SET);
00509 in_comment = 1;
00510 }
00511 } else {
00512 index = strstr(buffer, "-->");
00513 if (index == NULL) {
00514 fwrite(buffer, 1, MIN(buffsize, n), stream);
00515 fpos += MIN(buffsize, n);
00516 in_comment = 0;
00517 } else {
00518 found = (int)index - (int)buffer;
00519 if (!NutSsiCheckForSsi(stream, buffer, found, http_root, req)) {
00520 fwrite(buffer, 1, found+3, stream);
00521 }
00522 fpos += found+3;
00523 _seek(fd, fpos, SEEK_SET);
00524 in_comment = 0;
00525 }
00526 }
00527 }
00528
00529 free(buffer);
00530 }
00531
00542 void NutRegisterSsi(void)
00543 {
00544 NutSetMimeHandler(".shtml", NutHttpProcessSHTML);
00545 }
00546