00001
00002
00003 #include <ctype.h>
00004 #include <assert.h>
00005 #include <stdlib.h>
00006 #include <stdio.h>
00007 #include <string.h>
00008 #include <errno.h>
00009 #include <time.h>
00010
00011 #include <xmlrpc-c/config.h>
00012 #include "abyss_mallocvar.h"
00013 #include "abyss_xmlrpc_int.h"
00014 #include <xmlrpc-c/abyss.h>
00015
00016 #include "abyss_server.h"
00017 #include "abyss_session.h"
00018 #include "abyss_conn.h"
00019 #include "abyss_token.h"
00020 #include "abyss_date.h"
00021 #include "abyss_data.h"
00022 #include "abyss_info.h"
00023
00024 #include "abyss_http.h"
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 static void
00035 initRequestInfo(TRequestInfo * const requestInfoP,
00036 httpVersion const httpVersion,
00037 const char * const requestLine,
00038 TMethod const httpMethod,
00039 const char * const host,
00040 unsigned int const port,
00041 const char * const path,
00042 const char * const query) {
00043
00044
00045
00046
00047
00048 requestInfoP->requestline = requestLine;
00049 requestInfoP->method = httpMethod;
00050 requestInfoP->host = host;
00051 requestInfoP->port = port;
00052 requestInfoP->uri = path;
00053 requestInfoP->query = query;
00054 requestInfoP->from = NULL;
00055 requestInfoP->useragent = NULL;
00056 requestInfoP->referer = NULL;
00057 requestInfoP->user = NULL;
00058
00059 if (httpVersion.major > 1 ||
00060 (httpVersion.major == 1 && httpVersion.minor >= 1))
00061 requestInfoP->keepalive = TRUE;
00062 else
00063 requestInfoP->keepalive = FALSE;
00064 }
00065
00066
00067
00068 static void
00069 freeRequestInfo(TRequestInfo * const requestInfoP) {
00070
00071 if (requestInfoP->requestline)
00072 xmlrpc_strfree(requestInfoP->requestline);
00073
00074 if (requestInfoP->user)
00075 xmlrpc_strfree(requestInfoP->user);
00076 }
00077
00078
00079
00080 void
00081 RequestInit(TSession * const sessionP,
00082 TConn * const connectionP) {
00083
00084 time_t nowtime;
00085
00086 sessionP->validRequest = false;
00087
00088 time(&nowtime);
00089 sessionP->date = *gmtime(&nowtime);
00090
00091 sessionP->conn = connectionP;
00092
00093 sessionP->responseStarted = FALSE;
00094
00095 sessionP->chunkedwrite = FALSE;
00096 sessionP->chunkedwritemode = FALSE;
00097
00098 ListInit(&sessionP->cookies);
00099 ListInit(&sessionP->ranges);
00100 TableInit(&sessionP->request_headers);
00101 TableInit(&sessionP->response_headers);
00102
00103 sessionP->status = 0;
00104
00105 StringAlloc(&(sessionP->header));
00106 }
00107
00108
00109
00110 void
00111 RequestFree(TSession * const sessionP) {
00112
00113 if (sessionP->validRequest)
00114 freeRequestInfo(&sessionP->request_info);
00115
00116 ListFree(&sessionP->cookies);
00117 ListFree(&sessionP->ranges);
00118 TableFree(&sessionP->request_headers);
00119 TableFree(&sessionP->response_headers);
00120 StringFree(&(sessionP->header));
00121 }
00122
00123
00124
00125 static void
00126 readRequestLine(TSession * const sessionP,
00127 char ** const requestLineP,
00128 uint16_t * const httpErrorCodeP) {
00129
00130 *httpErrorCodeP = 0;
00131
00132
00133 do {
00134 abyss_bool success;
00135 success = ConnReadHeader(sessionP->conn, requestLineP);
00136 if (!success)
00137 *httpErrorCodeP = 408;
00138 } while (!*httpErrorCodeP && (*requestLineP)[0] == '\0');
00139 }
00140
00141
00142
00143 static void
00144 unescapeUri(char * const uri,
00145 abyss_bool * const errorP) {
00146
00147 char * x;
00148 char * y;
00149
00150 x = y = uri;
00151
00152 *errorP = FALSE;
00153
00154 while (*x && !*errorP) {
00155 switch (*x) {
00156 case '%': {
00157 char c;
00158 ++x;
00159 c = tolower(*x++);
00160 if ((c >= '0') && (c <= '9'))
00161 c -= '0';
00162 else if ((c >= 'a') && (c <= 'f'))
00163 c -= 'a' - 10;
00164 else
00165 *errorP = TRUE;
00166
00167 if (!*errorP) {
00168 char d;
00169 d = tolower(*x++);
00170 if ((d >= '0') && (d <= '9'))
00171 d -= '0';
00172 else if ((d >= 'a') && (d <= 'f'))
00173 d -= 'a' - 10;
00174 else
00175 *errorP = TRUE;
00176
00177 if (!*errorP)
00178 *y++ = ((c << 4) | d);
00179 }
00180 } break;
00181
00182 default:
00183 *y++ = *x++;
00184 break;
00185 }
00186 }
00187 *y = '\0';
00188 }
00189
00190
00191
00192 static void
00193 parseHostPort(char * const hostport,
00194 const char ** const hostP,
00195 unsigned short * const portP,
00196 uint16_t * const httpErrorCodeP) {
00197
00198 char * colonPos;
00199
00200 colonPos = strchr(hostport, ':');
00201 if (colonPos) {
00202 const char * p;
00203 uint32_t port;
00204
00205 *colonPos = '\0';
00206
00207 *hostP = hostport;
00208
00209 for (p = colonPos + 1, port = 0;
00210 isdigit(*p) && port < 65535;
00211 (port = port * 10 + (*p - '0')), ++p);
00212
00213 *portP = port;
00214
00215 if (*p || port == 0)
00216 *httpErrorCodeP = 400;
00217 else
00218 *httpErrorCodeP = 0;
00219 } else {
00220 *hostP = hostport;
00221 *portP = 80;
00222 *httpErrorCodeP = 0;
00223 }
00224 }
00225
00226
00227
00228 static void
00229 parseRequestUri(char * const requestUri,
00230 const char ** const hostP,
00231 const char ** const pathP,
00232 const char ** const queryP,
00233 unsigned short * const portP,
00234 uint16_t * const httpErrorCodeP) {
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 abyss_bool error;
00246
00247 unescapeUri(requestUri, &error);
00248
00249 if (error)
00250 *httpErrorCodeP = 400;
00251 else {
00252 char * requestUriNoQuery;
00253
00254
00255
00256 {
00257
00258 char * const qmark = strchr(requestUri, '?');
00259
00260 if (qmark) {
00261 *qmark = '\0';
00262 *queryP = qmark + 1;
00263 } else
00264 *queryP = NULL;
00265 }
00266
00267 requestUriNoQuery = requestUri;
00268
00269 if (requestUriNoQuery[0] == '/') {
00270 *hostP = NULL;
00271 *pathP = requestUriNoQuery;
00272 *portP = 80;
00273 } else {
00274 if (!xmlrpc_strneq(requestUriNoQuery, "http://", 7))
00275 *httpErrorCodeP = 400;
00276 else {
00277 char * const hostportpath = &requestUriNoQuery[7];
00278 char * const slashPos = strchr(hostportpath, '/');
00279 char * hostport;
00280
00281 if (slashPos) {
00282 char * p;
00283 *pathP = slashPos;
00284
00285
00286
00287
00288
00289
00290 for (p = hostportpath; *p != '/'; ++p)
00291 *(p-1) = *p;
00292 *(p-1) = '\0';
00293
00294 hostport = hostportpath - 1;
00295 *httpErrorCodeP = 0;
00296 } else {
00297 *pathP = "*";
00298 hostport = hostportpath;
00299 *httpErrorCodeP = 0;
00300 }
00301 if (!*httpErrorCodeP)
00302 parseHostPort(hostport, hostP, portP, httpErrorCodeP);
00303 }
00304 }
00305 }
00306 }
00307
00308
00309
00310 static void
00311 parseRequestLine(char * const requestLine,
00312 TMethod * const httpMethodP,
00313 httpVersion * const httpVersionP,
00314 const char ** const hostP,
00315 unsigned short * const portP,
00316 const char ** const pathP,
00317 const char ** const queryP,
00318 abyss_bool * const moreLinesP,
00319 uint16_t * const httpErrorCodeP) {
00320
00321
00322
00323 const char * httpMethodName;
00324 char * p;
00325
00326 p = requestLine;
00327
00328
00329 NextToken((const char **)&p);
00330
00331 httpMethodName = GetToken(&p);
00332 if (!httpMethodName)
00333 *httpErrorCodeP = 400;
00334 else {
00335 char * requestUri;
00336
00337 if (xmlrpc_streq(httpMethodName, "GET"))
00338 *httpMethodP = m_get;
00339 else if (xmlrpc_streq(httpMethodName, "PUT"))
00340 *httpMethodP = m_put;
00341 else if (xmlrpc_streq(httpMethodName, "OPTIONS"))
00342 *httpMethodP = m_options;
00343 else if (xmlrpc_streq(httpMethodName, "DELETE"))
00344 *httpMethodP = m_delete;
00345 else if (xmlrpc_streq(httpMethodName, "POST"))
00346 *httpMethodP = m_post;
00347 else if (xmlrpc_streq(httpMethodName, "TRACE"))
00348 *httpMethodP = m_trace;
00349 else if (xmlrpc_streq(httpMethodName, "HEAD"))
00350 *httpMethodP = m_head;
00351 else
00352 *httpMethodP = m_unknown;
00353
00354
00355 NextToken((const char **)&p);
00356
00357
00358 requestUri = GetToken(&p);
00359 if (!requestUri)
00360 *httpErrorCodeP = 400;
00361 else {
00362 parseRequestUri(requestUri, hostP, pathP, queryP, portP,
00363 httpErrorCodeP);
00364
00365 if (!*httpErrorCodeP) {
00366 const char * httpVersion;
00367
00368 NextToken((const char **)&p);
00369
00370
00371
00372 httpVersion = GetToken(&p);
00373 if (httpVersion) {
00374 uint32_t vmin, vmaj;
00375 if (sscanf(httpVersion, "HTTP/%d.%d", &vmaj, &vmin) != 2)
00376 *httpErrorCodeP = 400;
00377 else {
00378 httpVersionP->major = vmaj;
00379 httpVersionP->minor = vmin;
00380 *httpErrorCodeP = 0;
00381 }
00382 *moreLinesP = TRUE;
00383 } else {
00384
00385
00386
00387 *httpErrorCodeP = 0;
00388 *moreLinesP = FALSE;
00389 }
00390 }
00391 }
00392 }
00393 }
00394
00395
00396
00397 static void
00398 strtolower(char * const s) {
00399
00400 char * t;
00401
00402 t = &s[0];
00403 while (*t) {
00404 *t = tolower(*t);
00405 ++t;
00406 }
00407 }
00408
00409
00410
00411 static void
00412 getFieldNameToken(char ** const pP,
00413 char ** const fieldNameP,
00414 uint16_t * const httpErrorCodeP) {
00415
00416 char * fieldName;
00417
00418 NextToken((const char **)pP);
00419
00420 fieldName = GetToken(pP);
00421 if (!fieldName)
00422 *httpErrorCodeP = 400;
00423 else {
00424 if (fieldName[strlen(fieldName)-1] != ':')
00425
00426 *httpErrorCodeP = 400;
00427 else {
00428 fieldName[strlen(fieldName)-1] = '\0';
00429
00430 strtolower(fieldName);
00431
00432 *httpErrorCodeP = 0;
00433 *fieldNameP = fieldName;
00434 }
00435 }
00436 }
00437
00438
00439
00440 static void
00441 processHeader(const char * const fieldName,
00442 char * const fieldValue,
00443 TSession * const sessionP,
00444 uint16_t * const httpErrorCodeP) {
00445
00446
00447
00448
00449
00450
00451
00452 *httpErrorCodeP = 0;
00453
00454 if (xmlrpc_streq(fieldName, "connection")) {
00455 if (xmlrpc_strcaseeq(fieldValue, "keep-alive"))
00456 sessionP->request_info.keepalive = TRUE;
00457 else
00458 sessionP->request_info.keepalive = FALSE;
00459 } else if (xmlrpc_streq(fieldName, "host"))
00460 parseHostPort(fieldValue, &sessionP->request_info.host,
00461 &sessionP->request_info.port, httpErrorCodeP);
00462 else if (xmlrpc_streq(fieldName, "from"))
00463 sessionP->request_info.from = fieldValue;
00464 else if (xmlrpc_streq(fieldName, "user-agent"))
00465 sessionP->request_info.useragent = fieldValue;
00466 else if (xmlrpc_streq(fieldName, "referer"))
00467 sessionP->request_info.referer = fieldValue;
00468 else if (xmlrpc_streq(fieldName, "range")) {
00469 if (xmlrpc_strneq(fieldValue, "bytes=", 6)) {
00470 abyss_bool succeeded;
00471 succeeded = ListAddFromString(&sessionP->ranges, &fieldValue[6]);
00472 *httpErrorCodeP = succeeded ? 0 : 400;
00473 }
00474 } else if (xmlrpc_streq(fieldName, "cookies")) {
00475 abyss_bool succeeded;
00476 succeeded = ListAddFromString(&sessionP->cookies, fieldValue);
00477 *httpErrorCodeP = succeeded ? 0 : 400;
00478 }
00479 }
00480
00481
00482
00483 abyss_bool
00484 RequestRead(TSession * const sessionP) {
00485 uint16_t httpErrorCode;
00486 char * requestLine;
00487
00488 readRequestLine(sessionP, &requestLine, &httpErrorCode);
00489 if (!httpErrorCode) {
00490 TMethod httpMethod;
00491 const char * host;
00492 const char * path;
00493 const char * query;
00494 unsigned short port;
00495 abyss_bool moreHeaders=false;
00496
00497 parseRequestLine(requestLine, &httpMethod, &sessionP->version,
00498 &host, &port, &path, &query,
00499 &moreHeaders, &httpErrorCode);
00500
00501 if (!httpErrorCode)
00502 initRequestInfo(&sessionP->request_info, sessionP->version,
00503 strdup(requestLine),
00504 httpMethod, host, port, path, query);
00505
00506 while (moreHeaders && !httpErrorCode) {
00507 char * p;
00508 abyss_bool succeeded;
00509 succeeded = ConnReadHeader(sessionP->conn, &p);
00510 if (!succeeded)
00511 httpErrorCode = 408;
00512 else {
00513 if (!*p)
00514
00515
00516
00517 moreHeaders = FALSE;
00518 else {
00519 char * fieldName;
00520 getFieldNameToken(&p, &fieldName, &httpErrorCode);
00521 if (!httpErrorCode) {
00522 char * fieldValue;
00523
00524 NextToken((const char **)&p);
00525
00526 fieldValue = p;
00527
00528 TableAdd(&sessionP->request_headers,
00529 fieldName, fieldValue);
00530
00531 processHeader(fieldName, fieldValue, sessionP,
00532 &httpErrorCode);
00533 }
00534 }
00535 }
00536 }
00537 }
00538 if (httpErrorCode)
00539 ResponseStatus(sessionP, httpErrorCode);
00540 else
00541 sessionP->validRequest = true;
00542
00543 return !httpErrorCode;
00544 }
00545
00546
00547
00548 char *RequestHeaderValue(TSession *r,char *name)
00549 {
00550 return (TableFind(&r->request_headers,name));
00551 }
00552
00553
00554
00555 abyss_bool
00556 RequestValidURI(TSession * const sessionP) {
00557
00558 if (!sessionP->request_info.uri)
00559 return FALSE;
00560
00561 if (xmlrpc_streq(sessionP->request_info.uri, "*"))
00562 return (sessionP->request_info.method != m_options);
00563
00564 if (strchr(sessionP->request_info.uri, '*'))
00565 return FALSE;
00566
00567 return TRUE;
00568 }
00569
00570
00571
00572 abyss_bool
00573 RequestValidURIPath(TSession * const sessionP) {
00574
00575 uint32_t i;
00576 const char * p;
00577
00578 p = sessionP->request_info.uri;
00579
00580 i = 0;
00581
00582 if (*p == '/') {
00583 i = 1;
00584 while (*p)
00585 if (*(p++) == '/') {
00586 if (*p == '/')
00587 break;
00588 else if ((strncmp(p,"./",2) == 0) || (strcmp(p, ".") == 0))
00589 ++p;
00590 else if ((strncmp(p, "../", 2) == 0) ||
00591 (strcmp(p, "..") == 0)) {
00592 p += 2;
00593 --i;
00594 if (i == 0)
00595 break;
00596 }
00597
00598 else if (*p == '.')
00599 return FALSE;
00600 else
00601 if (*p)
00602 ++i;
00603 }
00604 }
00605 return (*p == 0 && i > 0);
00606 }
00607
00608
00609
00610 abyss_bool
00611 RequestAuth(TSession *r,char *credential,char *user,char *pass) {
00612
00613 char *p,*x;
00614 char z[80],t[80];
00615
00616 p=RequestHeaderValue(r,"authorization");
00617 if (p) {
00618 NextToken((const char **)&p);
00619 x=GetToken(&p);
00620 if (x) {
00621 if (strcasecmp(x,"basic")==0) {
00622 NextToken((const char **)&p);
00623 sprintf(z,"%s:%s",user,pass);
00624 Base64Encode(z,t);
00625
00626 if (strcmp(p,t)==0) {
00627 r->request_info.user=strdup(user);
00628 return TRUE;
00629 };
00630 };
00631 }
00632 };
00633
00634 sprintf(z,"Basic realm=\"%s\"",credential);
00635 ResponseAddField(r,"WWW-Authenticate",z);
00636 ResponseStatus(r,401);
00637 return FALSE;
00638 }
00639
00640
00641
00642
00643
00644
00645
00646 abyss_bool RangeDecode(char *str,uint64_t filesize,uint64_t *start,uint64_t *end)
00647 {
00648 char *ss;
00649
00650 *start=0;
00651 *end=filesize-1;
00652
00653 if (*str=='-')
00654 {
00655 *start=filesize-strtol(str+1,&ss,10);
00656 return ((ss!=str) && (!*ss));
00657 };
00658
00659 *start=strtol(str,&ss,10);
00660
00661 if ((ss==str) || (*ss!='-'))
00662 return FALSE;
00663
00664 str=ss+1;
00665
00666 if (!*str)
00667 return TRUE;
00668
00669 *end=strtol(str,&ss,10);
00670
00671 if ((ss==str) || (*ss) || (*end<*start))
00672 return FALSE;
00673
00674 return TRUE;
00675 }
00676
00677
00678
00679
00680
00681 const char *
00682 HTTPReasonByStatus(uint16_t const code) {
00683
00684 struct _HTTPReasons {
00685 uint16_t status;
00686 const char * reason;
00687 };
00688
00689 static struct _HTTPReasons const reasons[] = {
00690 { 100,"Continue" },
00691 { 101,"Switching Protocols" },
00692 { 200,"OK" },
00693 { 201,"Created" },
00694 { 202,"Accepted" },
00695 { 203,"Non-Authoritative Information" },
00696 { 204,"No Content" },
00697 { 205,"Reset Content" },
00698 { 206,"Partial Content" },
00699 { 300,"Multiple Choices" },
00700 { 301,"Moved Permanently" },
00701 { 302,"Moved Temporarily" },
00702 { 303,"See Other" },
00703 { 304,"Not Modified" },
00704 { 305,"Use Proxy" },
00705 { 400,"Bad Request" },
00706 { 401,"Unauthorized" },
00707 { 402,"Payment Required" },
00708 { 403,"Forbidden" },
00709 { 404,"Not Found" },
00710 { 405,"Method Not Allowed" },
00711 { 406,"Not Acceptable" },
00712 { 407,"Proxy Authentication Required" },
00713 { 408,"Request Timeout" },
00714 { 409,"Conflict" },
00715 { 410,"Gone" },
00716 { 411,"Length Required" },
00717 { 412,"Precondition Failed" },
00718 { 413,"Request Entity Too Large" },
00719 { 414,"Request-URI Too Long" },
00720 { 415,"Unsupported Media Type" },
00721 { 500,"Internal Server Error" },
00722 { 501,"Not Implemented" },
00723 { 502,"Bad Gateway" },
00724 { 503,"Service Unavailable" },
00725 { 504,"Gateway Timeout" },
00726 { 505,"HTTP Version Not Supported" },
00727 { 000, NULL }
00728 };
00729 const struct _HTTPReasons * reasonP;
00730
00731 reasonP = &reasons[0];
00732
00733 while (reasonP->status <= code)
00734 if (reasonP->status == code)
00735 return reasonP->reason;
00736 else
00737 ++reasonP;
00738
00739 return "No Reason";
00740 }
00741
00742
00743
00744 int32_t
00745 HTTPRead(TSession * const s ATTR_UNUSED,
00746 const char * const buffer ATTR_UNUSED,
00747 uint32_t const len ATTR_UNUSED) {
00748
00749 return 0;
00750 }
00751
00752
00753
00754 abyss_bool
00755 HTTPWriteBodyChunk(TSession * const sessionP,
00756 const char * const buffer,
00757 uint32_t const len) {
00758
00759 abyss_bool succeeded;
00760
00761 if (sessionP->chunkedwrite && sessionP->chunkedwritemode) {
00762 char chunkHeader[16];
00763
00764 sprintf(chunkHeader, "%x\r\n", len);
00765
00766 succeeded =
00767 ConnWrite(sessionP->conn, chunkHeader, strlen(chunkHeader));
00768 if (succeeded) {
00769 succeeded = ConnWrite(sessionP->conn, buffer, len);
00770 if (succeeded)
00771 succeeded = ConnWrite(sessionP->conn, "\r\n", 2);
00772 }
00773 } else
00774 succeeded = ConnWrite(sessionP->conn, buffer, len);
00775
00776 return succeeded;
00777 }
00778
00779
00780
00781 abyss_bool
00782 HTTPWriteEndChunk(TSession * const sessionP) {
00783
00784 abyss_bool retval;
00785
00786 if (sessionP->chunkedwritemode && sessionP->chunkedwrite) {
00787
00788 sessionP->chunkedwritemode = FALSE;
00789 retval = ConnWrite(sessionP->conn, "0\r\n\r\n", 5);
00790 } else
00791 retval = TRUE;
00792
00793 return retval;
00794 }
00795
00796
00797
00798 abyss_bool
00799 HTTPKeepalive(TSession * const sessionP) {
00800
00801
00802
00803
00804 return (sessionP->request_info.keepalive &&
00805 !sessionP->serverDeniesKeepalive &&
00806 sessionP->status < 400);
00807 }
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841