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