00001
00011
00012 #include "http.h"
00013 #include <string.h>
00014
00015 #if defined(__APPLE__)
00016 #include <sys/types.h>
00017 #endif
00018
00019 #include <errno.h>
00020 #include <stdlib.h>
00021
00022 #ifdef CP_HAS_UNISTD_H
00023 #include <unistd.h>
00024 #endif
00025
00026 #include <signal.h>
00027
00028 #if defined(unix) || defined(__unix__) || defined(__MACH__)
00029 #include <sys/socket.h>
00030 #include <netinet/in.h>
00031 #include <arpa/inet.h>
00032 #endif
00033
00034 #ifdef CP_USE_SSL
00035 #include <openssl/ssl.h>
00036 #include <openssl/err.h>
00037 #endif
00038
00039 #ifdef CP_HAS_STRINGS_H
00040 #include <strings.h>
00041 #endif
00042
00043 #ifdef CP_HAS_REGEX_H
00044 #include <regex.h>
00045 #else
00046 #ifdef CP_HAS_PCRE
00047 #include <pcreposix.h>
00048 #endif
00049 #endif
00050
00051 #include "hashtable.h"
00052 #include "hashlist.h"
00053 #include "trie.h"
00054 #include "vector.h"
00055 #include "log.h"
00056 #include "util.h"
00057 #include "socket.h"
00058
00059
00060
00061
00062
00063
00064
00065 #ifdef __OpenBSD__
00066 #define HTTP_PARSE_BUFSIZE 0x1000
00067 #else
00068 #define HTTP_PARSE_BUFSIZE 0xFFFF
00069 #endif
00070
00071 #define MATCHMAX 10
00072
00073 static char *re_request_line_str =
00074 "^(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT)[[:space:]]+([^ ]+)[[:space:]]+HTTP/([^[:space:]]*)[[:space:]]*$";
00075 static char *re_request_header_str =
00076 "^([[:alnum:][:punct:]]+): (.*[^[:space:]])([[:space:]]?)$";
00077
00078 static char *re_request_vars_str = "([^&]+)=([^&]*[^&[:space:]])&?";
00079
00080 static regex_t re_request_line;
00081 static regex_t re_request_header;
00082 static regex_t re_request_vars;
00083
00084 static char *cp_http_version_lit[] = { "1.0", "1.1" };
00085
00086 static char *connection_policy_lit[] = { "Close", "Close", "Keep-Alive" };
00087
00088 static char *content_type_lit[] = { "text/plain", "text/html", "image/jpeg" };
00089
00090 static char *server_error_fmt =
00091 "<html>\n"
00092 "<head>\n"
00093 "<title> 400 BAD REQUEST </title>\n"
00094 "</head>\n"
00095 "<body>\n"
00096 "<h1> 400 BAD REQUEST: %s </h1>\n"
00097 "</body>\n"
00098 "</html>";
00099
00100 static int cp_http_server_error_code[] =
00101 {
00102 CP_HTTP_EMPTY_REQUEST,
00103 CP_HTTP_INVALID_REQUEST_LINE,
00104 CP_HTTP_UNKNOWN_REQUEST_TYPE,
00105 CP_HTTP_INVALID_URI,
00106 CP_HTTP_VERSION_NOT_SPECIFIED,
00107 CP_HTTP_1_1_HOST_NOT_SPECIFIED,
00108 CP_HTTP_INCORRECT_REQUEST_BODY_LENGTH,
00109 -1
00110 };
00111
00112 static char *cp_http_server_error_lit[] =
00113 {
00114 "EMPTY REQUEST",
00115 "INVALID REQUEST LINE",
00116 "UNKNOWN REQUEST TYPE",
00117 "INVALID URI",
00118 "VERSION NOT SPECIFIED",
00119 "HTTP/1.1 HOST NOT SPECIFIED",
00120 "INCORRECT REQUEST BODY LENGTH"
00121 };
00122
00123 static cp_hashtable *cp_http_server_error;
00124
00125 struct cp_http_status_code_entry
00126 {
00127 cp_http_status_code code;
00128 char *lit;
00129 } cp_http_status_code_list[] =
00130 {
00131 { HTTP_100_CONTINUE, "100 CONTINUE" },
00132 { HTTP_101_SWITCHING_PROTOCOLS, "101 SWITCHING PROTOCOLS" },
00133 { HTTP_200_OK, "200 OK" },
00134 { HTTP_201_CREATED, "201 CREATED" },
00135 { HTTP_202_ACCEPTED, "202 ACCEPTED" },
00136 { HTTP_203_NON_AUTHORITATIVE_INFORMATION, "203 NON AUTHORITATIVE INFORMATION" },
00137 { HTTP_204_NO_CONTENT, "204 NO CONTENT" },
00138 { HTTP_205_RESET_CONTENT, "205 RESET CONTENT" },
00139 { HTTP_206_PARTIAL_CONTENT, "206 PARTIAL CONTENT" },
00140 { HTTP_300_MULTIPLE_CHOICES, "300 MULTIPLE CHOICES" },
00141 { HTTP_301_MOVED_PERMANENTLY, "301 MOVED PERMANENTLY" },
00142 { HTTP_302_FOUND, "302 FOUND" },
00143 { HTTP_303_SEE_OTHER, "303 SEE OTHER" },
00144 { HTTP_304_NOT_MODIFIED, "304 NOT MODIFIED" },
00145 { HTTP_305_USE_PROXY, "305 USE PROXY" },
00146 { HTTP_307_TEMPORARY_REDIRECT, "307 TEMPORARY REDIRECT" },
00147 { HTTP_400_BAD_REQUEST, "400 BAD REQUEST" },
00148 { HTTP_401_UNAUTHORIZED, "401 UNAUTHORIZED" },
00149 { HTTP_402_PAYMENT_REQUIRED, "402 PAYMENT REQUIRED" },
00150 { HTTP_403_FORBIDDEN, "403 FORBIDDEN" },
00151 { HTTP_404_NOT_FOUND, "404 NOT FOUND" },
00152 { HTTP_405_METHOD_NOT_ALLOWED, "405 METHOD NOT ALLOWED" },
00153 { HTTP_406_NOT_ACCEPTABLE, "406 NOT ACCEPTABLE" },
00154 { HTTP_407_PROXY_AUTHENTICATION_REQUIRED, "407 PROXY AUTHENTICATION REQUIRED" },
00155 { HTTP_408_REQUEST_TIME_OUT, "408 REQUEST TIME OUT" },
00156 { HTTP_409_CONFLICT, "409 CONFLICT" },
00157 { HTTP_410_GONE, "410 GONE" },
00158 { HTTP_411_LENGTH_REQUIRED, "411 LENGTH REQUIRED" },
00159 { HTTP_412_PRECONDITION_FAILED, "412 PRECONDITION FAILED" },
00160 { HTTP_413_REQUEST_ENTITY_TOO_LARGE, "413 REQUEST ENTITY TOO LARGE" },
00161 { HTTP_414_REQUEST_URI_TOO_LARGE, "414 REQUEST URI TOO LARGE" },
00162 { HTTP_415_UNSUPPORTED_MEDIA_TYPE, "415 UNSUPPORTED MEDIA TYPE" },
00163 { HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE, "416 REQUESTED RANGE NOT SATISFIABLE" },
00164 { HTTP_417_EXPECTATION_FAILED, "417 EXPECTATION FAILED" },
00165 { HTTP_500_INTERNAL_SERVER_ERROR, "500 INTERNAL SERVER ERROR" },
00166 { HTTP_501_NOT_IMPLEMENTED, "501 NOT IMPLEMENTED" },
00167 { HTTP_502_BAD_GATEWAY, "502 BAD GATEWAY" },
00168 { HTTP_503_SERVICE_UNAVAILABLE, "503 SERVICE UNAVAILABLE" },
00169 { HTTP_504_GATEWAY_TIME_OUT, "504 GATEWAY TIME OUT" },
00170 { HTTP_505_HTTP_VERSION_NOT_SUPPORTED, "505 HTTP VERSION NOT SUPPORTED" },
00171 { HTTP_NULL_STATUS, NULL}
00172 };
00173
00174 static cp_hashtable *cp_http_status_lit;
00175
00176 static char *cp_http_request_type_lit[] =
00177 {
00178 "OPTIONS",
00179 "GET",
00180 "HEAD",
00181 "POST",
00182 "PUT",
00183 "DELETE",
00184 "TRACE",
00185 "CONNECT"
00186 };
00187
00188 static volatile int initialized = 0;
00189
00190 static volatile int socket_reg_id = 0;
00191 static cp_hashlist *socket_registry = NULL;
00192 static cp_vector *shutdown_hook = NULL;
00193
00194 void cp_http_signal_handler(int sig);
00195
00196 void *session_cleanup_thread(void *);
00197
00198 int cp_http_init()
00199 {
00200 int i;
00201 int rc;
00202 #if defined(unix) || defined(__unix__) || defined(__MACH__)
00203 struct sigaction act;
00204 #endif
00205
00206 if (initialized) return initialized++;
00207 initialized = 1;
00208
00209 cp_socket_init();
00210
00211 #if defined(unix) || defined(__unix__) || defined(__MACH__)
00212 act.sa_handler = cp_http_signal_handler;
00213 sigemptyset(&act.sa_mask);
00214 act.sa_flags = 0;
00215 sigaction(SIGINT, &act, NULL);
00216 sigaction(SIGPIPE, &act, NULL);
00217 sigaction(SIGTERM, &act, NULL);
00218 #endif
00219
00220 if ((rc = regcomp(&re_request_line, re_request_line_str,
00221 REG_EXTENDED | REG_NEWLINE)))
00222 return log_regex_compilation_error(rc, "cp_http_init - request line");
00223
00224 if ((rc = regcomp(&re_request_header, re_request_header_str,
00225 REG_EXTENDED | REG_NEWLINE)))
00226 return log_regex_compilation_error(rc, "cp_http_init - request header");
00227
00228 if ((rc = regcomp(&re_request_vars, re_request_vars_str,
00229 REG_EXTENDED | REG_NEWLINE)))
00230 return log_regex_compilation_error(rc, "cp_http_init - request variables");
00231
00232 cp_http_server_error = cp_hashtable_create(10, cp_hash_int, cp_hash_compare_int);
00233 for (i = 0; cp_http_server_error_code[i] != -1; i++)
00234 cp_hashtable_put(cp_http_server_error,
00235 &cp_http_server_error_code[i],
00236 cp_http_server_error_lit[i]);
00237
00238 cp_http_status_lit = cp_hashtable_create(50, cp_hash_int, cp_hash_compare_int);
00239 for (i = 0; cp_http_status_code_list[i].lit != NULL; i++)
00240 cp_hashtable_put(cp_http_status_lit,
00241 &cp_http_status_code_list[i].code,
00242 cp_http_status_code_list[i].lit);
00243
00244 socket_registry =
00245 cp_hashlist_create_by_mode(1, COLLECTION_MODE_DEEP,
00246 cp_hash_int, cp_hash_compare_int);
00247
00248 #ifdef CP_USE_HTTP_SESSIONS
00249 {
00250 cp_thread _session_cleanup_thread;
00251 cp_thread_create(_session_cleanup_thread, NULL,
00252 session_cleanup_thread, NULL);
00253 #ifdef CP_HAS_PTHREAD_H
00254 cp_thread_detach(_session_cleanup_thread);
00255 #endif
00256 }
00257 #endif
00258
00259 return 0;
00260 }
00261
00262 volatile int cp_http_stopping = 0;
00263
00264
00265 void cp_httpsocket_stop_all()
00266 {
00267 cp_http_stopping = 1;
00268 cp_socket_stop_all();
00269 }
00270
00271 static volatile int cp_http_shutting_down = 0;
00272
00273 void cp_httpsocket_stop(cp_httpsocket *sock)
00274 {
00275 if (sock) sock->sock->closing = 1;
00276 }
00277
00278 void *cp_http_add_shutdown_callback(void (*cb)(void *), void *prm)
00279 {
00280 cp_wrap *wrap;
00281
00282 if (shutdown_hook == NULL)
00283 shutdown_hook = cp_vector_create(1);
00284
00285 wrap = cp_wrap_new(prm, cb);
00286
00287 cp_vector_add_element(shutdown_hook, wrap);
00288
00289 return wrap;
00290 }
00291
00292 void cp_http_shutdown()
00293 {
00294 if (cp_http_shutting_down) return;
00295
00296 cp_http_shutting_down = 1;
00297
00298 #ifdef __TRACE__
00299 DEBUGMSG("shutting down http services");
00300 #endif
00301
00302 if (shutdown_hook)
00303 {
00304 cp_vector_destroy_custom(shutdown_hook,
00305 (cp_destructor_fn) cp_wrap_delete);
00306 shutdown_hook = NULL;
00307 }
00308
00309 if (initialized)
00310 {
00311 regfree(&re_request_line);
00312 regfree(&re_request_header);
00313 regfree(&re_request_vars);
00314 }
00315
00316 cp_hashtable_destroy(cp_http_server_error);
00317 cp_hashtable_destroy(cp_http_status_lit);
00318 cp_hashlist_destroy_custom(socket_registry, NULL,
00319 (cp_destructor_fn) cp_httpsocket_stop);
00320 socket_registry = NULL;
00321
00322 cp_socket_shutdown();
00323
00324 initialized = 0;
00325 }
00326
00327 void cp_http_signal_handler(int sig)
00328 {
00329 switch (sig)
00330 {
00331 case SIGINT:
00332 #ifdef __TRACE__
00333 DEBUGMSG("SIGINT - stopping\n");
00334 #endif
00335 cp_http_shutdown();
00336 break;
00337
00338 #ifdef SIGPIPE
00339 case SIGPIPE:
00340 #ifdef __TRACE__
00341 DEBUGMSG("SIGPIPE - ignoring\n");
00342 #endif
00343 break;
00344 #endif
00345
00346 case SIGTERM:
00347 #ifdef __TRACE__
00348 DEBUGMSG("SIGTERM - stopping\n");
00349 #endif
00350 cp_http_shutdown();
00351 break;
00352 }
00353 }
00354
00355 #define HTTP_RE_MATCHMAX 10
00356
00357 #ifdef CP_USE_HTTP_SESSIONS
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 static cp_http_session *cp_httpsocket_create_session(cp_httpsocket *sock)
00382 {
00383 cp_http_session *session = calloc(1, sizeof(cp_http_session));
00384 if (session)
00385 {
00386 struct timeval tm;
00387 gettimeofday(&tm, NULL);
00388 session->sid = malloc(17 * sizeof(char));
00389 if (session->sid == NULL)
00390 {
00391 free(session);
00392 return NULL;
00393 }
00394 session->key =
00395 cp_hashtable_create_by_option(COLLECTION_MODE_COPY |
00396 COLLECTION_MODE_DEEP,
00397 1,
00398 cp_hash_string,
00399 cp_hash_compare_string,
00400 (cp_copy_fn) strdup,
00401 (cp_destructor_fn) free,
00402 NULL,
00403 (cp_destructor_fn) cp_wrap_delete);
00404 if (session->key == NULL)
00405 {
00406 free(session->sid);
00407 free(session);
00408 return NULL;
00409 }
00410
00411 session->created = session->access = tm.tv_sec;
00412 session->validity = DEFAULT_SESSION_VALIDITY;
00413 session->renew_on_access = 1;
00414 session->fresh = 1;
00415 session->refcount = 1;
00416 session->valid = 1;
00417
00418 if (sock)
00419 {
00420 if (sock->session == NULL)
00421 {
00422 sock->session =
00423 cp_hashlist_create_by_option(COLLECTION_MODE_COPY |
00424 COLLECTION_MODE_DEEP,
00425 1,
00426 cp_hash_string,
00427 cp_hash_compare_string,
00428 (cp_copy_fn) strdup,
00429 (cp_destructor_fn) free,
00430 NULL,
00431 (cp_destructor_fn)
00432 cp_http_session_delete);
00433 if (sock->session == NULL)
00434 {
00435 cp_http_session_delete(session);
00436 return NULL;
00437 }
00438 }
00439
00440
00441
00442 do
00443 {
00444 gen_tm_id_str(session->sid, &tm);
00445 } while (cp_hashlist_get(sock->session, session->sid));
00446
00447 cp_hashlist_append(sock->session, session->sid, session);
00448 }
00449 else
00450 gen_tm_id_str(session->sid, &tm);
00451 }
00452
00453 return session;
00454 }
00455
00456
00457 static cp_http_session *
00458 cp_httpsocket_checkout_session(cp_httpsocket *sock, char *sid)
00459 {
00460 cp_http_session *session =
00461 sock->session ? cp_hashlist_get(sock->session, sid) : NULL;
00462
00463 if (session)
00464 session->refcount++;
00465
00466
00467 return session;
00468 }
00469
00474 void cp_http_session_delete(cp_http_session *session)
00475 {
00476 if (session)
00477 {
00478 if (session->sid) free(session->sid);
00479 if (session->key)
00480 cp_hashtable_destroy(session->key);
00481 free(session);
00482 }
00483 }
00484
00485 void *cp_http_session_get(cp_http_session *session, char *key)
00486 {
00487 cp_wrap *wrap = cp_hashtable_get(session->key, key);
00488 if (wrap)
00489 return wrap->item;
00490 return NULL;
00491 }
00492
00493 void *cp_http_session_set_dtr(cp_http_session *session,
00494 char *key, void *value,
00495 cp_destructor_fn dtr)
00496 {
00497 cp_wrap *wrap = cp_wrap_new(value, dtr);
00498 if (wrap)
00499 return cp_hashtable_put(session->key, key, wrap);
00500 return NULL;
00501 }
00502
00503 void *cp_http_session_set(cp_http_session *session,
00504 char *key, void *value)
00505 {
00506 return cp_http_session_set_dtr(session, key, value, NULL);
00507 }
00508
00509 void cp_http_session_set_validity(cp_http_session *session, long sec)
00510 {
00511 session->validity = sec;
00512 }
00513
00514 short cp_http_session_is_fresh(cp_http_session *session)
00515 {
00516 return session->fresh;
00517 }
00518
00519 static char *redirect_fmt = "<html><head><title>302 FOUND</title></head><body><h1>302 FOUND</h1>The document has moved <a href=\"%s\"> here </a>.</body></html>";
00520
00525 static cp_http_response *
00526 cp_http_new_session_redirect(cp_http_request *req, int step)
00527 {
00528 cp_http_response *res = cp_http_response_create(req);
00529
00530 if (res)
00531 {
00532 char redirect_url[MAX_URL_LENGTH];
00533 #ifdef CP_USE_COOKIES
00534 char cookie_path[MAX_URL_LENGTH];
00535 char *cp;
00536 #endif
00537 char *host;
00538 char buf[HTTP_PARSE_BUFSIZE];
00539 cp_string *content;
00540 char *protocol;
00541
00542 #ifdef CP_USE_SSL
00543 if (req->owner->sock->use_ssl)
00544 protocol = "https";
00545 else
00546 #endif
00547 protocol = "http";
00548
00549 if ((host = cp_http_request_get_header(req, "Host")) == NULL)
00550 host = "localhost";
00551
00552 #ifdef CP_USE_COOKIES
00553 if (step == 2)
00554 #ifdef CP_HAS_SNPRINTF
00555 snprintf(redirect_url, MAX_URL_LENGTH,
00556 "%s://%s%s", protocol, host, req->uri);
00557 #else
00558 sprintf(redirect_url, "%s://%s%s", protocol, host, req->uri);
00559 #endif
00560 else
00561 #endif
00562 #ifdef CP_HAS_SNPRINTF
00563 snprintf(redirect_url, MAX_URL_LENGTH, "%s://%s%s?%s=%s", protocol,
00564 host, req->uri, CP_HTTP_SESSION_PRM, req->session->sid);
00565 #else
00566 sprintf(redirect_url, "%s://%s%s?%s=%s", protocol, host, req->uri,
00567 CP_HTTP_SESSION_PRM, req->session->sid);
00568 #endif
00569
00570 cp_http_response_set_status(res, HTTP_302_FOUND);
00571 cp_http_response_set_header(res, "Location", redirect_url);
00572 cp_http_response_set_connection_policy(res,
00573 HTTP_CONNECTION_POLICY_KEEP_ALIVE);
00574
00575 #ifdef CP_HAS_SNPRINTF
00576 snprintf(buf, HTTP_PARSE_BUFSIZE, redirect_fmt, redirect_url);
00577 #else
00578 sprintf(buf, redirect_fmt, redirect_url);
00579 #endif
00580 content = cp_string_cstrdup(buf);
00581 cp_http_response_set_content(res, content);
00582
00583 #ifdef CP_USE_COOKIES
00584 if (step == 1)
00585 {
00586 strlcpy(cookie_path, req->uri, MAX_URL_LENGTH);
00587 if ((cp = strrchr(cookie_path, '/')))
00588 {
00589 cp++;
00590 *cp = '\0';
00591 }
00592
00593 cp_http_response_set_cookie(res, CP_HTTP_SESSION_PRM,
00594 req->session->sid, host, cookie_path,
00595
00596 31536000,
00597 #ifdef CP_USE_SSL
00598 req->owner->sock->use_ssl
00599 #else
00600 0
00601 #endif
00602 );
00603 }
00604 #endif
00605 }
00606
00607 return res;
00608 }
00609
00611 void *session_cleanup_thread(void *prm)
00612 {
00613 cp_hashlist_iterator i, j;
00614 cp_httpsocket *curr;
00615 cp_http_session *session;
00616 time_t now;
00617 int rc;
00618
00619 while (!(cp_http_shutting_down || cp_http_stopping))
00620 {
00621 rc = cp_sleep(900);
00622 if (cp_http_shutting_down || cp_http_stopping) break;
00623 #ifdef __TRACE__
00624 DEBUGMSG("session_cleanup_thread running");
00625 #endif
00626 now = time(NULL);
00627 cp_hashlist_iterator_init(&i, socket_registry, COLLECTION_LOCK_READ);
00628 while ((curr = cp_hashlist_iterator_next_value(&i)))
00629 {
00630 if (curr->session == NULL) continue;
00631 cp_hashlist_iterator_init(&j, curr->session, COLLECTION_LOCK_WRITE);
00632 session = cp_hashlist_iterator_curr_value(&j);
00633 while (session != NULL)
00634 {
00635 time_t expiration = (session->renew_on_access ?
00636 session->access : session->created) + session->validity;
00637 if (now > expiration)
00638 {
00639 if (session->refcount <= 0)
00640 {
00641 if (curr->pending)
00642 {
00643 cp_http_response *res =
00644 cp_hashlist_remove(curr->pending, session->sid);
00645 if (res)
00646 cp_http_response_delete(res);
00647 }
00648 cp_hashlist_iterator_remove(&j);
00649 }
00650 }
00651 session = cp_hashlist_iterator_next_value(&j);
00652 }
00653 cp_hashlist_iterator_release(&j);
00654 }
00655 cp_hashlist_iterator_release(&i);
00656 #ifdef __TRACE__
00657 DEBUGMSG("session_cleanup_thread - cleanup done");
00658 #endif
00659 }
00660 #ifdef __TRACE__
00661 DEBUGMSG("session_cleanup_thread exits");
00662 #endif
00663
00664 return NULL;
00665 }
00666 #endif
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679 void cp_http_request_delete(cp_http_request *request)
00680 {
00681 if (request)
00682 {
00683 free(request->uri);
00684 #ifdef CP_USE_COOKIES
00685 if (request->cookie)
00686 cp_vector_destroy_custom(request->cookie, free);
00687 #endif
00688 if (request->header)
00689 cp_hashtable_destroy(request->header);
00690 if (request->query_string)
00691 free(request->query_string);
00692 if (request->prm)
00693 cp_hashtable_destroy(request->prm);
00694 #ifdef CP_USE_HTTP_SESSIONS
00695 if (request->session) request->session->refcount--;
00696 #endif
00697 free(request);
00698 }
00699 }
00700
00701 char *get_http_request_type_lit(cp_http_request_type type)
00702 {
00703 return cp_http_request_type_lit[type];
00704 }
00705
00706 static int parse_request_line(cp_http_request *req, char *request, int *plen)
00707 {
00708 regmatch_t rm[HTTP_RE_MATCHMAX];
00709 int len;
00710 int valid;
00711
00712 if (regexec(&re_request_line, request, HTTP_RE_MATCHMAX, rm, 0))
00713 return CP_HTTP_INVALID_REQUEST_LINE;
00714
00715 valid = 0;
00716 len = rm[1].rm_eo - rm[1].rm_so;
00717 if (len)
00718 for (req->type = OPTIONS; req->type <= CONNECT; req->type++)
00719 if (strncasecmp(&request[rm[1].rm_so],
00720 cp_http_request_type_lit[req->type], len) == 0)
00721 {
00722 valid = 1;
00723 break;
00724 }
00725
00726 if (!valid)
00727 return CP_HTTP_UNKNOWN_REQUEST_TYPE;
00728
00729 valid = 0;
00730 len = rm[2].rm_eo - rm[2].rm_so;
00731 if (len)
00732 {
00733 char *q = strnchr(&request[rm[2].rm_so], '?', rm[0].rm_eo);
00734 if (q)
00735 {
00736
00737 len = q - request;
00738 req->query_string = strndup(q + 1, rm[2].rm_eo - len - 1);
00739 len -= rm[2].rm_so;
00740 }
00741
00742 req->uri = strndup(&request[rm[2].rm_so], len);
00743 valid = 1;
00744 }
00745
00746 if (!valid)
00747 return CP_HTTP_INVALID_URI;
00748
00749 valid = 0;
00750 len = rm[3].rm_eo - rm[3].rm_so;
00751
00752 if (len)
00753 {
00754 if (strncmp(&request[rm[3].rm_so], "1.0", len) == 0)
00755 {
00756 req->version = HTTP_1_0;
00757 valid = 1;
00758 }
00759 else if (strncmp(&request[rm[3].rm_so], "1.1", len) == 0)
00760 {
00761 req->version = HTTP_1_1;
00762 valid = 1;
00763 }
00764 }
00765
00766 if (!valid)
00767 return CP_HTTP_VERSION_NOT_SPECIFIED;
00768
00769 *plen = rm[0].rm_eo;
00770
00771 return 0;
00772 }
00773
00774 #define REQUEST_STAGE_START 0
00775 #define REQUEST_STAGE_STATUS_LINE 1
00776 #define REQUEST_STAGE_HEADERS 2
00777 #define REQUEST_STAGE_BODY 3
00778 #define REQUEST_STAGE_DONE 4
00779
00780 static int is_empty_line(char *c)
00781 {
00782 return strncmp(c, "\r\n\r\n", 4) == 0 || strncmp(c, "\n\n", 2) == 0;
00783 }
00784
00785 static void skip_eol(char **c)
00786 {
00787 if (**c == '\r') (*c)++;
00788 if (**c == '\n') (*c)++;
00789 if (**c == '\r') (*c)++;
00790 if (**c == '\n') (*c)++;
00791 }
00792
00793 static int
00794 parse_headers(cp_http_request *req, char *request, int *plen, int *stage)
00795 {
00796 char *curr = request;
00797 regmatch_t rm[MATCHMAX];
00798 int len;
00799 char *name, *value;
00800 char *eol;
00801
00802 if (req->header == NULL)
00803 req->header =
00804 cp_hashtable_create_by_option(COLLECTION_MODE_NOSYNC |
00805 COLLECTION_MODE_DEEP, 10,
00806 cp_hash_string,
00807 cp_hash_compare_string,
00808 NULL, free, NULL, free);
00809
00810 while (regexec(&re_request_header, curr, MATCHMAX, rm, 0) == 0)
00811 {
00812 len = rm[1].rm_eo - rm[1].rm_so;
00813 if ((name = (char *) malloc((len + 1) * sizeof(char))) == NULL)
00814 return CP_MEMORY_ALLOCATION_FAILURE;
00815 strncpy(name, curr + rm[1].rm_so, len);
00816 name[len] = '\0';
00817
00818 len = rm[2].rm_eo - rm[2].rm_so;
00819 if ((value = (char *) malloc((len + 1) * sizeof(char))) == NULL)
00820 {
00821 free(name);
00822 return CP_MEMORY_ALLOCATION_FAILURE;
00823 }
00824 strncpy(value, curr + rm[2].rm_so, len);
00825 value[len] = '\0';
00826 #ifdef CP_USE_COOKIES
00827 if (strcmp(name, "Cookie") == 0)
00828 {
00829 if (req->cookie == NULL)
00830 {
00831 req->cookie = cp_vector_create(1);
00832 if (req->cookie == NULL)
00833 return CP_MEMORY_ALLOCATION_FAILURE;
00834 }
00835 cp_vector_add_element(req->cookie, value);
00836 free(name);
00837 }
00838 else
00839 #endif
00840 cp_hashtable_put(req->header, name, value);
00841
00842 eol = &curr[rm[2].rm_eo];
00843 curr = &curr[rm[0].rm_eo];
00844 if (is_empty_line(eol))
00845 {
00846 *stage = REQUEST_STAGE_DONE;
00847 break;
00848 }
00849 }
00850
00851 skip_eol(&curr);
00852 *plen = curr - request;
00853
00854 if ((req->version == HTTP_1_1) &&
00855 (cp_http_request_get_header(req, "Host") == NULL))
00856 return CP_HTTP_1_1_HOST_NOT_SPECIFIED;
00857
00858 return 0;
00859 }
00860
00861 static int parse_cp_http_request_body(cp_http_request *req,
00862 char *request,
00863 int *used)
00864 {
00865 int len;
00866 int dlen;
00867 char *clen;
00868 char *p = &request[*used];
00869
00870 clen = cp_http_request_get_header(req, "Content-Length");
00871 if (clen == NULL)
00872 {
00873 cp_warn("no length header");
00874 return CP_HTTP_INCORRECT_REQUEST_BODY_LENGTH;
00875 }
00876 dlen = atoi(clen);
00877
00878 if (req->query_string)
00879 {
00880 int before = strlen(req->query_string);
00881 len = dlen - before;
00882 strncat(req->query_string, request, len);
00883 len = strlen(req->query_string) - before;
00884 }
00885 else
00886 {
00887 req->query_string = malloc(dlen + 1);
00888 if (*p == '\r') { p++; (*used)++; }
00889 if (*p == '\n') { p++; (*used)++; }
00890 strncpy(req->query_string, p, dlen);
00891 req->query_string[dlen] = '\0';
00892 len = strlen(req->query_string);
00893 }
00894
00895 *used += len;
00896 p = &request[*used];
00897 if (*p == '\r') { p++; (*used)++; }
00898 if (*p == '\n') { p++; (*used)++; }
00899
00900 return 0;
00901 }
00902
00903 #define HEXDIGIT(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
00904 ((c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 0xA : \
00905 ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 0xA : -1)))
00906
00907 void urldecode(char *str, char **decoded)
00908 {
00909 char dbuf[HTTP_PARSE_BUFSIZE];
00910 char *src, *dst;
00911 int len;
00912
00913 for (src = str, dst = dbuf, len = 0; *src && len < HTTP_PARSE_BUFSIZE; src++, dst++, len++)
00914 {
00915 switch (*src)
00916 {
00917 case '+':
00918 *dst = ' ';
00919 break;
00920
00921 case '%':
00922 src++;
00923 if (*src == '%')
00924 *dst = '%';
00925 else
00926 *dst = (HEXDIGIT(src[0])) << 4 | (HEXDIGIT(src[1]));
00927 src++;
00928 break;
00929
00930 default:
00931 *dst = *src;
00932 break;
00933 }
00934 }
00935
00936 *dst = '\0';
00937
00938 *decoded = strndup(dbuf, len);
00939 }
00940
00941 static int parse_cgi_vars(cp_http_request *req)
00942 {
00943 regmatch_t rm[MATCHMAX];
00944 int len;
00945 char *pos;
00946 char *raw_name, *raw_value;
00947 char *name, *value;
00948
00949 req->prm =
00950 cp_hashtable_create_by_option(COLLECTION_MODE_NOSYNC |
00951 COLLECTION_MODE_DEEP, 10,
00952 cp_hash_string, cp_hash_compare_string,
00953 NULL, (cp_destructor_fn) free,
00954 NULL, (cp_destructor_fn) free);
00955
00956 for (pos = req->query_string;
00957 regexec(&re_request_vars, pos, MATCHMAX, rm, 0) == 0;
00958 pos = &pos[rm[0].rm_eo])
00959 {
00960 len = rm[1].rm_eo - rm[1].rm_so;
00961 raw_name = strndup(&pos[rm[1].rm_so], len);
00962
00963 len = rm[2].rm_eo - rm[2].rm_so;
00964 raw_value = strndup(&pos[rm[2].rm_so], len);
00965
00966 urldecode(raw_name, &name);
00967 urldecode(raw_value, &value);
00968 free(raw_name);
00969 free(raw_value);
00970
00971 cp_hashtable_put(req->prm, name, value);
00972 }
00973
00974 return 0;
00975 }
00976
00977 char *cp_http_request_get_header(cp_http_request *req, char *header)
00978 {
00979 char *res = NULL;
00980
00981 if (req && header)
00982 res = cp_hashtable_get(req->header, header);
00983
00984 return res;
00985 }
00986
00987 char **cp_http_request_get_headers(cp_http_request *request)
00988 {
00989 char **res = NULL;
00990
00991 if (request) res = (char **) cp_hashtable_get_keys(request->header);
00992
00993 return res;
00994 }
00995
00996 char *cp_http_request_get_parameter(cp_http_request *request, char *name)
00997 {
00998 char *res = NULL;
00999
01000 if (request && name && request->prm)
01001 res = cp_hashtable_get(request->prm, name);
01002
01003 return res;
01004 }
01005
01006 #ifdef CP_USE_HTTP_SESSIONS
01007 cp_http_session *
01008 cp_http_request_get_session(cp_http_request *request, int create)
01009 {
01010 if (request->session == NULL && create)
01011 request->session = cp_httpsocket_create_session(request->owner);
01012
01013 return request->session;
01014 }
01015 #endif
01016
01017 void cp_http_request_dump(cp_http_request *req)
01018 {
01019 int i;
01020 char **keys;
01021
01022 cp_info("dumping http request (%lX)", (long) req);
01023 cp_info("--------------------------------------------------------------");
01024 cp_info("method: %s", cp_http_request_type_lit[req->type]);
01025 cp_info("version: HTTP/%s", cp_http_version_lit[req->version]);
01026 cp_info("uri: [%s]", req->uri);
01027
01028 cp_info("headers:\n--------");
01029 keys = (char **) cp_hashtable_get_keys(req->header);
01030 for (i = 0; i < cp_hashtable_count(req->header); i++)
01031 cp_info("%s: %s", keys[i], (char *) cp_hashtable_get(req->header, keys[i]));
01032 free(keys);
01033
01034 #ifdef CP_USE_COOKIES
01035 if (req->cookie)
01036 {
01037 int n;
01038 cp_info("cookies:\n--------");
01039 n = cp_vector_size(req->cookie);
01040 for (i = 0; i < n; i++)
01041 cp_info("%s", cp_vector_element_at(req->cookie, i));
01042 }
01043 #endif
01044
01045 if (req->prm)
01046 {
01047 cp_info("cgi parameters:\n---------------");
01048 keys = (char **) cp_hashtable_get_keys(req->prm);
01049 for(i = 0; i < cp_hashtable_count(req->prm); i++)
01050 cp_info("%s: %s", keys[i], (char *) cp_hashtable_get(req->prm, keys[i]));
01051 free(keys);
01052 }
01053
01054 cp_info("--------------------------------------------------------------");
01055 }
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082 cp_http_response *cp_http_response_create(cp_http_request *req)
01083 {
01084 cp_http_response *res = NULL;
01085
01086 if ((res = (cp_http_response *) calloc(1, sizeof(cp_http_response))))
01087 {
01088 res->request = req;
01089 res->header =
01090 cp_hashtable_create_by_option(COLLECTION_MODE_NOSYNC |
01091 COLLECTION_MODE_COPY |
01092 COLLECTION_MODE_DEEP,
01093 10,
01094 cp_hash_string,
01095 cp_hash_compare_string,
01096 (cp_copy_fn) strdup, free,
01097 (cp_copy_fn) strdup, free);
01098 if (res->header == NULL)
01099 {
01100 free(res);
01101 return NULL;
01102 }
01103 res->status = HTTP_200_OK;
01104 res->version = req ? req->version : HTTP_1_1;
01105 res->servername = req && req->owner ? req->owner->server_name : DEFAULT_SERVER_NAME;
01106 }
01107
01108 return res;
01109 }
01110
01111 void cp_http_response_delete(cp_http_response *response)
01112 {
01113 if (response)
01114 {
01115 if (response->header)
01116 cp_hashtable_destroy(response->header);
01117 #ifdef CP_USE_COOKIES
01118 if (response->cookie)
01119 cp_vector_destroy_custom(response->cookie, free);
01120 #endif
01121 if (response->content_type_lit)
01122 free(response->content_type_lit);
01123 if (response->content)
01124 cp_string_delete(response->content);
01125
01126
01127
01128 if (response->status_lit)
01129 free(response->status_lit);
01130 free(response);
01131 }
01132 }
01133
01134 void cp_http_response_destroy(cp_http_response *res)
01135 {
01136 cp_http_response_delete(res);
01137 }
01138
01139 int cp_http_response_write(cp_connection_descriptor *cdesc,
01140 cp_http_response *res)
01141 {
01142 char rbuf[HTTP_PARSE_BUFSIZE];
01143 char *content = NULL;
01144 int content_len = 0;
01145 int len;
01146 int rc, total;
01147 int fd = cp_connection_descriptor_get_fd(cdesc);
01148 #ifdef CP_USE_SSL
01149 cp_socket *sock = cp_connection_descriptor_get_socket(cdesc);
01150 #endif
01151
01152 if (res->len == 0 && res->body) res->len = strlen(res->body);
01153
01154 #ifdef CP_HAS_SNPRINTF
01155 snprintf(rbuf, HTTP_PARSE_BUFSIZE,
01156 "HTTP/%s %s\r\n"
01157 "Server: %s\r\n"
01158 "Connection: %s\r\n",
01159 cp_http_version_lit[res->version],
01160 (char *) cp_hashtable_get(cp_http_status_lit, &res->status),
01161 res->servername ? res->servername : DEFAULT_SERVER_NAME,
01162 connection_policy_lit[res->connection]);
01163 #else
01164 sprintf(rbuf,
01165 "HTTP/%s %s\r\n"
01166 "Server: %s\r\n"
01167 "Connection: %s\r\n",
01168 cp_http_version_lit[res->version],
01169 (char *) cp_hashtable_get(cp_http_status_lit, &res->status),
01170 res->servername ? res->servername : DEFAULT_SERVER_NAME,
01171 connection_policy_lit[res->connection]);
01172 #endif
01173
01174 if (res->header)
01175 {
01176 char hbuf[HTTP_PARSE_BUFSIZE];
01177 int i;
01178 char **key = (char **) cp_hashtable_get_keys(res->header);
01179 for (i = 0; i < cp_hashtable_count(res->header); i++)
01180 {
01181 #ifdef CP_HAS_SNPRINTF
01182 snprintf(hbuf, HTTP_PARSE_BUFSIZE, "%s: %s\r\n",
01183 key[i], (char *) cp_hashtable_get(res->header, key[i]));
01184 #else
01185 sprintf(hbuf, "%s: %s\r\n",
01186 key[i], (char *) cp_hashtable_get(res->header, key[i]));
01187 #endif
01188 strlcat(rbuf, hbuf, HTTP_PARSE_BUFSIZE);
01189 }
01190 free(key);
01191 }
01192
01193 #ifdef CP_USE_COOKIES
01194 if (res->cookie)
01195 {
01196 char cbuf[HTTP_PARSE_BUFSIZE];
01197 int i;
01198 for (i = 0; i < cp_vector_size(res->cookie); i++)
01199 {
01200 #ifdef CP_HAS_SNPRINTF
01201 snprintf(cbuf, HTTP_PARSE_BUFSIZE, "Set-Cookie: %s\r\n",
01202 (char *) cp_vector_element_at(res->cookie, i));
01203 #else
01204 sprintf(cbuf, "Set-Cookie: %s\r\n",
01205 (char *) cp_vector_element_at(res->cookie, i));
01206 #endif
01207 strlcat(rbuf, cbuf, HTTP_PARSE_BUFSIZE);
01208 }
01209 }
01210 #endif
01211
01212 if (res->content)
01213 {
01214 char bbuf[HTTP_PARSE_BUFSIZE];
01215 #ifdef CP_HAS_SNPRINTF
01216 snprintf(bbuf, HTTP_PARSE_BUFSIZE,
01217 "Content-Type: %s\r\nContent-Length: %d\r\n\r\n",
01218 res->content_type_lit ?
01219 res->content_type_lit : content_type_lit[res->content_type],
01220 res->content->len);
01221 #else
01222 sprintf(bbuf, "Content-Type: %s\r\nContent-Length: %d\r\n\r\n",
01223 res->content_type_lit ?
01224 res->content_type_lit : content_type_lit[res->content_type],
01225 res->content->len);
01226 #endif
01227 strlcat(rbuf, bbuf, HTTP_PARSE_BUFSIZE);
01228 content = res->content->data;
01229 content_len = res->content->len;
01230 }
01231 else if (res->body)
01232 {
01233 char bbuf[HTTP_PARSE_BUFSIZE];
01234 content_len = strlen(res->body);
01235 #ifdef CP_HAS_SNPRINTF
01236 snprintf(bbuf, HTTP_PARSE_BUFSIZE,
01237 "Content-Type: %s\r\nContent-Length: %d\r\n\r\n",
01238 res->content_type_lit ?
01239 res->content_type_lit : content_type_lit[res->content_type],
01240 content_len);
01241 #else
01242 sprintf(bbuf, "Content-Type: %s\r\nContent-Length: %d\r\n\r\n",
01243 res->content_type_lit ?
01244 res->content_type_lit : content_type_lit[res->content_type],
01245 content_len);
01246 #endif
01247 strlcat(rbuf, bbuf, HTTP_PARSE_BUFSIZE);
01248 content = res->body;
01249 }
01250
01251 len = strlen(rbuf);
01252
01253 #ifdef CP_USE_SSL
01254 if (sock->use_ssl)
01255 {
01256 rc = SSL_write(cdesc->ssl, rbuf, len);
01257 total = rc;
01258 if (content_len)
01259 {
01260 rc = SSL_write(cdesc->ssl, content, content_len);
01261 total += rc;
01262 }
01263 }
01264 else
01265 #endif
01266 {
01267 rc = send(fd, rbuf, len, 0);
01268 total = rc;
01269 if (content_len)
01270 {
01271 rc = send(fd, content, content_len, 0);
01272 total += rc;
01273 }
01274 }
01275
01276 #ifdef __TRACE__
01277 cp_info("----- http response headers -----\n%s", rbuf);
01278 if (res->content)
01279 cp_ndump(LOG_LEVEL_INFO, res->content, 0x400);
01280 else if (res->body)
01281 cp_nlog(0x400, content);
01282 if (content_len > 0x400)
01283 cp_log("\n ... truncated (%d bytes)\n", content_len);
01284 cp_info("---------------------------------\n");
01285 #endif
01286
01287 if (total > 0) cdesc->bytes_sent += total;
01288
01289 #ifdef DEBUG
01290 DEBUGMSG("%d bytes written", total);
01291 #endif
01292
01293 return rc;
01294 }
01295
01296 void cp_http_response_set_status(cp_http_response *response,
01297 cp_http_status_code status)
01298 {
01299 response->status = status;
01300 }
01301
01302 cp_http_status_code cp_http_response_get_status(cp_http_response *response)
01303 {
01304 return response->status;
01305 }
01306
01307 void cp_http_response_set_content_type(cp_http_response *response,
01308 cp_http_content_type type)
01309 {
01310 response->content_type = type;
01311 }
01312
01313 void cp_http_response_set_content_type_string(cp_http_response *response,
01314 char *content_type)
01315 {
01316 response->content_type_lit = content_type ? strdup(content_type) : NULL;
01317 }
01318
01319 char *cp_http_response_get_content_type(cp_http_response *response)
01320 {
01321 return response->header ? cp_hashtable_get(response->header, "Content-Type"): NULL;
01322 }
01323
01324 void cp_http_response_set_header(cp_http_response *response,
01325 char *name, char *value)
01326 {
01327 cp_hashtable_put(response->header, name, value);
01328 }
01329
01330 char *cp_http_response_get_header(cp_http_response *response, char *name)
01331 {
01332 return cp_hashtable_get(response->header, name);
01333 }
01334
01335 cp_vector *cp_http_response_get_header_names(cp_http_response *response)
01336 {
01337 cp_vector *names = NULL;
01338 if (response->header)
01339 {
01340 int len = cp_hashtable_count(response->header);
01341 names = cp_vector_wrap(cp_hashtable_get_keys(response->header), len, 0);
01342 if (names == NULL) return NULL;
01343 }
01344
01345 return names;
01346 }
01347
01348 void cp_http_response_set_body(cp_http_response *response,
01349 char *body)
01350 {
01351 response->body = strdup(body);
01352 }
01353
01354 void cp_http_response_set_content(cp_http_response *response,
01355 cp_string *content)
01356 {
01357 response->content = content;
01358 }
01359
01360 cp_string *cp_http_response_get_content(cp_http_response *response)
01361 {
01362 return response->content;
01363 }
01364
01365 void cp_http_response_set_connection_policy(cp_http_response *response,
01366 connection_policy policy)
01367 {
01368 response->connection = policy;
01369 }
01370
01371 #ifdef CP_USE_COOKIES
01372 int cp_http_response_set_cookie(cp_http_response *response, char *name,
01373 char *content, char *host, char *path, long validity, int secure)
01374 {
01375 char cookie[MAX_COOKIE_LENGTH];
01376 char expiration[0x50];
01377 time_t now;
01378 struct tm gmt;
01379 #ifndef CP_HAS_GMTIME_R
01380 struct tm *pgmt;
01381 #endif
01382 char *domain;
01383
01384 now = time(NULL);
01385
01386 now += validity;
01387 #ifdef CP_HAS_GMTIME_R
01388 gmtime_r(&now, &gmt);
01389 #else
01390 pgmt = gmtime(&now);
01391 gmt = *pgmt;
01392 #endif
01393 strftime(expiration, 0x50, COOKIE_TIME_FMT, &gmt);
01394
01395 if (host)
01396 {
01397 if (strncmp(host, "www.", 4) == 0)
01398 domain = &host[3];
01399 else
01400 domain = NULL;
01401 }
01402 else
01403 domain = NULL;
01404
01405 #ifdef CP_HAS_SNPRINTF
01406 snprintf(cookie, MAX_COOKIE_LENGTH, "%s=%s; expires=%s", name, content, expiration);
01407 #else
01408 sprintf(cookie, "%s=%s; expires=%s", name, content, expiration);
01409 #endif
01410 if (path)
01411 {
01412 strlcat(cookie, "; path=", MAX_COOKIE_LENGTH);
01413 strlcat(cookie, path, MAX_COOKIE_LENGTH);
01414 }
01415 if (domain)
01416 {
01417 strlcat(cookie, "; domain=", MAX_COOKIE_LENGTH);
01418 strlcat(cookie, domain, MAX_COOKIE_LENGTH);
01419 }
01420 if (secure) strlcat(cookie, "; secure", MAX_COOKIE_LENGTH);
01421
01422 #ifdef __TRACE__
01423 DEBUGMSG("setting cookie (%d chars): %s", strlen(cookie), cookie);
01424 #endif
01425 if (response->cookie == NULL)
01426 {
01427 response->cookie = cp_vector_create(1);
01428 if (response->cookie == NULL) return -1;
01429 }
01430
01431 cp_vector_add_element(response->cookie, strdup(cookie));
01432
01433 return 0;
01434 }
01435 #endif
01436
01437 void cp_http_response_skip(cp_http_response *response)
01438 {
01439 response->skip = 1;
01440 }
01441
01442
01443 static int cp_http_write_server_error(cp_connection_descriptor *cdesc,
01444 int status_code)
01445 {
01446 char errbuf[HTTP_PARSE_BUFSIZE];
01447 char *lit;
01448 int rc;
01449
01450 cp_http_response *res = cp_http_response_create(NULL);
01451
01452 if (res == NULL) return CP_MEMORY_ALLOCATION_FAILURE;
01453
01454 cp_http_response_set_status(res, HTTP_400_BAD_REQUEST);
01455
01456 lit = cp_hashtable_get(cp_http_server_error, &status_code);
01457
01458 if (lit)
01459 #ifdef CP_HAS_SNPRINTF
01460 snprintf(errbuf, HTTP_PARSE_BUFSIZE, server_error_fmt, lit);
01461 #else
01462 sprintf(errbuf, server_error_fmt, lit);
01463 #endif
01464 else
01465 errbuf[0] = '\0';
01466
01467 cp_http_response_set_content_type(res, HTML);
01468
01469 res->body = errbuf;
01470
01471 rc = cp_http_response_write(cdesc, res);
01472
01473 res->body = NULL;
01474 cp_http_response_delete(res);
01475
01476 return rc;
01477 }
01478
01479
01480
01481
01482
01483
01484
01485
01486 cp_httpsocket *cp_httpsocket_create(int port, cp_http_service_callback service)
01487 {
01488 cp_socket *sock;
01489 cp_httpsocket *psock;
01490
01491 cp_http_init();
01492
01493 sock = cp_socket_create(port, CPSOCKET_STRATEGY_THREADPOOL, cp_http_thread_fn);
01494 if (sock == NULL) return NULL;
01495
01496 psock = (cp_httpsocket *) calloc(1, sizeof(cp_httpsocket));
01497 if (psock == NULL)
01498 {
01499 cp_socket_delete(sock);
01500 cp_error(CP_MEMORY_ALLOCATION_FAILURE, "can\'t allocate cp_httpsocket");
01501 }
01502
01503 psock->id = socket_reg_id++;
01504 cp_hashlist_append(socket_registry, &psock->id, psock);
01505
01506 psock->sock = sock;
01507 cp_socket_set_owner(sock, psock);
01508
01509 psock->default_service = service;
01510 cp_httpsocket_set_keepalive(psock, HTTP_KEEPALIVE);
01511
01512 return psock;
01513 }
01514
01515 #ifdef CP_USE_SSL
01516 cp_httpsocket *cp_httpsocket_create_ssl(int port,
01517 cp_http_service_callback service,
01518 char *certificate_file,
01519 char *key_file,
01520 int verification_mode)
01521 {
01522 cp_socket *sock;
01523 cp_httpsocket *psock;
01524
01525 cp_http_init();
01526
01527 sock = cp_socket_create_ssl(port, CPSOCKET_STRATEGY_THREADPOOL,
01528 cp_http_thread_fn, certificate_file,
01529 key_file, verification_mode);
01530
01531 if (sock == NULL) return NULL;
01532
01533 psock = (cp_httpsocket *) calloc(1, sizeof(cp_httpsocket));
01534 if (psock == NULL)
01535 {
01536 cp_socket_delete(sock);
01537 cp_error(CP_MEMORY_ALLOCATION_FAILURE, "can\'t allocate cp_httpsocket");
01538 }
01539
01540 psock->sock = sock;
01541 cp_socket_set_owner(sock, psock);
01542
01543 psock->default_service = service;
01544 cp_httpsocket_set_keepalive(psock, HTTP_KEEPALIVE);
01545
01546 return psock;
01547 }
01548 #endif
01549
01550 void cp_httpsocket_set_keepalive(cp_httpsocket *socket, int sec)
01551 {
01552 socket->keepalive = sec;
01553 }
01554
01555 void cp_httpsocket_set_server_name(cp_httpsocket *socket, char *name)
01556 {
01557 socket->server_name = strdup(name);
01558 }
01559
01560 void cp_httpsocket_set_backlog(cp_httpsocket *socket, int backlog)
01561 {
01562 cp_socket_set_backlog(socket->sock, backlog);
01563 }
01564
01565 void cp_httpsocket_set_delay(cp_httpsocket *socket, struct timeval delay)
01566 {
01567 cp_socket_set_delay(socket->sock, delay);
01568 }
01569
01570 void cp_httpsocket_set_delay_sec(cp_httpsocket *socket, long sec)
01571 {
01572 cp_socket_set_delay_sec(socket->sock, sec);
01573 }
01574
01575 void cp_httpsocket_set_delay_usec(cp_httpsocket *socket, long usec)
01576 {
01577 cp_socket_set_delay_usec(socket->sock, usec);
01578 }
01579
01580 void cp_httpsocket_set_poolsize_min(cp_httpsocket *socket, int min)
01581 {
01582 cp_socket_set_poolsize_min(socket->sock, min);
01583 }
01584
01585 void cp_httpsocket_set_poolsize_max(cp_httpsocket *socket, int max)
01586 {
01587 cp_socket_set_poolsize_max(socket->sock, max);
01588 }
01589
01590 void cp_httpsocket_delete(cp_httpsocket *sock)
01591 {
01592 if (sock)
01593 {
01594 if (socket_registry)
01595 cp_hashlist_remove(socket_registry, &sock->id);
01596
01597 cp_socket_delete(sock->sock);
01598 #ifdef CP_USE_HTTP_SESSIONS
01599 if (sock->session)
01600 cp_hashlist_destroy_deep(sock->session);
01601 if (sock->pending)
01602 cp_hashlist_destroy_custom(sock->pending, NULL,
01603 (cp_destructor_fn) cp_http_response_delete);
01604 #endif
01605 if (sock->service)
01606 cp_trie_destroy(sock->service);
01607 if (sock->server_name)
01608 free(sock->server_name);
01609 free(sock);
01610 }
01611 }
01612
01613 void *cp_httpsocket_add_shutdown_callback(cp_httpsocket *socket,
01614 void (*cb)(void *),
01615 void *prm)
01616 {
01617 return cp_socket_add_shutdown_callback(socket->sock, cb, prm);
01618 }
01619
01620 int cp_httpsocket_listen(cp_httpsocket *sock)
01621 {
01622 int rc;
01623
01624 rc = cp_socket_listen(sock->sock);
01625 if (rc == 0) rc = cp_socket_select(sock->sock);
01626
01627 return rc;
01628 }
01629
01630 int cp_httpsocket_register_service(cp_httpsocket *server,
01631 cp_http_service *service)
01632 {
01633 int rc = 0;
01634
01635 if (server->service == NULL)
01636 {
01637 server->service =
01638 cp_trie_create_trie(COLLECTION_MODE_DEEP, NULL,
01639 (cp_destructor_fn) cp_http_service_delete);
01640 if (server->service == NULL)
01641 return -1;
01642 }
01643
01644 rc = cp_trie_add(server->service, service->path, service);
01645
01646 return rc;
01647 }
01648
01649 void *cp_httpsocket_unregister_service(cp_httpsocket *server,
01650 cp_http_service *service)
01651 {
01652 if (server->service)
01653 {
01654 void *rm = NULL;
01655 cp_trie_remove(server->service, service->path, &rm);
01656 return rm;
01657 }
01658
01659 return NULL;
01660 }
01661
01662
01663
01664
01665
01666
01667
01668
01669 cp_http_service *cp_http_service_create(char *name,
01670 char *path,
01671 cp_http_service_callback callback)
01672 {
01673 cp_http_service *svc;
01674
01675 svc = (cp_http_service *) calloc(1, sizeof(cp_http_service));
01676 if (svc == NULL)
01677 {
01678 cp_error(CP_MEMORY_ALLOCATION_FAILURE, "can\'t allocate cp_http_service");
01679 return NULL;
01680 }
01681
01682 svc->name = strdup(name);
01683 svc->path = strdup(path);
01684 svc->service = callback;
01685
01686 return svc;
01687 }
01688
01689 void cp_http_service_delete(cp_http_service *service)
01690 {
01691 if (service)
01692 {
01693 free(service->name);
01694 free(service->path);
01695 free(service);
01696 }
01697 else
01698 cp_warn("cp_http_service_delete: attempting to delete NULL service");
01699 }
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713 static int cp_http_default_response(cp_http_request *request, cp_http_response *response)
01714 {
01715 char buf[0x400];
01716
01717 cp_warn("cp_http: no service defined for uri [%s]", request->uri);
01718
01719 cp_http_response_set_content_type(response, HTML);
01720 cp_http_response_set_status(response, HTTP_501_NOT_IMPLEMENTED);
01721
01722 #ifdef CP_HAS_SNPRINTF
01723 snprintf(buf, 0x400, "<html><head><title>%s: 501 NOT IMPLEMENTED</title></head><body><h1>Welcome to %s</h1>Your request [%s] could not be served: this server is not configured.<h1></body></html>", response->servername ? response->servername : DEFAULT_SERVER_NAME, response->servername ? response->servername : DEFAULT_SERVER_NAME, request->uri);
01724 #else
01725 sprintf(buf, "<html><head><title>%s: 501 NOT IMPLEMENTED</title></head><body><h1>Welcome to %s</h1>Your request [%s] could not be served: this server is not configured.<h1></body></html>", response->servername ? response->servername : DEFAULT_SERVER_NAME, response->servername ? response->servername : DEFAULT_SERVER_NAME, request->uri);
01726 #endif
01727
01728 response->body = strdup(buf);
01729
01730 return HTTP_CONNECTION_POLICY_CLOSE;
01731 }
01732
01733 void cp_http_response_report_error(cp_http_response *response,
01734 cp_http_status_code code,
01735 char *message)
01736 {
01737 char buf[0x400];
01738 char *err = cp_hashtable_get(cp_http_status_lit, &code);
01739
01740 cp_http_response_set_content_type(response, HTML);
01741 cp_http_response_set_status(response, code);
01742
01743 #ifdef CP_HAS_SNPRINTF
01744 snprintf(buf, 0x400, "<html><head><title>%s: %s</title></head>"
01745 "<body><h1>%s</h1>"
01746 "%s</body></html>",
01747 response->servername ? response->servername : DEFAULT_SERVER_NAME,
01748 err, err, message);
01749 #else
01750 sprintf(buf, "<html><head><title>%s: %s</title></head>"
01751 "<body><h1>%s</h1>"
01752 "%s</body></html>",
01753 response->servername ? response->servername : DEFAULT_SERVER_NAME,
01754 err, err, message);
01755 #endif
01756
01757 cp_http_response_set_body(response, buf);
01758 }
01759
01760 static int get_keepalive(cp_httpsocket *sock, cp_http_request *request)
01761 {
01762 int keepalive = 0;
01763 char *ka_lit;
01764 char *con_lit;
01765
01766 con_lit = cp_hashtable_get(request->header, "Connection");
01767 if (con_lit && strcmp(con_lit, "close") == 0) return 0;
01768
01769 ka_lit = cp_hashtable_get(request->header, "Keep-Alive");
01770 if (ka_lit)
01771 keepalive = atoi(ka_lit);
01772
01773 if (keepalive > sock->keepalive ||
01774 (keepalive == 0 && request->version == HTTP_1_1))
01775 keepalive = sock->keepalive;
01776
01777 return keepalive;
01778 }
01779
01780 static int cp_httpselect(cp_httpsocket *hsock, int sec, int fd)
01781 {
01782 int rc = -1;
01783
01784 fd_set rd;
01785 struct timeval tv;
01786
01787 #ifdef __TRACE__
01788 DEBUGMSG("keepalive: %d", sec);
01789 #endif
01790
01791 FD_ZERO(&rd);
01792 FD_SET((unsigned int) fd, &rd);
01793
01794 tv.tv_sec = sec;
01795 tv.tv_usec = 0;
01796 rc = select(fd + 1, &rd, NULL, NULL, &tv);
01797 #ifdef __TRACE__
01798 DEBUGMSG("read fd: %d", FD_ISSET(fd, &rd));
01799 #endif
01800
01801 if (rc > -1) return FD_ISSET(fd, &rd) - 1;
01802 #ifdef __TRACE__
01803 else DEBUGMSG("select: %s", strerror(errno));
01804 #endif
01805
01806 return rc;
01807 }
01808
01809 static int find_newline(char *buf)
01810 {
01811 char *p = strstr(buf, "\r\n");
01812 if (p == NULL) p = strchr(buf, '\n');
01813 if (p == NULL) return -1;
01814 return p - buf;
01815 }
01816
01817 static int check_newline(char *buf, int *index)
01818 {
01819 return (strncmp(buf, "\r\n\r\n", 4) == 0) ||
01820 (strncmp(buf, "\n\n", 2) == 0);
01821 }
01822
01823 static int
01824 incremental_request_parse(cp_httpsocket *sock, cp_http_request **request,
01825 int *stage, cp_string *state, char *curr,
01826 int len, int *used)
01827 {
01828 int rc;
01829 char *buf;
01830
01831
01832
01833
01834 if (state->len)
01835 {
01836 cp_string_cat_bin(state, curr, len);
01837 len = state->len;
01838 cp_string_tocstr(state);
01839 buf = state->data;
01840 }
01841 else
01842 buf = curr;
01843
01844 switch (*stage)
01845 {
01846 case REQUEST_STAGE_START:
01847 *used = 0;
01848 *request = calloc(1, sizeof(cp_http_request));
01849 if (*request == NULL) return CP_MEMORY_ALLOCATION_FAILURE;
01850 (*request)->owner = sock;
01851 *stage = REQUEST_STAGE_STATUS_LINE;
01852
01853 case REQUEST_STAGE_STATUS_LINE:
01854 if (find_newline(buf) == -1)
01855 {
01856 if (buf != state->data)
01857 cp_string_cstrcpy(state, buf);
01858 break;
01859 }
01860 if ((rc = parse_request_line(*request, buf, used)))
01861 return rc;
01862 if (check_newline(buf, used))
01863 {
01864 *stage = REQUEST_STAGE_DONE;
01865 break;
01866 }
01867 *stage = REQUEST_STAGE_HEADERS;
01868 if (*used == len) break;
01869
01870 case REQUEST_STAGE_HEADERS:
01871 if ((rc = parse_headers(*request, buf, used, stage)))
01872 return rc;
01873 if (*stage == REQUEST_STAGE_DONE &&
01874 cp_http_request_get_header(*request, "Content-Length"))
01875 *stage = REQUEST_STAGE_BODY;
01876 if (*used == len) break;
01877
01878 case REQUEST_STAGE_BODY:
01879 if ((rc = parse_cp_http_request_body(*request, buf, used)))
01880 return rc;
01881 if (*used == len) *stage = REQUEST_STAGE_DONE;
01882 }
01883
01884 return 0;
01885 }
01886
01887
01888 static int post_process(cp_httpsocket *socket, cp_http_request *req)
01889 {
01890 int rc;
01891
01892
01893 if (req->query_string)
01894 {
01895 if ((rc = parse_cgi_vars(req)))
01896 return rc;
01897 }
01898
01899
01900 #ifdef CP_USE_HTTP_SESSIONS
01901 {
01902 char *sid;
01903 #ifdef CP_USE_COOKIES
01904 if (req->cookie)
01905 {
01906 char *cookie;
01907 int i;
01908 int n = cp_vector_size(req->cookie);
01909 for (i = 0; i < n; i++)
01910 {
01911 cookie = cp_vector_element_at(req->cookie, i);
01912 if (strncmp(cookie,
01913 CP_HTTP_SESSION_MARKER, CP_HTTP_SESSION_MARKER_LEN) == 0)
01914 {
01915 sid = &cookie[CP_HTTP_SESSION_MARKER_LEN];
01916 req->session = cp_httpsocket_checkout_session(socket, sid);
01917 if (req->session == NULL)
01918 cp_warn("can\'t find session record %s", sid);
01919 else
01920 {
01921 req->session->type = SESSION_TYPE_COOKIE;
01922 req->session->access = time(NULL);
01923
01924 }
01925 }
01926 }
01927 }
01928 if (req->session == NULL)
01929 #endif
01930 {
01931 sid = cp_http_request_get_parameter(req, CP_HTTP_SESSION_PRM);
01932 if (sid)
01933 {
01934 req->session = cp_httpsocket_checkout_session(socket, sid);
01935 if (req->session == NULL)
01936 cp_warn("can\'t find session record %s", sid);
01937 else
01938 {
01939 req->session->type = SESSION_TYPE_URLREWRITE;
01940 req->session->access = time(NULL);
01941 }
01942 }
01943 }
01944 }
01945 #endif
01946
01947 return 0;
01948 }
01949
01950 static int read_request(cp_list *req_list, cp_connection_descriptor *cdesc)
01951 {
01952 char tmpbuf[HTTP_PARSE_BUFSIZE + 1];
01953 cp_string *buf = cp_string_create_empty(HTTP_PARSE_BUFSIZE);
01954 int rc;
01955 int len;
01956 int fd = 0;
01957 cp_socket *sock = cp_connection_descriptor_get_socket(cdesc);
01958 cp_http_request *request = NULL;
01959 int done_reading = 0;
01960 int stage = REQUEST_STAGE_START;
01961 int used;
01962
01963 #ifdef CP_USE_SSL
01964 if (!sock->use_ssl)
01965 #endif
01966 fd = cp_connection_descriptor_get_fd(cdesc);
01967
01968 while (!done_reading)
01969 {
01970 #ifdef CP_USE_SSL
01971 if (sock->use_ssl)
01972 {
01973 if ((len = SSL_read(cdesc->ssl, tmpbuf, HTTP_PARSE_BUFSIZE)) <= 0)
01974 break;
01975 }
01976 else
01977 #endif
01978 if ((len = recv(fd, tmpbuf, HTTP_PARSE_BUFSIZE, 0)) <= 0) break;
01979 if (len <= 0) break;
01980 tmpbuf[len] = '\0';
01981 cdesc->bytes_read += len;
01982 used = 0;
01983
01984 #ifdef _HTTP_DUMP
01985 DEBUGMSG("\n---------------------------------------------------------------------------" "\n%s\n" "---------------------------------------------------------------------------", tmpbuf);
01986 #endif
01987
01988
01989 rc = incremental_request_parse((cp_httpsocket *) sock->owner, &request,
01990 &stage, buf, tmpbuf, len, &used);
01991 if (rc)
01992 {
01993 if (request)
01994 cp_http_request_delete(request);
01995 return rc;
01996 }
01997
01998 if (stage == REQUEST_STAGE_DONE)
01999 {
02000 if (request)
02001 {
02002
02003 if ((rc = post_process(sock->owner, request)))
02004 {
02005 cp_list_append(req_list, (void *) (long) -rc);
02006 cp_http_request_delete(request);
02007 break;
02008 }
02009 else
02010 cp_list_append(req_list, request);
02011 }
02012 else
02013 cp_list_append(req_list, (void *) (long) -rc);
02014
02015 if (used == len)
02016 done_reading = 1;
02017 else
02018 {
02019 request = NULL;
02020 stage = REQUEST_STAGE_START;
02021 buf->len = 0;
02022 }
02023 }
02024 }
02025
02026 if (buf) cp_string_destroy(buf);
02027 return cp_list_item_count(req_list);
02028 }
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039 void *cp_http_thread_fn(void *prm)
02040 {
02041 cp_connection_descriptor *cdesc;
02042 cp_socket *sock;
02043 struct sockaddr_in *addr;
02044 int fd;
02045 int rc = 0;
02046 int done;
02047 int action;
02048 int keepalive = HTTP_CONNECTION_POLICY_DEFAULT;
02049 cp_http_request *request = NULL;
02050 cp_httpsocket *hsock;
02051 cp_http_service_callback svc;
02052 cp_list *req_list =
02053 cp_list_create_list(COLLECTION_MODE_NOSYNC |
02054 COLLECTION_MODE_MULTIPLE_VALUES, NULL, NULL, NULL);
02055
02056 cdesc = (cp_connection_descriptor *) prm;
02057 sock = cp_connection_descriptor_get_socket(cdesc);
02058 fd = cp_connection_descriptor_get_fd(cdesc);
02059 hsock = (cp_httpsocket *) sock->owner;
02060
02061 addr = cp_connection_descriptor_get_addr(cdesc);
02062
02063 #ifdef __TRACE__
02064 cp_info("\n\n *** connection from %s:%d\n",
02065 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
02066 #endif
02067
02068 done = 0;
02069
02070 while (!done && !sock->closing && !cp_http_stopping)
02071 {
02072 svc = hsock->default_service;
02073 action = HTTP_CONNECTION_POLICY_DEFAULT;
02074
02075
02076 if ((rc = read_request(req_list, cdesc)) == -1)
02077 {
02078 rc = errno;
02079 cp_perror(CP_IO_ERROR, rc, "serving request from %s:%d on port %d",
02080 inet_ntoa(addr->sin_addr), addr->sin_port,
02081 sock->port);
02082 continue;
02083 }
02084
02085
02086 if (rc == 0) break;
02087
02088
02089 while ((request = cp_list_remove_head(req_list)))
02090 {
02091 cp_http_response *res;
02092 long err = (long) request;
02093 if (err < 0)
02094 {
02095 cp_http_write_server_error(cdesc, -err);
02096 continue;
02097 }
02098
02099 request->connection = cdesc;
02100 #ifdef CP_USE_HTTP_SESSIONS
02101
02102 res = NULL;
02103 if (request->session && request->session->fresh)
02104 {
02105 #ifdef CP_USE_COOKIES
02106 if (request->session->type == SESSION_TYPE_COOKIE &&
02107 cp_http_request_get_parameter(request, CP_HTTP_SESSION_PRM))
02108 res = cp_http_new_session_redirect(request, 2);
02109 else
02110 #endif
02111 {
02112 res = cp_hashlist_get(hsock->pending, request->session->sid);
02113 if (res)
02114 {
02115 res->request = request;
02116 request->session->fresh = 0;
02117 cp_hashlist_remove(hsock->pending, request->session->sid);
02118 }
02119 }
02120 }
02121
02122 if (res == NULL)
02123 #endif
02124 {
02125 res = cp_http_response_create(request);
02126 if (res == NULL)
02127 {
02128 cp_error(CP_MEMORY_ALLOCATION_FAILURE, "couldn\'t create response wrapper");
02129 cp_http_request_dump(request);
02130 cp_http_request_delete(request);
02131 continue;
02132 }
02133
02134
02135 if (hsock->service)
02136 {
02137 cp_http_service *desc;
02138 void *ptr;
02139 cp_trie_prefix_match(hsock->service, request->uri, &ptr);
02140 desc = ptr;
02141
02142 if (desc) svc = desc->service;
02143 #ifdef __TRACE__
02144 if (desc) DEBUGMSG("invoking service [%s]", desc->name);
02145 #endif
02146 }
02147 if (svc == NULL)
02148 svc = cp_http_default_response;
02149
02150 action = (*svc)(request, res);
02151
02152 if (action != res->connection)
02153 if (res->connection == HTTP_CONNECTION_POLICY_DEFAULT)
02154 res->connection = (connection_policy) action;
02155
02156 #ifdef CP_USE_HTTP_SESSIONS
02157
02158 if (res->request->session)
02159 {
02160 if (res->request->session->fresh)
02161 {
02162 if (hsock->pending == NULL)
02163 hsock->pending =
02164 cp_hashlist_create(1, cp_hash_string,
02165 cp_hash_compare_string);
02166 cp_hashlist_append(hsock->pending,
02167 res->request->session->sid, res);
02168
02169 res = cp_http_new_session_redirect(request, 1);
02170 }
02171 }
02172 #endif
02173 }
02174
02175 if (!res->skip)
02176 cp_http_response_write(cdesc, res);
02177 cp_http_response_delete(res);
02178
02179 keepalive = get_keepalive(hsock, request);
02180 if (action == HTTP_CONNECTION_POLICY_DEFAULT)
02181 action = request->version == HTTP_1_1 ?
02182 HTTP_CONNECTION_POLICY_KEEP_ALIVE :
02183 HTTP_CONNECTION_POLICY_CLOSE;
02184
02185 cp_http_request_delete(request);
02186 }
02187
02188
02189
02190
02191 switch (action)
02192 {
02193 case HTTP_CONNECTION_POLICY_KEEP_ALIVE:
02194 if ((rc = cp_httpselect(hsock, keepalive, fd)) < 0)
02195 done = 1;
02196 #ifdef __TRACE__
02197 DEBUGMSG("rc: %d", rc);
02198 #endif
02199 break;
02200
02201 case HTTP_CONNECTION_POLICY_CLOSE:
02202 done = 1;
02203 break;
02204 }
02205 }
02206
02207 cp_list_destroy_custom(req_list,
02208 (cp_destructor_fn) cp_http_request_delete);
02209
02210 #ifdef __TRACE__
02211 if (rc == 0)
02212 cp_info("done serving connection from %s:%d\n",
02213 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
02214 #endif
02215
02216 cp_connection_descriptor_destroy(cdesc);
02217
02218 return NULL;
02219 }
02220