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
00083
00084 #include <sys/heap.h>
00085 #include <sys/version.h>
00086
00087 #include <cfg/arch.h>
00088
00089 #include <io.h>
00090 #include <ctype.h>
00091 #include <stdio.h>
00092 #include <string.h>
00093 #include <stdlib.h>
00094 #include <sys/types.h>
00095 #include <unistd.h>
00096 #include <fcntl.h>
00097
00098 #include <pro/httpd.h>
00099 #include <pro/ssi.h>
00100 #include "httpd_p.h"
00101 #include "dencode.h"
00102
00103 #define BUFSIZE 512
00104
00105 #define MIN(a,b) (a<b?a:b)
00106
00107 #define SSI_TYPE_FILE 0x01
00108 #define SSI_TYPE_VIRTUAL 0x02
00109 #define SSI_TYPE_EXEC 0x03
00110
00111 static prog_char rsp_not_found_P[] = "404 Not found: %s\r\n";
00112 static prog_char rsp_intern_err_P[] = "500 Internal error\r\n";
00113 static prog_char rsp_bad_req_P[] = "400 Bad request\r\n";
00114
00115 extern char *cgiBinPath;
00116
00127 static void NutSsiProcessFile(FILE * stream, char *filename)
00128 {
00129 int fd;
00130 int n;
00131 char *data;
00132 int size;
00133 long file_len;
00134
00135 fd = _open(filename, _O_BINARY | _O_RDONLY);
00136
00137 if (fd == -1) {
00138 fprintf_P(stream, rsp_not_found_P, filename);
00139 return;
00140 }
00141
00142 file_len = _filelength(fd);
00143
00144 size = 512;
00145 if ((data = NutHeapAlloc(size)) != 0) {
00146 while (file_len) {
00147 if (file_len < 512L)
00148 size = (int) file_len;
00149
00150 n = _read(fd, data, size);
00151 if (fwrite(data, 1, n, stream) == 0)
00152 break;
00153 file_len -= (long) n;
00154 }
00155 NutHeapFree(data);
00156 }
00157
00158 _close(fd);
00159 }
00160
00161
00175 static void NutSsiProcessVirtual(FILE * stream, char *url, char* http_root, REQUEST *orig_req)
00176 {
00177 int fd;
00178 int i;
00179 int n;
00180 char *data;
00181 int size;
00182 long file_len;
00183 char *filename = NULL;
00184 void (*handler)(FILE *stream, int fd, int file_len, char *http_root, REQUEST *req);
00185 char *cp;
00186 REQUEST * req;
00187 CONST char *cgi_bin = cgiBinPath ? cgiBinPath : "cgi-bin/";
00188 CONST char * tmp;
00189 size_t len;
00190
00191 tmp = cgi_bin;
00192 if (NutDecodePath(url) == 0) {
00193 fprintf_P(stream, rsp_bad_req_P);
00194 return;
00195 }
00196
00197
00198
00199
00200 while (tmp) {
00201
00202 while (*cgi_bin == ';')
00203 cgi_bin++;
00204
00205 for (len = 0, cp = (char *)cgi_bin; *cp && *cp != ';'; len++, cp++);
00206 tmp = cgi_bin;
00207 if (len && strncasecmp(url, tmp, len) == 0) {
00208 if ((req = NutHeapAllocClear(sizeof(REQUEST))) == 0) {
00209 fprintf_P(stream, rsp_intern_err_P);
00210 return;
00211 }
00212 req->req_method = METHOD_GET;
00213 req->req_version = orig_req->req_version;
00214 req->req_length = 0;
00215
00216 if (orig_req->req_agent != NULL) {
00217 if ((req->req_agent = NutHeapAlloc((strlen(orig_req->req_agent) + 1))) == 0) {
00218 fprintf_P(stream, rsp_intern_err_P);
00219 DestroyRequestInfo(req);
00220 return;
00221 }
00222 strcpy(req->req_agent, orig_req->req_agent);
00223 }
00224 if (orig_req->req_cookie!= NULL) {
00225 if ((req->req_cookie = NutHeapAlloc((strlen(orig_req->req_cookie) + 1))) == 0) {
00226 fprintf_P(stream, rsp_intern_err_P);
00227 DestroyRequestInfo(req);
00228 return;
00229 }
00230 strcpy(req->req_cookie, orig_req->req_cookie);
00231 }
00232 if ((cp = strchr(url, '?')) != 0) {
00233 *cp++ = 0;
00234 if (strcmp(cp, "$QUERY_STRING") == 0) {
00235 u_short size;
00236 size = 1;
00237 for (i = 0; i < orig_req->req_numqptrs*2; i ++) {
00238 size += strlen(orig_req->req_qptrs[i]) + 1;
00239 }
00240 if ((req->req_query = NutHeapAlloc(size)) == 0) {
00241 fprintf_P(stream, rsp_intern_err_P);
00242 DestroyRequestInfo(req);
00243 return;
00244 }
00245 req->req_query[0] = 0;
00246 for (i = 0; i < (orig_req->req_numqptrs * 2); i++) {
00247 if(i) {
00248 strcat (req->req_query, "&");
00249 }
00250 strcat (req->req_query, orig_req->req_qptrs[i]);
00251 strcat (req->req_query, "=");
00252 i++;
00253 strcat (req->req_query, orig_req->req_qptrs[i]);
00254 }
00255
00256 } else {
00257 if ((req->req_query = NutHeapAlloc(strlen(cp) + 1)) == 0) {
00258 fprintf_P(stream, rsp_intern_err_P);
00259 DestroyRequestInfo(req);
00260 return;
00261 }
00262 strcpy(req->req_query, cp);
00263 }
00264 NutHttpProcessQueryString(req);
00265 }
00266 if ((req->req_url = NutHeapAlloc(strlen(url) + 1)) == 0) {
00267 fprintf_P(stream, rsp_intern_err_P);
00268 DestroyRequestInfo(req);
00269 return;
00270 }
00271 strcpy(req->req_url, url);
00272
00273 NutCgiProcessRequest(stream, req, len);
00274 DestroyRequestInfo(req);
00275 return;
00276 }
00277 cgi_bin += len;
00278 if (*cgi_bin == '\0') {
00279 break;
00280 }
00281 }
00282
00283
00284
00285
00286
00287 for (n = 0, fd = -1; default_files[n]; n++) {
00288 filename = CreateFilePath(url, default_files[n]);
00289 if (filename == NULL) {
00290 fprintf_P(stream, rsp_intern_err_P);
00291 return;
00292 }
00293
00294
00295
00296
00297
00298
00299 if ((fd = _open(filename, _O_BINARY | _O_RDONLY)) != -1) {
00300 if (_filelength(fd)) {
00301 break;
00302 }
00303 _close(fd);
00304 }
00305 NutHeapFree(filename);
00306 }
00307 if (fd == -1) {
00308 fprintf_P(stream, rsp_not_found_P, filename);
00309 NutHeapFree(filename);
00310 return;
00311 }
00312
00313 file_len = _filelength(fd);
00314 handler = NutGetMimeHandler(filename);
00315 NutHeapFree(filename);
00316
00317 if (handler == NULL) {
00318 size = 512;
00319 if ((data = NutHeapAlloc(size)) != 0) {
00320 while (file_len) {
00321 if (file_len < 512L) {
00322 size = (int) file_len;
00323 }
00324
00325 n = _read(fd, data, size);
00326 if (fwrite(data, 1, n, stream) == 0) {
00327 break;
00328 }
00329 file_len -= (long) n;
00330 }
00331 NutHeapFree(data);
00332 }
00333 } else handler(stream, fd, file_len, http_root, orig_req);
00334 _close(fd);
00335 return;
00336 }
00337
00350 static void NutSsiSkipWhitespace(char *buffer, u_short *pos, u_short end)
00351 {
00352 while ((*pos < end) && (
00353 (buffer[*pos] == '\n') || (buffer[*pos] == '\r') ||
00354 (buffer[*pos] == '\t') || (buffer[*pos] == ' ')))
00355 (*pos) ++;
00356 }
00357
00376 static u_char NutSsiCheckForSsi(FILE *stream, char *buffer, u_short end, char* http_root, REQUEST *req)
00377 {
00378 u_short pos = 4;
00379 char * filename;
00380 u_char type;
00381
00382 pos = 4;
00383 NutSsiSkipWhitespace(buffer, &pos, end);
00384 if (pos == end) return 0;
00385
00386 if (strncasecmp(&buffer[pos], "#include", 8) == 0) {
00387 pos += 8;
00388 type = SSI_TYPE_VIRTUAL;
00389 } else
00390 if (strncasecmp(&buffer[pos], "#exec", 5) == 0) {
00391 pos += 5;
00392 type = SSI_TYPE_EXEC;
00393 } else return 0;
00394 if (pos >= end) return 0;
00395
00396 NutSsiSkipWhitespace(buffer, &pos, end);
00397 if (pos == end) return 0;
00398
00399 if (type == SSI_TYPE_VIRTUAL) {
00400 if (strncasecmp(&buffer[pos], "virtual", 7) == 0) {
00401 pos += 7;
00402 } else
00403 if (strncasecmp(&buffer[pos], "file", 4) == 0) {
00404 pos += 4;
00405 type = SSI_TYPE_FILE;
00406 } else return 0;
00407 } else {
00408 if (strncasecmp(&buffer[pos], "cgi", 3) == 0) {
00409 pos += 3;
00410 } else return 0;
00411 }
00412 if (pos >= end) return 0;
00413
00414 NutSsiSkipWhitespace(buffer, &pos, end);
00415 if (pos == end) return 0;
00416
00417 if (buffer[pos] != '=') return 0;
00418 pos ++;
00419
00420 NutSsiSkipWhitespace(buffer, &pos, end);
00421 if (pos == end) return 0;
00422
00423 if (buffer[pos] == '"') {
00424 pos ++;
00425 if (pos == end) return 0;
00426 filename = &buffer[pos];
00427 while (buffer[pos] != '"') {
00428 pos ++;
00429 if (pos == end) return 0;
00430 }
00431 buffer[pos] = '\0';
00432 switch (type) {
00433 case SSI_TYPE_FILE:
00434 NutSsiProcessFile(stream, filename);
00435 break;
00436 case SSI_TYPE_VIRTUAL:
00437 NutSsiProcessVirtual(stream, filename, http_root, req);
00438 break;
00439 case SSI_TYPE_EXEC:
00440 NutSsiProcessVirtual(stream, filename, http_root, req);
00441 break;
00442 }
00443 }
00444 return 1;
00445 }
00446
00466 static void NutHttpProcessSHTML(FILE * stream, int fd, int file_len, char* http_root, REQUEST *req)
00467 {
00468 char * buffer;
00469 u_char in_comment;
00470 int buffsize;
00471 int fpos;
00472 int n;
00473 char *index;
00474 u_char found;
00475 buffsize = MIN(BUFSIZE, file_len);
00476 buffer = NutHeapAlloc(buffsize+1);
00477 in_comment = 0;
00478 fpos = 0;
00479 while (file_len != fpos) {
00480 memset(buffer, 0, buffsize+1);
00481 n = _read(fd, buffer, MIN(buffsize, file_len-fpos));
00482
00483 if (!in_comment) {
00484
00485 index = strstr(buffer, "<!--");
00486 if (index == NULL) {
00487 if (file_len > buffsize) {
00488 fwrite(buffer, 1, MIN(buffsize-100, n), stream);
00489 fpos += MIN(buffsize-100, n);
00490 _seek(fd, fpos, SEEK_SET);
00491 } else {
00492 fwrite(buffer, 1, n, stream);
00493 fpos += n;
00494 }
00495
00496 } else {
00497 found = (int)index - (int)buffer;
00498 fwrite (buffer, 1, found, stream);
00499 fpos += found;
00500 _seek(fd, fpos, SEEK_SET);
00501 in_comment = 1;
00502 }
00503 } else {
00504 index = strstr(buffer, "-->");
00505 if (index == NULL) {
00506 fwrite(buffer, 1, MIN(buffsize, n), stream);
00507 fpos += MIN(buffsize, n);
00508 in_comment = 0;
00509 } else {
00510 found = (int)index - (int)buffer;
00511 if (!NutSsiCheckForSsi(stream, buffer, found, http_root, req)) {
00512 fwrite(buffer, 1, found+3, stream);
00513 }
00514 fpos += found+3;
00515 _seek(fd, fpos, SEEK_SET);
00516 in_comment = 0;
00517 }
00518 }
00519 }
00520
00521 NutHeapFree(buffer);
00522 }
00523
00534 void NutRegisterSsi(void)
00535 {
00536 NutSetMimeHandler(".shtml", NutHttpProcessSHTML);
00537 }
00538