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
00077
00078 #include <cfg/arch.h>
00079
00080 #include <io.h>
00081 #include <ctype.h>
00082 #include <stdio.h>
00083 #include <string.h>
00084 #include <stdlib.h>
00085 #if defined(__GNUC__)
00086 #include <alloca.h>
00087 #endif
00088 #include <sys/types.h>
00089 #include <unistd.h>
00090 #include <fcntl.h>
00091
00092 #include <sys/heap.h>
00093 #include <sys/version.h>
00094
00095 #include <pro/httpd.h>
00096 #include <pro/ssi.h>
00097 #include "httpd_p.h"
00098 #include "dencode.h"
00099
00100 #define BUFSIZE 512
00101
00102 #define MIN(a,b) (a<b?a:b)
00103
00104 #define SSI_TYPE_FILE 0x01
00105 #define SSI_TYPE_VIRTUAL 0x02
00106 #define SSI_TYPE_EXEC 0x03
00107
00108 static prog_char rsp_not_found_P[] = "404 Not found: %s\r\n";
00109 static prog_char rsp_intern_err_P[] = "500 Internal error\r\n";
00110 static prog_char rsp_bad_req_P[] = "400 Bad request\r\n";
00111
00112 extern char *cgiBinPath;
00113
00124 static void NutSsiProcessFile(FILE * stream, char *filename)
00125 {
00126 int fd;
00127 int n;
00128 char *data;
00129 int size;
00130 long file_len;
00131
00132 fd = _open(filename, _O_BINARY | _O_RDONLY);
00133
00134 if (fd == -1) {
00135 fprintf_P(stream, rsp_not_found_P, filename);
00136 return;
00137 }
00138
00139 file_len = _filelength(fd);
00140
00141 size = 512;
00142 if ((data = NutHeapAlloc(size)) != 0) {
00143 while (file_len) {
00144 if (file_len < 512L)
00145 size = (int) file_len;
00146
00147 n = _read(fd, data, size);
00148 if (fwrite(data, 1, n, stream) == 0)
00149 break;
00150 file_len -= (long) n;
00151 }
00152 NutHeapFree(data);
00153 }
00154
00155 _close(fd);
00156 }
00157
00158
00172 static void NutSsiProcessVirtual(FILE * stream, char *url, char* http_root, REQUEST *orig_req)
00173 {
00174 int fd;
00175 int i;
00176 int n;
00177 char *data;
00178 int size;
00179 long file_len;
00180 char *filename = NULL;
00181 void (*handler)(FILE *stream, int fd, int file_len, char *http_root, REQUEST *req);
00182 char *cp;
00183 REQUEST * req;
00184 CONST char *cgi_bin = cgiBinPath ? cgiBinPath : "cgi-bin/";
00185 char * tmp;
00186 size_t len;
00187
00188 #ifdef __GNUC__
00189 char * save_ptr = NULL;
00190
00191 tmp = alloca(strlen(cgi_bin) + 1);
00192 strcpy(tmp, cgi_bin);
00193 tmp = strtok_r(tmp, ";", &save_ptr);
00194 #else
00195 tmp = cgi_bin;
00196 #endif
00197
00198 if (NutDecodePath(url) == 0) {
00199 fprintf_P(stream, rsp_bad_req_P);
00200 return;
00201 }
00202
00203
00204
00205
00206 while (tmp) {
00207 #ifdef __GNUC__
00208 len = strlen(tmp);
00209 #else
00210
00211 while (*cgi_bin == ';')
00212 cgi_bin++;
00213
00214 for (len = 0, cp = cgi_bin; *cp && *cp != ';'; len++, cp++);
00215 tmp = cgi_bin;
00216 #endif
00217 if (len && strncasecmp(url, tmp, len) == 0) {
00218 if ((req = NutHeapAllocClear(sizeof(REQUEST))) == 0) {
00219 fprintf_P(stream, rsp_intern_err_P);
00220 return;
00221 }
00222 req->req_method = METHOD_GET;
00223 req->req_version = orig_req->req_version;
00224 req->req_length = 0;
00225
00226 if (orig_req->req_agent != NULL) {
00227 if ((req->req_agent = NutHeapAlloc((strlen(orig_req->req_agent) + 1))) == 0) {
00228 fprintf_P(stream, rsp_intern_err_P);
00229 DestroyRequestInfo(req);
00230 return;
00231 }
00232 strcpy(req->req_agent, orig_req->req_agent);
00233 }
00234 if (orig_req->req_cookie!= NULL) {
00235 if ((req->req_cookie = NutHeapAlloc((strlen(orig_req->req_cookie) + 1))) == 0) {
00236 fprintf_P(stream, rsp_intern_err_P);
00237 DestroyRequestInfo(req);
00238 return;
00239 }
00240 strcpy(req->req_cookie, orig_req->req_cookie);
00241 }
00242 if ((cp = strchr(url, '?')) != 0) {
00243 *cp++ = 0;
00244 if (strcmp(cp, "$QUERY_STRING") == 0) {
00245 u_short size;
00246 size = 0;
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 = NutHeapAlloc(size)) == 0) {
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 = NutHeapAlloc(strlen(cp) + 1)) == 0) {
00268 fprintf_P(stream, rsp_intern_err_P);
00269 DestroyRequestInfo(req);
00270 return;
00271 }
00272 strcpy(req->req_query, cp);
00273 }
00274 NutHttpProcessQueryString(req);
00275 }
00276 if ((req->req_url = NutHeapAlloc(strlen(url) + 1)) == 0) {
00277 fprintf_P(stream, rsp_intern_err_P);
00278 DestroyRequestInfo(req);
00279 return;
00280 }
00281 strcpy(req->req_url, url);
00282
00283 NutCgiProcessRequest(stream, req, len);
00284 DestroyRequestInfo(req);
00285 return;
00286 }
00287 #ifdef __GNUC__
00288 tmp = strtok_r(NULL, ";", &save_ptr);
00289 #else
00290 cgi_bin += len;
00291 if (*cgi_bin == '\0') {
00292 break;
00293 }
00294 #endif
00295 }
00296
00297
00298
00299
00300
00301 for (n = 0, fd = -1; default_files[n]; n++) {
00302 filename = CreateFilePath(url, default_files[n]);
00303 if (filename == NULL) {
00304 fprintf_P(stream, rsp_intern_err_P);
00305 return;
00306 }
00307
00308
00309
00310
00311
00312
00313 if ((fd = _open(filename, _O_BINARY | _O_RDONLY)) != -1) {
00314 if (_filelength(fd)) {
00315 break;
00316 }
00317 _close(fd);
00318 }
00319 NutHeapFree(filename);
00320 }
00321 if (fd == -1) {
00322 fprintf_P(stream, rsp_not_found_P, filename);
00323 return;
00324 }
00325
00326 file_len = _filelength(fd);
00327 handler = NutGetMimeHandler(filename);
00328
00329 if (handler == NULL) {
00330 size = 512;
00331 if ((data = NutHeapAlloc(size)) != 0) {
00332 while (file_len) {
00333 if (file_len < 512L) {
00334 size = (int) file_len;
00335 }
00336
00337 n = _read(fd, data, size);
00338 if (fwrite(data, 1, n, stream) == 0) {
00339 break;
00340 }
00341 file_len -= (long) n;
00342 }
00343 NutHeapFree(data);
00344 }
00345 } else handler(stream, fd, file_len, http_root, orig_req);
00346 _close(fd);
00347 return;
00348 }
00349
00362 static void NutSsiSkipWhitespace(char *buffer, u_short *pos, u_short end)
00363 {
00364 while ((*pos < end) && (
00365 (buffer[*pos] == '\n') || (buffer[*pos] == '\r') ||
00366 (buffer[*pos] == '\t') || (buffer[*pos] == ' ')))
00367 (*pos) ++;
00368 }
00369
00388 static u_char NutSsiCheckForSsi(FILE *stream, char *buffer, u_short end, char* http_root, REQUEST *req)
00389 {
00390 u_short pos = 4;
00391 char * filename;
00392 u_char type;
00393
00394 pos = 4;
00395 NutSsiSkipWhitespace(buffer, &pos, end);
00396 if (pos == end) return 0;
00397
00398 if (strncasecmp(&buffer[pos], "#include", 8) == 0) {
00399 pos += 8;
00400 type = SSI_TYPE_VIRTUAL;
00401 } else
00402 if (strncasecmp(&buffer[pos], "#exec", 5) == 0) {
00403 pos += 5;
00404 type = SSI_TYPE_EXEC;
00405 } else return 0;
00406 if (pos >= end) return 0;
00407
00408 NutSsiSkipWhitespace(buffer, &pos, end);
00409 if (pos == end) return 0;
00410
00411 if (type == SSI_TYPE_VIRTUAL) {
00412 if (strncasecmp(&buffer[pos], "virtual", 7) == 0) {
00413 pos += 7;
00414 } else
00415 if (strncasecmp(&buffer[pos], "file", 4) == 0) {
00416 pos += 4;
00417 type = SSI_TYPE_FILE;
00418 } else return 0;
00419 } else {
00420 if (strncasecmp(&buffer[pos], "cgi", 3) == 0) {
00421 pos += 3;
00422 } else return 0;
00423 }
00424 if (pos >= end) return 0;
00425
00426 NutSsiSkipWhitespace(buffer, &pos, end);
00427 if (pos == end) return 0;
00428
00429 if (buffer[pos] != '=') return 0;
00430 pos ++;
00431
00432 NutSsiSkipWhitespace(buffer, &pos, end);
00433 if (pos == end) return 0;
00434
00435 if (buffer[pos] == '"') {
00436 pos ++;
00437 if (pos == end) return 0;
00438 filename = &buffer[pos];
00439 while (buffer[pos] != '"') {
00440 pos ++;
00441 if (pos == end) return 0;
00442 }
00443 buffer[pos] = '\0';
00444 switch (type) {
00445 case SSI_TYPE_FILE:
00446 NutSsiProcessFile(stream, filename);
00447 break;
00448 case SSI_TYPE_VIRTUAL:
00449 NutSsiProcessVirtual(stream, filename, http_root, req);
00450 break;
00451 case SSI_TYPE_EXEC:
00452 NutSsiProcessVirtual(stream, filename, http_root, req);
00453 break;
00454 }
00455 }
00456 return 1;
00457 }
00458
00478 static void NutHttpProcessSHTML(FILE * stream, int fd, int file_len, char* http_root, REQUEST *req)
00479 {
00480 char * buffer;
00481 u_char in_comment;
00482 int buffsize;
00483 int fpos;
00484 int n;
00485 char *index;
00486 u_char found;
00487 buffsize = MIN(BUFSIZE, file_len);
00488 buffer = NutHeapAlloc(buffsize+1);
00489 in_comment = 0;
00490 fpos = 0;
00491 while (file_len != fpos) {
00492 memset(buffer, 0, buffsize+1);
00493 n = _read(fd, buffer, MIN(buffsize, file_len-fpos));
00494
00495 if (!in_comment) {
00496
00497 index = strstr(buffer, "<!--");
00498 if (index == NULL) {
00499 if (file_len > buffsize) {
00500 fwrite(buffer, 1, MIN(buffsize-100, n), stream);
00501 fpos += MIN(buffsize-100, n);
00502 _seek(fd, fpos, SEEK_SET);
00503 } else {
00504 fwrite(buffer, 1, n, stream);
00505 fpos += n;
00506 }
00507
00508 } else {
00509 found = (int)index - (int)buffer;
00510 fwrite (buffer, 1, found, stream);
00511 fpos += found;
00512 _seek(fd, fpos, SEEK_SET);
00513 in_comment = 1;
00514 }
00515 } else {
00516 index = strstr(buffer, "-->");
00517 if (index == NULL) {
00518 fwrite(buffer, 1, MIN(buffsize, n), stream);
00519 fpos += MIN(buffsize, n);
00520 in_comment = 0;
00521 } else {
00522 found = (int)index - (int)buffer;
00523 if (!NutSsiCheckForSsi(stream, buffer, found, http_root, req)) {
00524 fwrite(buffer, 1, found+3, stream);
00525 }
00526 fpos += found+3;
00527 _seek(fd, fpos, SEEK_SET);
00528 in_comment = 0;
00529 }
00530 }
00531 }
00532
00533 NutHeapFree(buffer);
00534 }
00535
00546 void NutRegisterSsi(void)
00547 {
00548 NutSetMimeHandler(".shtml", NutHttpProcessSHTML);
00549 }
00550