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