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 #include <sys/types.h>
00097
00098 #include <memdebug.h>
00099 #include <string.h>
00100 #include <stdlib.h>
00101
00102 #include <io.h>
00103 #include <ctype.h>
00104 #include <stdio.h>
00105 #include <unistd.h>
00106 #include <fcntl.h>
00107
00108 #include <sys/heap.h>
00109 #include <sys/version.h>
00110
00111 #include <pro/httpd.h>
00112 #include <pro/ssi.h>
00113 #include "httpd_p.h"
00114 #include "dencode.h"
00115
00116 #define BUFSIZE 512
00117
00118 #define MIN(a,b) (a<b?a:b)
00119
00120 #define SSI_TYPE_FILE 0x01
00121 #define SSI_TYPE_VIRTUAL 0x02
00122 #define SSI_TYPE_EXEC 0x03
00123 #define SSI_TYPE_ECHO 0x04
00124
00125 static char * (*ssivar_handler)(char *, REQUEST *);
00126
00127 static prog_char rsp_not_found_P[] = "404 Not found: %s\r\n";
00128 static prog_char rsp_intern_err_P[] = "500 Internal error\r\n";
00129 static prog_char rsp_bad_req_P[] = "400 Bad request\r\n";
00130
00131 extern char *cgiBinPath;
00132
00143 static void NutSsiProcessFile(FILE * stream, char *filename)
00144 {
00145 int fd;
00146 int n;
00147 char *data;
00148 int size;
00149 long file_len;
00150
00151 fd = _open(filename, _O_BINARY | _O_RDONLY);
00152
00153 if (fd == -1) {
00154 fprintf_P(stream, rsp_not_found_P, filename);
00155 return;
00156 }
00157
00158 file_len = _filelength(fd);
00159
00160 size = 512;
00161 if ((data = malloc(size)) != NULL) {
00162 while (file_len) {
00163 if (file_len < 512L)
00164 size = (int) file_len;
00165
00166 n = _read(fd, data, size);
00167 if (fwrite(data, 1, n, stream) == 0)
00168 break;
00169 file_len -= (long) n;
00170 }
00171 free(data);
00172 }
00173
00174 _close(fd);
00175 }
00176
00177
00191 static void NutSsiProcessVirtual(FILE * stream, char *url, char* http_root, REQUEST *orig_req)
00192 {
00193 int fd;
00194 int i;
00195 int n;
00196 char *data;
00197 int size;
00198 long file_len;
00199 char *filename = NULL;
00200 void (*handler)(FILE *stream, int fd, int file_len, char *http_root, REQUEST *req);
00201 char *cp;
00202 REQUEST * req;
00203 CONST char *cgi_bin = cgiBinPath ? cgiBinPath : "cgi-bin/";
00204 CONST char * tmp;
00205 size_t len;
00206
00207 tmp = cgi_bin;
00208 if (NutDecodePath(url) == 0) {
00209 fprintf_P(stream, rsp_bad_req_P);
00210 return;
00211 }
00212
00213
00214
00215
00216 while (tmp) {
00217
00218 while (*cgi_bin == ';')
00219 cgi_bin++;
00220
00221 for (len = 0, cp = (char *)cgi_bin; *cp && *cp != ';'; len++, cp++);
00222 tmp = cgi_bin;
00223 if (len && strncasecmp(url, tmp, len) == 0) {
00224 if ((req = calloc(1, sizeof(REQUEST))) == 0) {
00225 fprintf_P(stream, rsp_intern_err_P);
00226 return;
00227 }
00228 req->req_method = METHOD_GET;
00229 req->req_version = orig_req->req_version;
00230 req->req_length = 0;
00231
00232 if (orig_req->req_agent != NULL) {
00233 if ((req->req_agent = strdup(orig_req->req_agent)) == NULL) {
00234 fprintf_P(stream, rsp_intern_err_P);
00235 DestroyRequestInfo(req);
00236 return;
00237 }
00238 }
00239 if (orig_req->req_cookie!= NULL) {
00240 if ((req->req_cookie = strdup(orig_req->req_cookie)) == NULL) {
00241 fprintf_P(stream, rsp_intern_err_P);
00242 DestroyRequestInfo(req);
00243 return;
00244 }
00245 }
00246 if ((cp = strchr(url, '?')) != 0) {
00247 *cp++ = 0;
00248 if (strcmp(cp, "$QUERY_STRING") == 0) {
00249 uint16_t size;
00250 size = 1;
00251 for (i = 0; i < orig_req->req_numqptrs*2; i ++) {
00252 size += strlen(orig_req->req_qptrs[i]) + 1;
00253 }
00254 if ((req->req_query = malloc(size)) == NULL) {
00255 fprintf_P(stream, rsp_intern_err_P);
00256 DestroyRequestInfo(req);
00257 return;
00258 }
00259 req->req_query[0] = 0;
00260 for (i = 0; i < (orig_req->req_numqptrs * 2); i++) {
00261 if(i) {
00262 strcat (req->req_query, "&");
00263 }
00264 strcat (req->req_query, orig_req->req_qptrs[i]);
00265 strcat (req->req_query, "=");
00266 i++;
00267 strcat (req->req_query, orig_req->req_qptrs[i]);
00268 }
00269
00270 } else {
00271 if ((req->req_query = strdup(cp)) == NULL) {
00272 fprintf_P(stream, rsp_intern_err_P);
00273 DestroyRequestInfo(req);
00274 return;
00275 }
00276 }
00277 NutHttpProcessQueryString(req);
00278 }
00279 if ((req->req_url = strdup(url)) == NULL) {
00280 fprintf_P(stream, rsp_intern_err_P);
00281 DestroyRequestInfo(req);
00282 return;
00283 }
00284 NutCgiProcessRequest(stream, req, len);
00285 DestroyRequestInfo(req);
00286 return;
00287 }
00288 cgi_bin += len;
00289 if (*cgi_bin == '\0') {
00290 break;
00291 }
00292 }
00293
00294
00295
00296
00297
00298 for (n = 0, fd = -1; default_files[n]; n++) {
00299 filename = CreateFilePath(url, default_files[n]);
00300 if (filename == NULL) {
00301 fprintf_P(stream, rsp_intern_err_P);
00302 return;
00303 }
00304
00305
00306
00307
00308
00309
00310 if ((fd = _open(filename, _O_BINARY | _O_RDONLY)) != -1) {
00311 if (_filelength(fd)) {
00312 break;
00313 }
00314 _close(fd);
00315 }
00316 free(filename);
00317 }
00318 if (fd == -1) {
00319 fprintf_P(stream, rsp_not_found_P, url);
00320 return;
00321 }
00322
00323 file_len = _filelength(fd);
00324 handler = NutGetMimeHandler(filename);
00325 free(filename);
00326
00327 if (handler == NULL) {
00328 size = 512;
00329 if ((data = malloc(size)) != NULL) {
00330 while (file_len) {
00331 if (file_len < 512L) {
00332 size = (int) file_len;
00333 }
00334
00335 n = _read(fd, data, size);
00336 if (fwrite(data, 1, n, stream) == 0) {
00337 break;
00338 }
00339 file_len -= (long) n;
00340 }
00341 free(data);
00342 }
00343 } else handler(stream, fd, file_len, http_root, orig_req);
00344 _close(fd);
00345 return;
00346 }
00347
00355 static void NutSsiProcessEcho(FILE * stream, char *name, REQUEST *req)
00356 {
00357 if (ssivar_handler) {
00358 char *value = (*ssivar_handler)(name, req);
00359
00360 if (value) {
00361 fputs(value, stream);
00362 }
00363 }
00364 }
00365
00378 static void NutSsiSkipWhitespace(char *buffer, uint16_t *pos, uint16_t end)
00379 {
00380 while ((*pos < end) && (
00381 (buffer[*pos] == '\n') || (buffer[*pos] == '\r') ||
00382 (buffer[*pos] == '\t') || (buffer[*pos] == ' ')))
00383 (*pos) ++;
00384 }
00385
00404 static uint8_t NutSsiCheckForSsi(FILE *stream, char *buffer, uint16_t end, char* http_root, REQUEST *req)
00405 {
00406 uint16_t pos = 4;
00407 char * filename;
00408 uint8_t type;
00409
00410 pos = 4;
00411 NutSsiSkipWhitespace(buffer, &pos, end);
00412 if (pos == end) return 0;
00413
00414 if (strncasecmp(&buffer[pos], "#include", 8) == 0) {
00415 pos += 8;
00416 type = SSI_TYPE_VIRTUAL;
00417 } else
00418 if (strncasecmp(&buffer[pos], "#exec", 5) == 0) {
00419 pos += 5;
00420 type = SSI_TYPE_EXEC;
00421 } else
00422 if (strncasecmp(&buffer[pos], "#echo", 5) == 0) {
00423 pos += 5;
00424 type = SSI_TYPE_ECHO;
00425 } else return 0;
00426 if (pos >= end) return 0;
00427
00428 NutSsiSkipWhitespace(buffer, &pos, end);
00429 if (pos == end) return 0;
00430
00431 if (type == SSI_TYPE_VIRTUAL) {
00432 if (strncasecmp(&buffer[pos], "virtual", 7) == 0) {
00433 pos += 7;
00434 } else
00435 if (strncasecmp(&buffer[pos], "file", 4) == 0) {
00436 pos += 4;
00437 type = SSI_TYPE_FILE;
00438 } else return 0;
00439 }
00440 else if (type == SSI_TYPE_ECHO) {
00441 if (strncasecmp(&buffer[pos], "var", 3) == 0) {
00442 pos += 3;
00443 } else return 0;
00444 } else {
00445 if (strncasecmp(&buffer[pos], "cgi", 3) == 0) {
00446 pos += 3;
00447 } else return 0;
00448 }
00449 if (pos >= end) return 0;
00450
00451 NutSsiSkipWhitespace(buffer, &pos, end);
00452 if (pos == end) return 0;
00453
00454 if (buffer[pos] != '=') return 0;
00455 pos ++;
00456
00457 NutSsiSkipWhitespace(buffer, &pos, end);
00458 if (pos == end) return 0;
00459
00460 if (buffer[pos] == '"') {
00461 pos ++;
00462 if (pos == end) return 0;
00463 filename = &buffer[pos];
00464 while (buffer[pos] != '"') {
00465 pos ++;
00466 if (pos == end) return 0;
00467 }
00468 buffer[pos] = '\0';
00469 switch (type) {
00470 case SSI_TYPE_FILE:
00471 NutSsiProcessFile(stream, filename);
00472 break;
00473 case SSI_TYPE_VIRTUAL:
00474 NutSsiProcessVirtual(stream, filename, http_root, req);
00475 break;
00476 case SSI_TYPE_EXEC:
00477 NutSsiProcessVirtual(stream, filename, http_root, req);
00478 break;
00479 case SSI_TYPE_ECHO:
00480 NutSsiProcessEcho(stream, filename, req);
00481 break;
00482 }
00483 }
00484 return 1;
00485 }
00486
00506 static void NutHttpProcessSHTML(FILE * stream, int fd, int file_len, char* http_root, REQUEST *req)
00507 {
00508 char * buffer;
00509 uint8_t in_comment;
00510 int buffsize;
00511 int fpos;
00512 int n;
00513 char *index;
00514 uint8_t found;
00515 buffsize = MIN(BUFSIZE, file_len);
00516 buffer = malloc(buffsize+1);
00517 in_comment = 0;
00518 fpos = 0;
00519 while (file_len != fpos) {
00520 memset(buffer, 0, buffsize+1);
00521 n = _read(fd, buffer, MIN(buffsize, file_len-fpos));
00522
00523 if (!in_comment) {
00524
00525 index = strstr(buffer, "<!--");
00526 if (index == NULL) {
00527 if (file_len > buffsize) {
00528 fwrite(buffer, 1, MIN(buffsize-100, n), stream);
00529 fpos += MIN(buffsize-100, n);
00530 _seek(fd, fpos, SEEK_SET);
00531 } else {
00532 fwrite(buffer, 1, n, stream);
00533 fpos += n;
00534 }
00535
00536 } else {
00537 found = (int)index - (int)buffer;
00538 fwrite (buffer, 1, found, stream);
00539 fpos += found;
00540 _seek(fd, fpos, SEEK_SET);
00541 in_comment = 1;
00542 }
00543 } else {
00544 index = strstr(buffer, "-->");
00545 if (index == NULL) {
00546 fwrite(buffer, 1, MIN(buffsize, n), stream);
00547 fpos += MIN(buffsize, n);
00548 in_comment = 0;
00549 } else {
00550 found = (int)index - (int)buffer;
00551 if (!NutSsiCheckForSsi(stream, buffer, found, http_root, req)) {
00552 fwrite(buffer, 1, found+3, stream);
00553 }
00554 fpos += found+3;
00555 _seek(fd, fpos, SEEK_SET);
00556 in_comment = 0;
00557 }
00558 }
00559 }
00560
00561 free(buffer);
00562 }
00563
00575 void NutRegisterSsi(void)
00576 {
00577 NutSetMimeHandler(".shtml", NutHttpProcessSHTML);
00578 }
00579
00583 int NutRegisterSsiVarHandler(char * (*handler)(char *name, REQUEST *req))
00584 {
00585 ssivar_handler = handler;
00586
00587 return 0;
00588 }
00589