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 unsigned 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++)=(unsigned char)(DEC(*bufin)<<2|DEC(bufin[1])>>4);
00259 *(bufout++)=(unsigned char)(DEC(bufin[1])<<4|DEC(bufin[2])>>2);
00260 *(bufout++)=(unsigned char)(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 if (*cp2 == '.')
00384 {
00385 strcpy(cp2,"_dot_");
00386 cp2 += 5;
00387 }
00388 else
00389 {
00390 cp2++;
00391 }
00392 }
00393 }
00394 *cp = 0;
00395 tmpVal = _httpd_unescape(val);
00396 httpdAddVariable(r, var, tmpVal);
00397 free(var);
00398 }
00399
00400
00401 void _httpd_formatTimeString(char *ptr, int clock)
00402 {
00403 struct tm *timePtr;
00404
00405 if (clock == 0)
00406 clock = time(NULL);
00407 timePtr = gmtime((time_t*)&clock);
00408 strftime(ptr, HTTP_TIME_STRING_LEN,"%a, %d %b %Y %T GMT",timePtr);
00409 }
00410
00411
00412 void _httpd_sendHeaders(request *r, int contentLength, int modTime)
00413 {
00414 char tmpBuf[80],
00415 timeBuf[HTTP_TIME_STRING_LEN];
00416
00417 if(r->response.headersSent)
00418 return;
00419
00420 r->response.headersSent = 1;
00421 _httpd_net_write(r->clientSock, "HTTP/1.0 ", 9);
00422 _httpd_net_write(r->clientSock, r->response.response,
00423 strlen(r->response.response));
00424 _httpd_net_write(r->clientSock, r->response.headers,
00425 strlen(r->response.headers));
00426
00427 _httpd_formatTimeString(timeBuf, 0);
00428 _httpd_net_write(r->clientSock,"Date: ", 6);
00429 _httpd_net_write(r->clientSock, timeBuf, strlen(timeBuf));
00430 _httpd_net_write(r->clientSock, "\n", 1);
00431
00432 _httpd_net_write(r->clientSock, "Connection: close\n", 18);
00433 _httpd_net_write(r->clientSock, "Content-Type: ", 14);
00434 _httpd_net_write(r->clientSock, r->response.contentType,
00435 strlen(r->response.contentType));
00436 _httpd_net_write(r->clientSock, "\n", 1);
00437
00438 if (contentLength > 0)
00439 {
00440 _httpd_net_write(r->clientSock, "Content-Length: ", 16);
00441 snprintf(tmpBuf, sizeof(tmpBuf), "%d", contentLength);
00442 _httpd_net_write(r->clientSock, tmpBuf, strlen(tmpBuf));
00443 _httpd_net_write(r->clientSock, "\n", 1);
00444
00445 _httpd_formatTimeString(timeBuf, modTime);
00446 _httpd_net_write(r->clientSock, "Last-Modified: ", 15);
00447 _httpd_net_write(r->clientSock, timeBuf, strlen(timeBuf));
00448 _httpd_net_write(r->clientSock, "\n", 1);
00449 }
00450 _httpd_net_write(r->clientSock, "\n", 1);
00451 }
00452
00453 httpDir *_httpd_findContentDir(server, dir, createFlag)
00454 httpd *server;
00455 char *dir;
00456 int createFlag;
00457 {
00458 char buffer[HTTP_MAX_URL],
00459 *curDir;
00460 httpDir *curItem,
00461 *curChild;
00462
00463 strncpy(buffer, dir, HTTP_MAX_URL);
00464 curItem = server->content;
00465 curDir = strtok(buffer,"/");
00466 while(curDir)
00467 {
00468 curChild = curItem->children;
00469 while(curChild)
00470 {
00471 if (strcmp(curChild->name, curDir) == 0)
00472 break;
00473 curChild = curChild->next;
00474 }
00475 if (curChild == NULL)
00476 {
00477 if (createFlag == HTTP_TRUE)
00478 {
00479 curChild = malloc(sizeof(httpDir));
00480 bzero(curChild, sizeof(httpDir));
00481 curChild->name = strdup(curDir);
00482 curChild->next = curItem->children;
00483 curItem->children = curChild;
00484 }
00485 else
00486 {
00487 return(NULL);
00488 }
00489 }
00490 curItem = curChild;
00491 curDir = strtok(NULL,"/");
00492 }
00493 return(curItem);
00494 }
00495
00496
00497 httpContent *_httpd_findContentEntry(request *r, httpDir *dir, char *entryName)
00498 {
00499 httpContent *curEntry;
00500
00501 curEntry = dir->entries;
00502 while(curEntry)
00503 {
00504 if (curEntry->type == HTTP_WILDCARD ||
00505 curEntry->type ==HTTP_C_WILDCARD)
00506 break;
00507 if (*entryName == 0 && curEntry->indexFlag)
00508 break;
00509 if (strcmp(curEntry->name, entryName) == 0)
00510 break;
00511 curEntry = curEntry->next;
00512 }
00513 if (curEntry)
00514 r->response.content = curEntry;
00515 return(curEntry);
00516 }
00517
00518
00519 void _httpd_send304(request *r)
00520 {
00521 httpdSetResponse(r, "304 Not Modified\n");
00522 _httpd_sendHeaders(r,0,0);
00523 }
00524
00525
00526 void _httpd_send403(request *r)
00527 {
00528 httpdSetResponse(r, "403 Permission Denied\n");
00529 _httpd_sendHeaders(r,0,0);
00530 _httpd_sendText(r,
00531 "<HTML><HEAD><TITLE>403 Permission Denied</TITLE></HEAD>\n");
00532 _httpd_sendText(r,
00533 "<BODY><H1>Access to the request URL was denied!</H1>\n");
00534 }
00535
00536
00537 void _httpd_send404(httpd *server, request *r)
00538 {
00539 char msg[HTTP_MAX_URL];
00540
00541 snprintf(msg, HTTP_MAX_URL,
00542 "File does not exist: %s\n", r->request.path);
00543 _httpd_writeErrorLog(server, r, LEVEL_ERROR, msg);
00544
00545 if (server->handle404 && server->handle404->function) {
00546
00547
00548
00549 (server->handle404->function)(server, r);
00550 }
00551 else {
00552
00553
00554
00555 httpdSetResponse(r, "404 Not Found\n");
00556 _httpd_sendHeaders(r,0,0);
00557 _httpd_sendText(r,
00558 "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
00559 _httpd_sendText(r,
00560 "<BODY><H1>The request URL was not found!</H1>\n");
00561 _httpd_sendText(r, "</BODY></HTML>\n");
00562 }
00563 }
00564
00565
00566 void _httpd_catFile(request *r, char *path)
00567 {
00568 int fd,
00569 len;
00570 char buf[HTTP_MAX_LEN];
00571
00572 fd = open(path,O_RDONLY);
00573 if (fd < 0)
00574 return;
00575 len = read(fd, buf, HTTP_MAX_LEN);
00576 while(len > 0)
00577 {
00578 r->response.responseLength += len;
00579 _httpd_net_write(r->clientSock, buf, len);
00580 len = read(fd, buf, HTTP_MAX_LEN);
00581 }
00582 close(fd);
00583 }
00584
00585
00586 void _httpd_sendStatic(httpd *server, request *r, char *data)
00587 {
00588 if (_httpd_checkLastModified(r, server->startTime) == 0)
00589 {
00590 _httpd_send304(r);
00591 }
00592 _httpd_sendHeaders(r, server->startTime, strlen(data));
00593 httpdOutput(r, data);
00594 }
00595
00596
00597
00598 void _httpd_sendFile(httpd *server, request *r, char *path)
00599 {
00600 char *suffix;
00601 struct stat sbuf;
00602
00603 suffix = rindex(path, '.');
00604 if (suffix != NULL)
00605 {
00606 if (strcasecmp(suffix,".gif") == 0)
00607 strcpy(r->response.contentType,"image/gif");
00608 if (strcasecmp(suffix,".jpg") == 0)
00609 strcpy(r->response.contentType,"image/jpeg");
00610 if (strcasecmp(suffix,".xbm") == 0)
00611 strcpy(r->response.contentType,"image/xbm");
00612 if (strcasecmp(suffix,".png") == 0)
00613 strcpy(r->response.contentType,"image/png");
00614 }
00615 if (stat(path, &sbuf) < 0)
00616 {
00617 _httpd_send404(server, r);
00618 return;
00619 }
00620 if (_httpd_checkLastModified(r, sbuf.st_mtime) == 0)
00621 {
00622 _httpd_send304(r);
00623 }
00624 else
00625 {
00626 _httpd_sendHeaders(r, sbuf.st_size, sbuf.st_mtime);
00627 _httpd_catFile(r, path);
00628 }
00629 }
00630
00631
00632 int _httpd_sendDirectoryEntry(httpd *server, request *r, httpContent *entry,
00633 char *entryName)
00634 {
00635 char path[HTTP_MAX_URL];
00636
00637 snprintf(path, HTTP_MAX_URL, "%s/%s", entry->path, entryName);
00638 _httpd_sendFile(server, r, path);
00639 return(0);
00640 }
00641
00642
00643 void _httpd_sendText(request *r, char *msg)
00644 {
00645 r->response.responseLength += strlen(msg);
00646 _httpd_net_write(r->clientSock,msg,strlen(msg));
00647 }
00648
00649
00650 int _httpd_checkLastModified(request *r, int modTime)
00651 {
00652 char timeBuf[HTTP_TIME_STRING_LEN];
00653
00654 _httpd_formatTimeString(timeBuf, modTime);
00655 if (strcmp(timeBuf, r->request.ifModified) == 0)
00656 return(0);
00657 return(1);
00658 }
00659
00660
00661 static unsigned char isAcceptable[96] =
00662
00663
00664 #define URL_XALPHAS (unsigned char) 1
00665 #define URL_XPALPHAS (unsigned char) 2
00666
00667
00668
00669
00670
00671
00672 { 7,0,0,0,0,0,0,0,0,0,7,0,0,7,7,7,
00673 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,
00674 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
00675 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7,
00676 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
00677 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0 };
00678
00679 #define ACCEPTABLE(a) ( a>=32 && a<128 && ((isAcceptable[a-32]) & mask))
00680
00681 static char *hex = "0123456789ABCDEF";
00682
00683
00684 char *_httpd_escape(str)
00685 char *str;
00686 {
00687 unsigned char mask = URL_XPALPHAS;
00688 char * p;
00689 char * q;
00690 char * result;
00691 int unacceptable = 0;
00692 for(p=str; *p; p++)
00693 if (!ACCEPTABLE((unsigned char)*p))
00694 unacceptable +=2;
00695 result = (char *) malloc(p-str + unacceptable + 1);
00696 bzero(result,(p-str + unacceptable + 1));
00697
00698 if (result == NULL)
00699 {
00700 return(NULL);
00701 }
00702 for(q=result, p=str; *p; p++) {
00703 unsigned char a = *p;
00704 if (!ACCEPTABLE(a)) {
00705 *q++ = '%';
00706 *q++ = hex[a >> 4];
00707 *q++ = hex[a & 15];
00708 }
00709 else *q++ = *p;
00710 }
00711 *q++ = 0;
00712 return result;
00713 }
00714
00715
00716
00717 void _httpd_sanitiseUrl(url)
00718 char *url;
00719 {
00720 char *from,
00721 *to,
00722 *last;
00723
00724
00725
00726
00727 from = to = url;
00728 while(*from)
00729 {
00730 if (*from == '/' && *(from+1) == '/')
00731 {
00732 from++;
00733 continue;
00734 }
00735 *to = *from;
00736 to++;
00737 from++;
00738 }
00739 *to = 0;
00740
00741
00742
00743
00744
00745 from = to = url;
00746 while(*from)
00747 {
00748 if (*from == '/' && *(from+1) == '.' && *(from+2)=='/')
00749 {
00750 from += 2;
00751 continue;
00752 }
00753 *to = *from;
00754 to++;
00755 from++;
00756 }
00757 *to = 0;
00758
00759
00760
00761
00762
00763
00764 from = to = last = url;
00765 while(*from)
00766 {
00767 if (*from == '/' && *(from+1) == '.' &&
00768 *(from+2)=='.' && *(from+3)=='/')
00769 {
00770 to = last;
00771 from += 3;
00772 continue;
00773 }
00774 if (*from == '/')
00775 {
00776 last = to;
00777 }
00778 *to = *from;
00779 to++;
00780 from++;
00781 }
00782 *to = 0;
00783 }