00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <ctype.h>
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #include <time.h>
00028
00029 #if defined(_WIN32)
00030 #else
00031 #include <unistd.h>
00032 #include <sys/file.h>
00033 #endif
00034
00035 #include "config.h"
00036 #include "httpd.h"
00037 #include "httpd_priv.h"
00038
00039 int _httpd_net_read(sock, buf, len)
00040 int sock;
00041 char *buf;
00042 int len;
00043 {
00044 #if defined(_WIN32)
00045 return( recv(sock, buf, len, 0));
00046 #else
00047
00048
00049
00050 int nfds;
00051 fd_set readfds;
00052 struct timeval timeout;
00053
00054 FD_ZERO(&readfds);
00055 FD_SET(sock, &readfds);
00056 timeout.tv_sec = 10;
00057 timeout.tv_usec = 0;
00058 nfds = sock + 1;
00059
00060 nfds = select(nfds, &readfds, NULL, NULL, &timeout);
00061
00062 if (nfds > 0) {
00063 return(read(sock, buf, len));
00064 }
00065 return(nfds);
00066 #endif
00067 }
00068
00069
00070 int _httpd_net_write(sock, buf, len)
00071 int sock;
00072 char *buf;
00073 int len;
00074 {
00075 #if defined(_WIN32)
00076 return( send(sock, buf, len, 0));
00077 #else
00078 return( write(sock, buf, len));
00079 #endif
00080 }
00081
00082 int _httpd_readChar(request *r, char *cp)
00083 {
00084 if (r->readBufRemain == 0)
00085 {
00086 bzero(r->readBuf, HTTP_READ_BUF_LEN + 1);
00087 r->readBufRemain = _httpd_net_read(r->clientSock,
00088 r->readBuf, HTTP_READ_BUF_LEN);
00089 if (r->readBufRemain < 1)
00090 return(0);
00091 r->readBuf[r->readBufRemain] = 0;
00092 r->readBufPtr = r->readBuf;
00093 }
00094 *cp = *r->readBufPtr++;
00095 r->readBufRemain--;
00096 return(1);
00097 }
00098
00099
00100 int _httpd_readLine(request *r, char *destBuf, int len)
00101 {
00102 char curChar,
00103 *dst;
00104 int count;
00105
00106
00107 count = 0;
00108 dst = destBuf;
00109 while(count < len)
00110 {
00111 if (_httpd_readChar(r, &curChar) < 1)
00112 return(0);
00113
00114
00115 if (curChar == '\n' || !isascii(curChar))
00116 {
00117 *dst = 0;
00118 return(1);
00119 }
00120 if (curChar == '\r')
00121 {
00122 continue;
00123 }
00124 else
00125 {
00126 *dst++ = curChar;
00127 count++;
00128 }
00129 }
00130 *dst = 0;
00131 return(1);
00132 }
00133
00134
00135 int _httpd_readBuf(request *r, char *destBuf, int len)
00136 {
00137 char curChar,
00138 *dst;
00139 int count;
00140
00141
00142 count = 0;
00143 dst = destBuf;
00144 while(count < len)
00145 {
00146 if (_httpd_readChar(r, &curChar) < 1)
00147 return(0);
00148 *dst++ = curChar;
00149 count++;
00150 }
00151 return(1);
00152 }
00153
00154 void _httpd_writeAccessLog(httpd *server, request *r)
00155 {
00156 char dateBuf[30];
00157 struct tm *timePtr;
00158 time_t clock;
00159 int responseCode;
00160
00161
00162 if (server->accessLog == NULL)
00163 return;
00164 clock = time(NULL);
00165 timePtr = localtime(&clock);
00166 strftime(dateBuf, 30, "%d/%b/%Y:%T %Z", timePtr);
00167 responseCode = atoi(r->response.response);
00168 fprintf(server->accessLog, "%s - - [%s] %s \"%s\" %d %d\n",
00169 r->clientAddr, dateBuf, httpdRequestMethodName(r),
00170 httpdRequestPath(r), responseCode,
00171 r->response.responseLength);
00172 }
00173
00174 void _httpd_writeErrorLog(httpd *server, request *r, char *level, char *message)
00175 {
00176 char dateBuf[30];
00177 struct tm *timePtr;
00178 time_t clock;
00179
00180
00181 if (server->errorLog == NULL)
00182 return;
00183 clock = time(NULL);
00184 timePtr = localtime(&clock);
00185 strftime(dateBuf, 30, "%a %b %d %T %Y", timePtr);
00186 if (r != NULL && *r->clientAddr != 0)
00187 {
00188 fprintf(server->errorLog, "[%s] [%s] [client %s] %s\n",
00189 dateBuf, level, r->clientAddr, message);
00190 }
00191 else
00192 {
00193 fprintf(server->errorLog, "[%s] [%s] %s\n",
00194 dateBuf, level, message);
00195 }
00196 }
00197
00198
00199
00200 int _httpd_decode (bufcoded, bufplain, outbufsize)
00201 char * bufcoded;
00202 char * bufplain;
00203 int outbufsize;
00204 {
00205 static char six2pr[64] = {
00206 'A','B','C','D','E','F','G','H','I','J','K','L','M',
00207 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
00208 'a','b','c','d','e','f','g','h','i','j','k','l','m',
00209 'n','o','p','q','r','s','t','u','v','w','x','y','z',
00210 '0','1','2','3','4','5','6','7','8','9','+','/'
00211 };
00212
00213 static unsigned char pr2six[256];
00214
00215
00216 # define DEC(c) pr2six[(int)c]
00217 # define _DECODE_MAXVAL 63
00218
00219 static int first = 1;
00220
00221 int nbytesdecoded, j;
00222 register char *bufin = bufcoded;
00223 register char *bufout = bufplain;
00224 register int nprbytes;
00225
00226
00227
00228
00229
00230 if(first)
00231 {
00232 first = 0;
00233 for(j=0; j<256; j++) pr2six[j] = _DECODE_MAXVAL+1;
00234 for(j=0; j<64; j++) pr2six[(int)six2pr[j]] = (unsigned char)j;
00235 }
00236
00237
00238
00239 while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
00240
00241
00242
00243
00244
00245
00246 bufin = bufcoded;
00247 while(pr2six[(int)*(bufin++)] <= _DECODE_MAXVAL);
00248 nprbytes = bufin - bufcoded - 1;
00249 nbytesdecoded = ((nprbytes+3)/4) * 3;
00250 if(nbytesdecoded > outbufsize)
00251 {
00252 nprbytes = (outbufsize*4)/3;
00253 }
00254 bufin = bufcoded;
00255
00256 while (nprbytes > 0)
00257 {
00258 *(bufout++)=(DEC(*bufin)<<2|DEC(bufin[1])>>4);
00259 *(bufout++)=(DEC(bufin[1])<<4|DEC(bufin[2])>>2);
00260 *(bufout++)=(DEC(bufin[2])<<6|DEC(bufin[3]));
00261 bufin += 4;
00262 nprbytes -= 4;
00263 }
00264 if(nprbytes & 03)
00265 {
00266 if(pr2six[(int)bufin[-2]] > _DECODE_MAXVAL)
00267 {
00268 nbytesdecoded -= 2;
00269 }
00270 else
00271 {
00272 nbytesdecoded -= 1;
00273 }
00274 }
00275 bufplain[nbytesdecoded] = 0;
00276 return(nbytesdecoded);
00277 }
00278
00279
00280
00281 char _httpd_from_hex (c)
00282 char c;
00283 {
00284 return c >= '0' && c <= '9' ? c - '0'
00285 : c >= 'A' && c <= 'F'? c - 'A' + 10
00286 : c - 'a' + 10;
00287 }
00288
00289 char * _httpd_unescape(str)
00290 char *str;
00291 {
00292 char * p = str;
00293 char * q = str;
00294 static char blank[] = "";
00295
00296 if (!str)
00297 return(blank);
00298 while(*p) {
00299 if (*p == '%') {
00300 p++;
00301 if (*p) *q = _httpd_from_hex(*p++) * 16;
00302 if (*p) *q = (*q + _httpd_from_hex(*p++));
00303 q++;
00304 } else {
00305 if (*p == '+') {
00306 *q++ = ' ';
00307 p++;
00308 } else {
00309 *q++ = *p++;
00310 }
00311 }
00312 }
00313
00314 *q++ = 0;
00315 return str;
00316 }
00317
00318
00319 void _httpd_freeVariables(var)
00320 httpVar *var;
00321 {
00322 httpVar *curVar, *lastVar;
00323
00324 if (var == NULL)
00325 return;
00326 _httpd_freeVariables(var->nextVariable);
00327 var->nextVariable = NULL;
00328 curVar = var;
00329 while(curVar)
00330 {
00331 lastVar = curVar;
00332 curVar = curVar->nextValue;
00333 free(lastVar->name);
00334 free(lastVar->value);
00335 free(lastVar);
00336 }
00337 return;
00338 }
00339
00340 void _httpd_storeData(request *r, char *query)
00341 {
00342 char *cp,
00343 *cp2,
00344 *var,
00345 *val,
00346 *tmpVal;
00347
00348 if (!query)
00349 return;
00350
00351 var = (char *)malloc(strlen(query));
00352
00353 cp = query;
00354 cp2 = var;
00355 bzero(var, strlen(query));
00356 val = NULL;
00357 while(*cp)
00358 {
00359 if (*cp == '=')
00360 {
00361 cp++;
00362 *cp2 = 0;
00363 val = cp;
00364 continue;
00365 }
00366 if (*cp == '&')
00367 {
00368 *cp = 0;
00369 tmpVal = _httpd_unescape(val);
00370 httpdAddVariable(r, var, tmpVal);
00371 cp++;
00372 cp2 = var;
00373 val = NULL;
00374 continue;
00375 }
00376 if (val)
00377 {
00378 cp++;
00379 }
00380 else
00381 {
00382 *cp2 = *cp++;
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 cp2++;
00393
00394
00395
00396 }
00397 }
00398 if (val != NULL) {
00399 *cp = 0;
00400 tmpVal = _httpd_unescape(val);
00401 httpdAddVariable(r, var, tmpVal);
00402 }
00403 free(var);
00404 }
00405
00406
00407 void _httpd_formatTimeString(char *ptr, int clock)
00408 {
00409 struct tm *timePtr;
00410
00411 if (clock == 0)
00412 clock = time(NULL);
00413 timePtr = gmtime((time_t*)&clock);
00414 strftime(ptr, HTTP_TIME_STRING_LEN,"%a, %d %b %Y %T GMT",timePtr);
00415 }
00416
00417
00418 void _httpd_sendHeaders(request *r, int contentLength, int modTime)
00419 {
00420 char tmpBuf[80],
00421 timeBuf[HTTP_TIME_STRING_LEN];
00422
00423 if(r->response.headersSent)
00424 return;
00425
00426 r->response.headersSent = 1;
00427 _httpd_net_write(r->clientSock, "HTTP/1.0 ", 9);
00428 _httpd_net_write(r->clientSock, r->response.response,
00429 strlen(r->response.response));
00430 _httpd_net_write(r->clientSock, r->response.headers,
00431 strlen(r->response.headers));
00432
00433 _httpd_formatTimeString(timeBuf, 0);
00434 _httpd_net_write(r->clientSock,"Date: ", 6);
00435 _httpd_net_write(r->clientSock, timeBuf, strlen(timeBuf));
00436 _httpd_net_write(r->clientSock, "\n", 1);
00437
00438 _httpd_net_write(r->clientSock, "Connection: close\n", 18);
00439 _httpd_net_write(r->clientSock, "Content-Type: ", 14);
00440 _httpd_net_write(r->clientSock, r->response.contentType,
00441 strlen(r->response.contentType));
00442 _httpd_net_write(r->clientSock, "\n", 1);
00443
00444 if (contentLength > 0)
00445 {
00446 _httpd_net_write(r->clientSock, "Content-Length: ", 16);
00447 snprintf(tmpBuf, sizeof(tmpBuf), "%d", contentLength);
00448 _httpd_net_write(r->clientSock, tmpBuf, strlen(tmpBuf));
00449 _httpd_net_write(r->clientSock, "\n", 1);
00450
00451 _httpd_formatTimeString(timeBuf, modTime);
00452 _httpd_net_write(r->clientSock, "Last-Modified: ", 15);
00453 _httpd_net_write(r->clientSock, timeBuf, strlen(timeBuf));
00454 _httpd_net_write(r->clientSock, "\n", 1);
00455 }
00456 _httpd_net_write(r->clientSock, "\n", 1);
00457 }
00458
00459 httpDir *_httpd_findContentDir(server, dir, createFlag)
00460 httpd *server;
00461 char *dir;
00462 int createFlag;
00463 {
00464 char buffer[HTTP_MAX_URL],
00465 *curDir;
00466 httpDir *curItem,
00467 *curChild;
00468
00469 strncpy(buffer, dir, HTTP_MAX_URL);
00470 curItem = server->content;
00471 curDir = strtok(buffer,"/");
00472 while(curDir)
00473 {
00474 curChild = curItem->children;
00475 while(curChild)
00476 {
00477 if (strcmp(curChild->name, curDir) == 0)
00478 break;
00479 curChild = curChild->next;
00480 }
00481 if (curChild == NULL)
00482 {
00483 if (createFlag == HTTP_TRUE)
00484 {
00485 curChild = malloc(sizeof(httpDir));
00486 bzero(curChild, sizeof(httpDir));
00487 curChild->name = strdup(curDir);
00488 curChild->next = curItem->children;
00489 curItem->children = curChild;
00490 }
00491 else
00492 {
00493 return(NULL);
00494 }
00495 }
00496 curItem = curChild;
00497 curDir = strtok(NULL,"/");
00498 }
00499 return(curItem);
00500 }
00501
00502
00503 httpContent *_httpd_findContentEntry(request *r, httpDir *dir, char *entryName)
00504 {
00505 httpContent *curEntry;
00506
00507 curEntry = dir->entries;
00508 while(curEntry)
00509 {
00510 if (curEntry->type == HTTP_WILDCARD ||
00511 curEntry->type ==HTTP_C_WILDCARD)
00512 break;
00513 if (*entryName == 0 && curEntry->indexFlag)
00514 break;
00515 if (strcmp(curEntry->name, entryName) == 0)
00516 break;
00517 curEntry = curEntry->next;
00518 }
00519 if (curEntry)
00520 r->response.content = curEntry;
00521 return(curEntry);
00522 }
00523
00524
00525 void _httpd_send304(request *r)
00526 {
00527 httpdSetResponse(r, "304 Not Modified\n");
00528 _httpd_sendHeaders(r,0,0);
00529 }
00530
00531
00532 void _httpd_send403(request *r)
00533 {
00534 httpdSetResponse(r, "403 Permission Denied\n");
00535 _httpd_sendHeaders(r,0,0);
00536 _httpd_sendText(r,
00537 "<HTML><HEAD><TITLE>403 Permission Denied</TITLE></HEAD>\n");
00538 _httpd_sendText(r,
00539 "<BODY><H1>Access to the request URL was denied!</H1>\n");
00540 }
00541
00542
00543 void _httpd_send404(httpd *server, request *r)
00544 {
00545 char msg[HTTP_MAX_URL];
00546
00547 snprintf(msg, HTTP_MAX_URL,
00548 "File does not exist: %s\n", r->request.path);
00549 _httpd_writeErrorLog(server, r, LEVEL_ERROR, msg);
00550
00551 if (server->handle404 && server->handle404->function) {
00552
00553
00554
00555 (server->handle404->function)(server, r);
00556 }
00557 else {
00558
00559
00560
00561 httpdSetResponse(r, "404 Not Found\n");
00562 _httpd_sendHeaders(r,0,0);
00563 _httpd_sendText(r,
00564 "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
00565 _httpd_sendText(r,
00566 "<BODY><H1>The request URL was not found!</H1>\n");
00567 _httpd_sendText(r, "</BODY></HTML>\n");
00568 }
00569 }
00570
00571
00572 void _httpd_catFile(request *r, char *path)
00573 {
00574 int fd,
00575 len;
00576 char buf[HTTP_MAX_LEN];
00577
00578 fd = open(path,O_RDONLY);
00579 if (fd < 0)
00580 return;
00581 len = read(fd, buf, HTTP_MAX_LEN);
00582 while(len > 0)
00583 {
00584 r->response.responseLength += len;
00585 _httpd_net_write(r->clientSock, buf, len);
00586 len = read(fd, buf, HTTP_MAX_LEN);
00587 }
00588 close(fd);
00589 }
00590
00591
00592 void _httpd_sendStatic(httpd *server, request *r, char *data)
00593 {
00594 if (_httpd_checkLastModified(r, server->startTime) == 0)
00595 {
00596 _httpd_send304(r);
00597 }
00598 _httpd_sendHeaders(r, server->startTime, strlen(data));
00599 httpdOutput(r, data);
00600 }
00601
00602
00603
00604 void _httpd_sendFile(httpd *server, request *r, char *path)
00605 {
00606 char *suffix;
00607 struct stat sbuf;
00608
00609 suffix = rindex(path, '.');
00610 if (suffix != NULL)
00611 {
00612 if (strcasecmp(suffix,".gif") == 0)
00613 strcpy(r->response.contentType,"image/gif");
00614 if (strcasecmp(suffix,".jpg") == 0)
00615 strcpy(r->response.contentType,"image/jpeg");
00616 if (strcasecmp(suffix,".xbm") == 0)
00617 strcpy(r->response.contentType,"image/xbm");
00618 if (strcasecmp(suffix,".png") == 0)
00619 strcpy(r->response.contentType,"image/png");
00620 }
00621 if (stat(path, &sbuf) < 0)
00622 {
00623 _httpd_send404(server, r);
00624 return;
00625 }
00626 if (_httpd_checkLastModified(r, sbuf.st_mtime) == 0)
00627 {
00628 _httpd_send304(r);
00629 }
00630 else
00631 {
00632 _httpd_sendHeaders(r, sbuf.st_size, sbuf.st_mtime);
00633 _httpd_catFile(r, path);
00634 }
00635 }
00636
00637
00638 int _httpd_sendDirectoryEntry(httpd *server, request *r, httpContent *entry,
00639 char *entryName)
00640 {
00641 char path[HTTP_MAX_URL];
00642
00643 snprintf(path, HTTP_MAX_URL, "%s/%s", entry->path, entryName);
00644 _httpd_sendFile(server, r, path);
00645 return(0);
00646 }
00647
00648
00649 void _httpd_sendText(request *r, char *msg)
00650 {
00651 r->response.responseLength += strlen(msg);
00652 _httpd_net_write(r->clientSock,msg,strlen(msg));
00653 }
00654
00655
00656 int _httpd_checkLastModified(request *r, int modTime)
00657 {
00658 char timeBuf[HTTP_TIME_STRING_LEN];
00659
00660 _httpd_formatTimeString(timeBuf, modTime);
00661 if (strcmp(timeBuf, r->request.ifModified) == 0)
00662 return(0);
00663 return(1);
00664 }
00665
00666
00667 static unsigned char isAcceptable[96] =
00668
00669
00670 #define URL_XALPHAS (unsigned char) 1
00671 #define URL_XPALPHAS (unsigned char) 2
00672
00673
00674
00675
00676
00677
00678 { 7,0,0,0,0,0,0,0,0,0,7,0,0,7,7,7,
00679 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,
00680 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
00681 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7,
00682 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
00683 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0 };
00684
00685 #define ACCEPTABLE(a) ( a>=32 && a<128 && ((isAcceptable[a-32]) & mask))
00686
00687 static char *hex = "0123456789ABCDEF";
00688
00689
00690 char *_httpd_escape(str)
00691 char *str;
00692 {
00693 unsigned char mask = URL_XPALPHAS;
00694 char * p;
00695 char * q;
00696 char * result;
00697 int unacceptable = 0;
00698 for(p=str; *p; p++)
00699 if (!ACCEPTABLE((unsigned char)*p))
00700 unacceptable +=2;
00701 result = (char *) malloc(p-str + unacceptable + 1);
00702 bzero(result,(p-str + unacceptable + 1));
00703
00704 if (result == NULL)
00705 {
00706 return(NULL);
00707 }
00708 for(q=result, p=str; *p; p++) {
00709 unsigned char a = *p;
00710 if (!ACCEPTABLE(a)) {
00711 *q++ = '%';
00712 *q++ = hex[a >> 4];
00713 *q++ = hex[a & 15];
00714 }
00715 else *q++ = *p;
00716 }
00717 *q++ = 0;
00718 return result;
00719 }
00720
00721
00722
00723 void _httpd_sanitiseUrl(url)
00724 char *url;
00725 {
00726 char *from,
00727 *to,
00728 *last;
00729
00730
00731
00732
00733 from = to = url;
00734 while(*from)
00735 {
00736 if (*from == '/' && *(from+1) == '/')
00737 {
00738 from++;
00739 continue;
00740 }
00741 *to = *from;
00742 to++;
00743 from++;
00744 }
00745 *to = 0;
00746
00747
00748
00749
00750
00751 from = to = url;
00752 while(*from)
00753 {
00754 if (*from == '/' && *(from+1) == '.' && *(from+2)=='/')
00755 {
00756 from += 2;
00757 continue;
00758 }
00759 *to = *from;
00760 to++;
00761 from++;
00762 }
00763 *to = 0;
00764
00765
00766
00767
00768
00769
00770 from = to = last = url;
00771 while(*from)
00772 {
00773 if (*from == '/' && *(from+1) == '.' &&
00774 *(from+2)=='.' && *(from+3)=='/')
00775 {
00776 to = last;
00777 from += 3;
00778 continue;
00779 }
00780 if (*from == '/')
00781 {
00782 last = to;
00783 }
00784 *to = *from;
00785 to++;
00786 from++;
00787 }
00788 *to = 0;
00789 }