static int proxy_create_env(server *srv, handler_ctx *hctx) { size_t i; connection *con = hctx->remote_conn; buffer *b; /* build header */ b = buffer_init(); /* request line */ buffer_copy_string(b, get_http_method_name(con->request.http_method)); buffer_append_string_len(b, CONST_STR_LEN(" ")); buffer_append_string_buffer(b, con->request.uri); buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n")); proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr))); /* http_host is NOT is just a pointer to a buffer * which is NULL if it is not set */ if (!buffer_string_is_empty(con->request.http_host)) { proxy_set_header(con, "X-Host", con->request.http_host->ptr); } proxy_set_header(con, "X-Forwarded-Proto", con->uri.scheme->ptr); /* request header */ for (i = 0; i < con->request.headers->used; i++) { data_string *ds; ds = (data_string *)con->request.headers->data[i]; if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) { if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue; if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue; buffer_append_string_buffer(b, ds->key); buffer_append_string_len(b, CONST_STR_LEN(": ")); buffer_append_string_buffer(b, ds->value); buffer_append_string_len(b, CONST_STR_LEN("\r\n")); } } buffer_append_string_len(b, CONST_STR_LEN("\r\n")); hctx->wb->bytes_in += buffer_string_length(b); chunkqueue_append_buffer(hctx->wb, b); buffer_free(b); /* body */ if (con->request.content_length) { chunkqueue *req_cq = con->request_content_queue; chunkqueue_steal(hctx->wb, req_cq, req_cq->bytes_in); } return 0; }
static void prepare_lisp_request (server *srv, handler_ctx *hctx) { size_t i; buffer *buf; connection *con = hctx->connection; chunkqueue *hr_cq = hctx->request_queue; buf = chunkqueue_get_append_buffer(hr_cq); #define APPEND_HEADER(k, vt, v) \ BUFFER_APPEND_STRING_CONST(buf, k); \ BUFFER_APPEND_STRING_CONST(buf, "\n"); \ buffer_append_##vt(buf, v); \ BUFFER_APPEND_STRING_CONST(buf, "\n") #define KEY_IS(string) \ (buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN(string)) == 0) #if 0 for (i = 0; i < srv->srv_sockets.used; i++) { log_error_write(srv, __FILE__, __LINE__, "sd<S>", "srv_sockets", i, inet_ntop_cache_get_ip(srv, &(srv->srv_sockets.ptr[i]->addr))); } #endif /* Mod_lisp configuration and connection info. */ APPEND_HEADER("server-id", string_buffer, hctx->socket_data->id); APPEND_HEADER("server-baseversion", string, PACKAGE_STRING); APPEND_HEADER("modlisp-version", string, MOD_LISP_VERSION); /* Server/connection configuration info. */ APPEND_HEADER("url", string_buffer, con->request.uri); APPEND_HEADER("method", string, get_http_method_name(con->request.http_method)); APPEND_HEADER("script-filename", string_buffer, con->physical.path); APPEND_HEADER("server-protocol", string, get_http_version_name(con->request.http_version)); APPEND_HEADER("remote-ip-port", long, get_remote_port(srv, con)); APPEND_HEADER("server-ip-port", long, srv->srvconf.port); APPEND_HEADER("remote-ip-addr", string, inet_ntop_cache_get_ip(srv, &(con->dst_addr))); APPEND_HEADER("server-ip-addr", string, get_local_ip(srv, con)); if (con->request.http_content_type) { APPEND_HEADER("content-type", string, con->request.http_content_type); } if (con->request.content_length) { APPEND_HEADER("content-length", long, con->request.content_length); }
connection *connection_accepted(server *srv, server_socket *srv_socket, sock_addr *cnt_addr, int cnt) { connection *con; srv->cur_fds++; /* ok, we have the connection, register it */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "appected()", cnt); #endif srv->con_opened++; con = connections_get_new_connection(srv); con->fd = cnt; con->fde_ndx = -1; fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con); connection_set_state(srv, con, CON_STATE_REQUEST_START); con->connection_start = srv->cur_ts; con->dst_addr = *cnt_addr; buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr))); con->srv_socket = srv_socket; if (-1 == fdevent_fcntl_set_nb_cloexec_sock(srv->ev, con->fd)) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); connection_close(srv, con); return NULL; } #ifdef USE_OPENSSL /* connect FD to SSL */ if (srv_socket->is_ssl) { if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); connection_close(srv, con); return NULL; } con->renegotiations = 0; SSL_set_app_data(con->ssl, con); SSL_set_accept_state(con->ssl); if (1 != (SSL_set_fd(con->ssl, cnt))) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); connection_close(srv, con); return NULL; } } #endif return con; }
static const char* get_local_ip(server *srv, connection *con) { sock_addr local_addr; socklen_t len; if (con->fd > 0 && getsockname(con->fd, &(local_addr.plain), &len) == 0) { return inet_ntop_cache_get_ip(srv, &local_addr); } return "?.?.?.?"; }
static const char *sock_addr_to_p(server *srv, sock_addr *addr) { switch (addr->plain.sa_family) { case AF_INET: return inet_ntoa(addr->ipv4.sin_addr); #ifdef HAVE_IPV6 case AF_INET6: return inet_ntop_cache_get_ip(srv, addr); #endif #ifdef HAVE_SYS_UN_H case AF_UNIX: return addr->un.sun_path; #endif } return ""; }
static handler_t mod_status_handle_server_status_html(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; buffer *b; size_t j; double avg; char multiplier = '\0'; char buf[32]; time_t ts; int days, hours, mins, seconds; b = chunkqueue_get_append_buffer(con->write_queue); BUFFER_COPY_STRING_CONST(b, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" " <head>\n" " <title>Status</title>\n"); BUFFER_APPEND_STRING_CONST(b, " <style type=\"text/css\">\n" " table.status { border: black solid thin; }\n" " td.int { background-color: #f0f0f0; text-align: right }\n" " td.string { background-color: #f0f0f0; text-align: left }\n" " th.status { background-color: black; color: white; font-weight: bold; }\n" " a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n" " span.sortarrow { color: white; text-decoration: none; }\n" " </style>\n"); if (p->conf.sort) { BUFFER_APPEND_STRING_CONST(b, "<script type=\"text/javascript\">\n" "// <!--\n" "var sort_column;\n" "var prev_span = null;\n"); BUFFER_APPEND_STRING_CONST(b, "function get_inner_text(el) {\n" " if((typeof el == 'string')||(typeof el == 'undefined'))\n" " return el;\n" " if(el.innerText)\n" " return el.innerText;\n" " else {\n" " var str = \"\";\n" " var cs = el.childNodes;\n" " var l = cs.length;\n" " for (i=0;i<l;i++) {\n" " if (cs[i].nodeType==1) str += get_inner_text(cs[i]);\n" " else if (cs[i].nodeType==3) str += cs[i].nodeValue;\n" " }\n" " }\n" " return str;\n" "}\n"); BUFFER_APPEND_STRING_CONST(b, "function sortfn(a,b) {\n" " var at = get_inner_text(a.cells[sort_column]);\n" " var bt = get_inner_text(b.cells[sort_column]);\n" " if (a.cells[sort_column].className == 'int') {\n" " return parseInt(at)-parseInt(bt);\n" " } else {\n" " aa = at.toLowerCase();\n" " bb = bt.toLowerCase();\n" " if (aa==bb) return 0;\n" " else if (aa<bb) return -1;\n" " else return 1;\n" " }\n" "}\n"); BUFFER_APPEND_STRING_CONST(b, "function resort(lnk) {\n" " var span = lnk.childNodes[1];\n" " var table = lnk.parentNode.parentNode.parentNode.parentNode;\n" " var rows = new Array();\n" " for (j=1;j<table.rows.length;j++)\n" " rows[j-1] = table.rows[j];\n" " sort_column = lnk.parentNode.cellIndex;\n" " rows.sort(sortfn);\n"); BUFFER_APPEND_STRING_CONST(b, " if (prev_span != null) prev_span.innerHTML = '';\n" " if (span.getAttribute('sortdir')=='down') {\n" " span.innerHTML = '↑';\n" " span.setAttribute('sortdir','up');\n" " rows.reverse();\n" " } else {\n" " span.innerHTML = '↓';\n" " span.setAttribute('sortdir','down');\n" " }\n" " for (i=0;i<rows.length;i++)\n" " table.tBodies[0].appendChild(rows[i]);\n" " prev_span = span;\n" "}\n" "// -->\n" "</script>\n"); } BUFFER_APPEND_STRING_CONST(b, " </head>\n" " <body>\n"); /* connection listing */ BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>"); BUFFER_APPEND_STRING_CONST(b, "<table summary=\"status\" class=\"status\">"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">"); buffer_append_string_buffer(b, con->uri.authority); BUFFER_APPEND_STRING_CONST(b, " ("); buffer_append_string_buffer(b, con->server_name); BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">"); ts = srv->cur_ts - srv->startup_ts; days = ts / (60 * 60 * 24); ts %= (60 * 60 * 24); hours = ts / (60 * 60); ts %= (60 * 60); mins = ts / (60); ts %= (60); seconds = ts; if (days) { buffer_append_long(b, days); BUFFER_APPEND_STRING_CONST(b, " days "); } if (hours) { buffer_append_long(b, hours); BUFFER_APPEND_STRING_CONST(b, " hours "); } if (mins) { buffer_append_long(b, mins); BUFFER_APPEND_STRING_CONST(b, " min "); } buffer_append_long(b, seconds); BUFFER_APPEND_STRING_CONST(b, " s"); BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">"); ts = srv->startup_ts; strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts)); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); avg = p->abs_requests; mod_status_get_multiplier(&avg, &multiplier, 1000); buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); avg = p->abs_traffic_out; mod_status_get_multiplier(&avg, &multiplier, 1024); sprintf(buf, "%.2f", avg); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); avg = p->abs_requests / (srv->cur_ts - srv->startup_ts); mod_status_get_multiplier(&avg, &multiplier, 1000); buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts); mod_status_get_multiplier(&avg, &multiplier, 1024); sprintf(buf, "%.2f", avg); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n"); for (j = 0, avg = 0; j < 5; j++) { avg += p->mod_5s_requests[j]; } avg /= 5; BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); mod_status_get_multiplier(&avg, &multiplier, 1000); buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n"); for (j = 0, avg = 0; j < 5; j++) { avg += p->mod_5s_traffic_out[j]; } avg /= 5; BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); mod_status_get_multiplier(&avg, &multiplier, 1024); sprintf(buf, "%.2f", avg); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "</table>\n"); BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n"); BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n"); BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n"); BUFFER_APPEND_STRING_CONST(b, "q = request-start, Q = request-end\n"); BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n"); BUFFER_APPEND_STRING_CONST(b, "<b>"); buffer_append_long(b, srv->conns->used); BUFFER_APPEND_STRING_CONST(b, " connections</b>\n"); for (j = 0; j < srv->conns->used; j++) { connection *c = srv->conns->ptr[j]; const char *state = connection_get_short_state(c->state); buffer_append_string_len(b, state, 1); if (((j + 1) % 50) == 0) { BUFFER_APPEND_STRING_CONST(b, "\n"); } } BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n"); BUFFER_APPEND_STRING_CONST(b, "<table summary=\"status\" class=\"status\">\n"); BUFFER_APPEND_STRING_CONST(b, "<tr>"); mod_status_header_append_sort(b, p_d, "Client IP"); mod_status_header_append_sort(b, p_d, "Read"); mod_status_header_append_sort(b, p_d, "Written"); mod_status_header_append_sort(b, p_d, "State"); mod_status_header_append_sort(b, p_d, "Time"); mod_status_header_append_sort(b, p_d, "Host"); mod_status_header_append_sort(b, p_d, "URI"); mod_status_header_append_sort(b, p_d, "File"); BUFFER_APPEND_STRING_CONST(b, "</tr>\n"); for (j = 0; j < srv->conns->used; j++) { connection *c = srv->conns->ptr[j]; BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">"); buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr))); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); if (con->request.content_length) { buffer_append_long(b, c->request_content_queue->bytes_in); BUFFER_APPEND_STRING_CONST(b, "/"); buffer_append_long(b, c->request.content_length); } else { BUFFER_APPEND_STRING_CONST(b, "0/0"); } BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); buffer_append_off_t(b, chunkqueue_written(c->write_queue)); BUFFER_APPEND_STRING_CONST(b, "/"); buffer_append_off_t(b, chunkqueue_length(c->write_queue)); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); buffer_append_string(b, connection_get_state(c->state)); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); buffer_append_long(b, srv->cur_ts - c->request_start); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); if (buffer_is_empty(c->server_name)) { buffer_append_string_buffer(b, c->uri.authority); } else { buffer_append_string_buffer(b, c->server_name); } BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); if (!buffer_is_empty(c->uri.path)) { buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML); } BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); buffer_append_string_buffer(b, c->physical.path); BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); } BUFFER_APPEND_STRING_CONST(b, "</table>\n"); BUFFER_APPEND_STRING_CONST(b, " </body>\n" "</html>\n" ); response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); return 0; }
static int proxy_create_env(server *srv, handler_ctx *hctx) { size_t i; connection *con = hctx->remote_conn; buffer *b; /* build header */ b = chunkqueue_get_append_buffer(hctx->wb); /* request line */ buffer_copy_string(b, get_http_method_name(con->request.http_method)); buffer_append_string_len(b, CONST_STR_LEN(" ")); buffer_append_string_buffer(b, con->request.uri); buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n")); proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr))); /* http_host is NOT is just a pointer to a buffer * which is NULL if it is not set */ if (con->request.http_host && !buffer_is_empty(con->request.http_host)) { proxy_set_header(con, "X-Host", con->request.http_host->ptr); } proxy_set_header(con, "X-Forwarded-Proto", con->conf.is_ssl ? "https" : "http"); /* request header */ for (i = 0; i < con->request.headers->used; i++) { data_string *ds; ds = (data_string *)con->request.headers->data[i]; if (ds->value->used && ds->key->used) { if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue; if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue; buffer_append_string_buffer(b, ds->key); buffer_append_string_len(b, CONST_STR_LEN(": ")); buffer_append_string_buffer(b, ds->value); buffer_append_string_len(b, CONST_STR_LEN("\r\n")); } } buffer_append_string_len(b, CONST_STR_LEN("\r\n")); hctx->wb->bytes_in += b->used - 1; /* body */ if (con->request.content_length) { chunkqueue *req_cq = con->request_content_queue; chunk *req_c; off_t offset; /* something to send ? */ for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; req_c = req_c->next) { off_t weWant = req_cq->bytes_in - offset; off_t weHave = 0; /* we announce toWrite octects * now take all the request_content chunk that we need to fill this request * */ switch (req_c->type) { case FILE_CHUNK: weHave = req_c->file.length - req_c->offset; if (weHave > weWant) weHave = weWant; chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave); req_c->offset += weHave; req_cq->bytes_out += weHave; hctx->wb->bytes_in += weHave; break; case MEM_CHUNK: /* append to the buffer */ weHave = req_c->mem->used - 1 - req_c->offset; if (weHave > weWant) weHave = weWant; b = chunkqueue_get_append_buffer(hctx->wb); buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave); b->used++; /* add virtual \0 */ req_c->offset += weHave; req_cq->bytes_out += weHave; hctx->wb->bytes_in += weHave; break; default: break; } offset += weHave; } } return 0; }
static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) { char buf[32]; server_socket *srv_sock = con->srv_socket; #ifdef HAVE_IPV6 char b2[INET6_ADDRSTRLEN + 1]; #endif #define CONST_STRING(x) \ x array_reset(p->ssi_cgi_env); ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_DESC); ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"), #ifdef HAVE_IPV6 inet_ntop(srv_sock->addr.plain.sa_family, srv_sock->addr.plain.sa_family == AF_INET6 ? (const void *) &(srv_sock->addr.ipv6.sin6_addr) : (const void *) &(srv_sock->addr.ipv4.sin_addr), b2, sizeof(b2)-1) #else inet_ntoa(srv_sock->addr.ipv4.sin_addr) #endif ); ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1"); LI_ltostr(buf, #ifdef HAVE_IPV6 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port) #else ntohs(srv_sock->addr.ipv4.sin_port) #endif ); ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf); ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"), inet_ntop_cache_get_ip(srv, &(con->dst_addr))); if (con->request.content_length > 0) { /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */ /* request.content_length < SSIZE_MAX, see request.c */ LI_ltostr(buf, con->request.content_length); ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf); } /* * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to * http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html * (6.1.14, 6.1.6, 6.1.7) */ ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_NAME"), con->uri.path->ptr); ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), ""); /* * SCRIPT_FILENAME and DOCUMENT_ROOT for php. The PHP manual * http://www.php.net/manual/en/reserved.variables.php * treatment of PATH_TRANSLATED is different from the one of CGI specs. * TODO: this code should be checked against cgi.fix_pathinfo php * parameter. */ if (con->request.pathinfo->used) { ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr); } ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr); ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr); ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr); ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : ""); ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method)); ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200"); ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version)); ssi_env_add_request_headers(srv, con, p); return 0; }
connection *connection_accept(server *srv, server_socket *srv_socket) { /* accept everything */ /* search an empty place */ int cnt; sock_addr cnt_addr; socklen_t cnt_len; /* accept it and register the fd */ /** * check if we can still open a new connections * * see #1216 */ if (srv->conns->used >= srv->max_conns) { return NULL; } cnt_len = sizeof(cnt_addr); if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) { switch (errno) { case EAGAIN: #if EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif case EINTR: /* we were stopped _before_ we had a connection */ case ECONNABORTED: /* this is a FreeBSD thingy */ /* we were stopped _after_ we had a connection */ break; case EMFILE: /* out of fds */ break; default: log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno); } return NULL; } else { connection *con; srv->cur_fds++; /* ok, we have the connection, register it */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "appected()", cnt); #endif srv->con_opened++; con = connections_get_new_connection(srv); con->fd = cnt; con->fde_ndx = -1; #if 0 gettimeofday(&(con->start_tv), NULL); #endif fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con); connection_set_state(srv, con, CON_STATE_REQUEST_START); con->connection_start = srv->cur_ts; con->dst_addr = cnt_addr; buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr))); con->srv_socket = srv_socket; if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); return NULL; } #ifdef USE_OPENSSL /* connect FD to SSL */ if (srv_socket->is_ssl) { if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); return NULL; } con->renegotiations = 0; SSL_set_app_data(con->ssl, con); SSL_set_accept_state(con->ssl); if (1 != (SSL_set_fd(con->ssl, cnt))) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); return NULL; } } #endif return con; } }
connection *connection_accept(server *srv, server_socket *srv_socket) { /* accept everything */ /* search an empty place */ int cnt; sock_addr cnt_addr; #ifndef HAVE_LIBMTCP socklen_t cnt_len; #endif /* accept it and register the fd */ /** * check if we can still open a new connections * * see #1216 */ if (srv->conns->used >= srv->max_conns) { return NULL; } #ifdef HAVE_LIBMTCP if (-1 == (cnt = mtcp_accept(srv->mctx, srv_socket->fd, NULL, NULL))) { #else cnt_len = sizeof(cnt_addr); if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) { #endif switch (errno) { case EAGAIN: #if EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif case EINTR: /* we were stopped _before_ we had a connection */ case ECONNABORTED: /* this is a FreeBSD thingy */ /* we were stopped _after_ we had a connection */ break; case EMFILE: /* out of fds */ break; default: log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno); } return NULL; } else { connection *con; srv->cur_fds++; /* ok, we have the connection, register it */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "appected()", cnt); #endif srv->con_opened++; con = connections_get_new_connection(srv); con->fd = cnt; con->fde_ndx = -1; #if 0 gettimeofday(&(con->start_tv), NULL); #endif fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con); connection_set_state(srv, con, CON_STATE_REQUEST_START); con->connection_start = srv->cur_ts; con->dst_addr = cnt_addr; buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr))); con->srv_socket = srv_socket; if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); return NULL; } #ifdef USE_OPENSSL /* connect FD to SSL */ if (srv_socket->is_ssl) { if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); return NULL; } con->renegotiations = 0; SSL_set_app_data(con->ssl, con); SSL_set_accept_state(con->ssl); con->conf.is_ssl=1; if (1 != (SSL_set_fd(con->ssl, cnt))) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); return NULL; } } #endif return con; } } int connection_state_machine(server *srv, connection *con) { int done = 0, r; #ifdef USE_OPENSSL server_socket *srv_sock = con->srv_socket; #endif if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state at start", con->fd, connection_get_state(con->state)); } while (done == 0) { size_t ostate = con->state; switch (con->state) { case CON_STATE_REQUEST_START: /* transient */ if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } con->request_start = srv->cur_ts; con->read_idle_ts = srv->cur_ts; con->request_count++; con->loops_per_request = 0; connection_set_state(srv, con, CON_STATE_READ); /* patch con->conf.is_ssl if the connection is a ssl-socket already */ #ifdef USE_OPENSSL con->conf.is_ssl = srv_sock->is_ssl; #endif break; case CON_STATE_REQUEST_END: /* transient */ if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } buffer_reset(con->uri.authority); buffer_reset(con->uri.path); buffer_reset(con->uri.query); buffer_reset(con->request.orig_uri); if (http_request_parse(srv, con)) { /* we have to read some data from the POST request */ connection_set_state(srv, con, CON_STATE_READ_POST); break; } connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); break; case CON_STATE_HANDLE_REQUEST: /* * the request is parsed * * decided what to do with the request * - * * */ if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } switch (r = http_response_prepare(srv, con)) { case HANDLER_FINISHED: if (con->mode == DIRECT) { if (con->http_status == 404 || con->http_status == 403) { /* 404 error-handler */ if (con->in_error_handler == 0 && (!buffer_is_empty(con->conf.error_handler) || !buffer_is_empty(con->error_handler))) { /* call error-handler */ con->error_handler_saved_status = con->http_status; con->http_status = 0; if (buffer_is_empty(con->error_handler)) { buffer_copy_string_buffer(con->request.uri, con->conf.error_handler); } else { buffer_copy_string_buffer(con->request.uri, con->error_handler); } buffer_reset(con->physical.path); con->in_error_handler = 1; connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); done = -1; break; } else if (con->in_error_handler) { /* error-handler is a 404 */ con->http_status = con->error_handler_saved_status; } } else if (con->in_error_handler) { /* error-handler is back and has generated content */ /* if Status: was set, take it otherwise use 200 */ } } if (con->http_status == 0) con->http_status = 200; /* we have something to send, go on */ connection_set_state(srv, con, CON_STATE_RESPONSE_START); break; case HANDLER_WAIT_FOR_FD: srv->want_fds++; fdwaitqueue_append(srv, con); connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); break; case HANDLER_COMEBACK: done = -1; case HANDLER_WAIT_FOR_EVENT: /* come back here */ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); break; case HANDLER_ERROR: /* something went wrong */ connection_set_state(srv, con, CON_STATE_ERROR); break; default: log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r); break; } break; case CON_STATE_RESPONSE_START: /* * the decision is done * - create the HTTP-Response-Header * */ if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } if (-1 == connection_handle_write_prepare(srv, con)) { connection_set_state(srv, con, CON_STATE_ERROR); break; } connection_set_state(srv, con, CON_STATE_WRITE); break; case CON_STATE_RESPONSE_END: /* transient */ /* log the request */ if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } plugins_call_handle_request_done(srv, con); srv->con_written++; if (con->keep_alive) { connection_set_state(srv, con, CON_STATE_REQUEST_START); #if 0 con->request_start = srv->cur_ts; con->read_idle_ts = srv->cur_ts; #endif } else { switch(r = plugins_call_handle_connection_close(srv, con)) { case HANDLER_GO_ON: case HANDLER_FINISHED: break; default: log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r); break; } #ifdef USE_OPENSSL if (srv_sock->is_ssl) { switch (SSL_shutdown(con->ssl)) { case 1: /* done */ break; case 0: /* wait for fd-event * * FIXME: wait for fdevent and call SSL_shutdown again * */ break; default: log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); } } #endif if ((0 == shutdown(con->fd, SHUT_WR))) { con->close_timeout_ts = srv->cur_ts; connection_set_state(srv, con, CON_STATE_CLOSE); } else { connection_close(srv, con); } srv->con_closed++; } connection_reset(srv, con); break; case CON_STATE_CONNECT: if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } chunkqueue_reset(con->read_queue); con->request_count = 0; break; case CON_STATE_CLOSE: if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } /* we have to do the linger_on_close stuff regardless * of con->keep_alive; even non-keepalive sockets may * still have unread data, and closing before reading * it will make the client not see all our output. */ { int len; char buf[1024]; #ifdef HAVE_LIBMTCP len = mtcp_read(srv->mctx, con->fd, buf, sizeof(buf)); #else len = read(con->fd, buf, sizeof(buf)); #endif if (len == 0 || (len < 0 && errno != EAGAIN && errno != EINTR) ) { con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1); } } if (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT) { connection_close(srv, con); if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed for fd", con->fd); } } break; case CON_STATE_READ_POST: case CON_STATE_READ: if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } connection_handle_read_state(srv, con); break; case CON_STATE_WRITE: if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } /* only try to write if we have something in the queue */ if (!chunkqueue_is_empty(con->write_queue)) { #if 0 log_error_write(srv, __FILE__, __LINE__, "dsd", con->fd, "packets to write:", con->write_queue->used); #endif } if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) { if (-1 == connection_handle_write(srv, con)) { log_error_write(srv, __FILE__, __LINE__, "ds", con->fd, "handle write failed."); connection_set_state(srv, con, CON_STATE_ERROR); } } break; case CON_STATE_ERROR: /* transient */ /* even if the connection was drop we still have to write it to the access log */ if (con->http_status) { plugins_call_handle_request_done(srv, con); } #ifdef USE_OPENSSL if (srv_sock->is_ssl) { int ret, ssl_r; unsigned long err; ERR_clear_error(); switch ((ret = SSL_shutdown(con->ssl))) { case 1: /* ok */ break; case 0: ERR_clear_error(); if (-1 != (ret = SSL_shutdown(con->ssl))) break; /* fall through */ default: switch ((ssl_r = SSL_get_error(con->ssl, ret))) { case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: break; case SSL_ERROR_SYSCALL: /* perhaps we have error waiting in our error-queue */ if (0 != (err = ERR_get_error())) { do { log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", ssl_r, ret, ERR_error_string(err, NULL)); } while((err = ERR_get_error())); } else if (errno != 0) { /* ssl bug (see lighttpd ticket #2213): sometimes errno == 0 */ switch(errno) { case EPIPE: case ECONNRESET: break; default: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", ssl_r, ret, errno, strerror(errno)); break; } } break; default: while((err = ERR_get_error())) { log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", ssl_r, ret, ERR_error_string(err, NULL)); } break; } } } ERR_clear_error(); #endif switch(con->mode) { case DIRECT: #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "emergency exit: direct", con->fd); #endif break; default: switch(r = plugins_call_handle_connection_close(srv, con)) { case HANDLER_GO_ON: case HANDLER_FINISHED: break; default: log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r); break; } break; } connection_reset(srv, con); /* close the connection */ if ((0 == shutdown(con->fd, SHUT_WR))) { con->close_timeout_ts = srv->cur_ts; connection_set_state(srv, con, CON_STATE_CLOSE); if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sd", "shutdown for fd", con->fd); } } else { connection_close(srv, con); } con->keep_alive = 0; srv->con_closed++; break; default: log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown state:", con->fd, con->state); break; } if (done == -1) { done = 0; } else if (ostate == con->state) { done = 1; } } if (srv->srvconf.log_state_handling) { log_error_write(srv, __FILE__, __LINE__, "sds", "state at exit:", con->fd, connection_get_state(con->state)); } switch(con->state) { case CON_STATE_READ_POST: case CON_STATE_READ: case CON_STATE_CLOSE: fdevent_event_set(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN); break; case CON_STATE_WRITE: /* request write-fdevent only if we really need it * - if we have data to write * - if the socket is not writable yet */ if (!chunkqueue_is_empty(con->write_queue) && (con->is_writable == 0) && (con->traffic_limit_reached == 0)) { fdevent_event_set(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT); } else { fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd); } break; default: fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd); break; } return 0; }