static ret_t add_environment (cherokee_handler_cgi_t *cgi, cherokee_connection_t *conn) { ret_t ret; cherokee_handler_cgi_base_t *cgi_base = HDL_CGI_BASE(cgi); cherokee_buffer_t *tmp = THREAD_TMP_BUF2(CONN_THREAD(conn)); ret = cherokee_handler_cgi_base_build_envp (HDL_CGI_BASE(cgi), conn); if (unlikely (ret != ret_ok)) return ret; /* CONTENT_LENGTH */ if (http_method_with_input (conn->header.method)) { cherokee_buffer_clean (tmp); cherokee_buffer_add_ullong10 (tmp, conn->post.len); set_env (cgi_base, "CONTENT_LENGTH", tmp->buf, tmp->len); } /* SCRIPT_FILENAME */ if (cgi_base->executable.len <= 0) return ret_error; set_env (cgi_base, "SCRIPT_FILENAME", cgi_base->executable.buf, cgi_base->executable.len); return ret_ok; }
ret_t cherokee_handler_ssi_add_headers (cherokee_handler_ssi_t *hdl, cherokee_buffer_t *buffer) { ret_t ret; char *ext; cherokee_buffer_t *mime = NULL; cherokee_server_t *srv = HANDLER_SRV(hdl); cherokee_connection_t *conn = HANDLER_CONN(hdl); /* MIME type */ if (srv->mime != NULL) { ext = strrchr (conn->request.buf, '.'); if (ext == NULL) return ret_ok; ret = cherokee_mime_get_by_suffix (srv->mime, ext+1, &hdl->mime); if (ret == ret_ok) { cherokee_mime_entry_get_type (hdl->mime, &mime); cherokee_buffer_add_str (buffer, "Content-Type: "); cherokee_buffer_add_buffer (buffer, mime); cherokee_buffer_add_str (buffer, CRLF); } } /* Length */ if (cherokee_connection_should_include_length(conn)) { HANDLER(hdl)->support = hsupport_length; cherokee_buffer_add_str (buffer, "Content-Length: "); cherokee_buffer_add_ullong10(buffer, (cullong_t) hdl->render.len); cherokee_buffer_add_str (buffer, CRLF); } return ret_ok; }
static ret_t parse (cherokee_handler_ssi_t *hdl, cherokee_buffer_t *in, cherokee_buffer_t *out) { ret_t ret; char *p, *q; char *begin; int re; cuint_t len; operations_t op; path_type_t path; struct stat info; cherokee_boolean_t ignore; cherokee_buffer_t key = CHEROKEE_BUF_INIT; cherokee_buffer_t val = CHEROKEE_BUF_INIT; cherokee_buffer_t pair = CHEROKEE_BUF_INIT; cherokee_buffer_t fpath = CHEROKEE_BUF_INIT; q = in->buf; while (true) { begin = q; /* Check the end */ if (q >= in->buf + in->len) break; /* Find next SSI tag */ p = strstr (q, "<!--#"); if (p == NULL) { cherokee_buffer_add (out, begin, (in->buf + in->len) - begin); ret = ret_ok; goto out; } q = strstr (p + 5, "-->"); if (q == NULL) { ret = ret_error; goto out; } len = q - p; len -= 5; cherokee_buffer_clean (&key); cherokee_buffer_add (&key, p+5, len); cherokee_buffer_trim (&key); q += 3; TRACE(ENTRIES, "Found key '%s'\n", key.buf); /* Add the previous chunk */ cherokee_buffer_add (out, begin, p - begin); /* Check element */ op = op_none; ignore = false; if (strncmp (key.buf, "include", 7) == 0) { op = op_include; len = 7; } else if (strncmp (key.buf, "fsize", 5) == 0) { op = op_size; len = 5; } else if (strncmp (key.buf, "flastmod", 8) == 0) { op = op_lastmod; len = 8; } else { LOG_ERROR (CHEROKEE_ERROR_HANDLER_SSI_PROPERTY, key.buf); } /* Deeper parsing */ path = path_none; switch (op) { case op_size: case op_include: case op_lastmod: /* Read a property key */ cherokee_buffer_move_to_begin (&key, len); cherokee_buffer_trim (&key); cherokee_buffer_clean (&pair); get_pair (&key, &pair); cherokee_buffer_drop_ending (&key, pair.len); cherokee_buffer_trim (&key); /* Parse the property */ if (strncmp (pair.buf, "file=", 5) == 0) { path = path_file; len = 5; } else if (strncmp (pair.buf, "virtual=", 8) == 0) { path = path_virtual; len = 8; } cherokee_buffer_clean (&val); get_val (pair.buf + len, &val); cherokee_buffer_clean (&fpath); switch (path) { case path_file: cherokee_buffer_add_buffer (&fpath, &hdl->dir); cherokee_buffer_add_char (&fpath, '/'); cherokee_buffer_add_buffer (&fpath, &val); TRACE(ENTRIES, "Path: file '%s'\n", fpath.buf); break; case path_virtual: cherokee_buffer_add_buffer (&fpath, &HANDLER_VSRV(hdl)->root); cherokee_buffer_add_char (&fpath, '/'); cherokee_buffer_add_buffer (&fpath, &val); TRACE(ENTRIES, "Path: virtual '%s'\n", fpath.buf); break; default: ignore = true; SHOULDNT_HAPPEN; } /* Path security check: ensure that the file * to include is inside the document root. */ if (! cherokee_buffer_is_empty (&fpath)) { cherokee_path_short (&fpath); if (fpath.len < HANDLER_VSRV(hdl)->root.len) { ignore = true; } else { re = strncmp (fpath.buf, HANDLER_VSRV(hdl)->root.buf, HANDLER_VSRV(hdl)->root.len); if (re != 0) { ignore = true; } } } /* Perform the operation */ if (! ignore) { switch (op) { case op_include: { cherokee_buffer_t file_content = CHEROKEE_BUF_INIT; ret = cherokee_buffer_read_file (&file_content, fpath.buf); if (unlikely (ret != ret_ok)) { cherokee_buffer_mrproper (&file_content); ret = ret_error; goto out; } TRACE(ENTRIES, "Including file '%s'\n", fpath.buf); ret = parse (hdl, &file_content, out); if (unlikely (ret != ret_ok)) { cherokee_buffer_mrproper (&file_content); ret = ret_error; goto out; } cherokee_buffer_mrproper (&file_content); break; } case op_size: TRACE(ENTRIES, "Including file size '%s'\n", fpath.buf); re = cherokee_stat (fpath.buf, &info); if (re >=0) { cherokee_buffer_add_ullong10 (out, info.st_size); } break; case op_lastmod: TRACE(ENTRIES, "Including file modification date '%s'\n", fpath.buf); re = cherokee_stat (fpath.buf, &info); if (re >= 0) { struct tm *ltime; struct tm ltime_buf; char tmp[50]; ltime = cherokee_localtime (&info.st_mtime, <ime_buf); if (ltime != NULL) { strftime (tmp, sizeof(tmp), "%d-%b-%Y %H:%M", ltime); cherokee_buffer_add (out, tmp, strlen(tmp)); } } break; default: SHOULDNT_HAPPEN; } } /* !ignore */ break; default: SHOULDNT_HAPPEN; } /* switch(op) */ } /* while */ ret = ret_ok; out: cherokee_buffer_mrproper (&key); cherokee_buffer_mrproper (&val); cherokee_buffer_mrproper (&pair); cherokee_buffer_mrproper (&fpath); return ret; }
ret_t cherokee_request_header_build_string (cherokee_request_header_t *request, cherokee_buffer_t *buf, cherokee_buffer_t *tmp1, cherokee_buffer_t *tmp2) { ret_t ret; const char *ptr; cuint_t len; cherokee_url_t *url = REQUEST_URL(request); /* 200 bytes should be enough for a small header */ cherokee_buffer_ensure_size (buf, 200); /* Add main request line: * GET /dir/object HTTP/1.1 */ ret = cherokee_http_method_to_string (request->method, &ptr, &len); if (ret != ret_ok) return ret; ret = cherokee_buffer_add (buf, ptr, len); if (ret != ret_ok) return ret; cherokee_buffer_add_str (buf, " "); /* Check if the requests goes through a proxy */ if (request->proxy) { cherokee_buffer_add_str (buf, "http://"); cherokee_buffer_add_buffer (buf, URL_HOST(url)); } cherokee_buffer_add_buffer (buf, URL_REQUEST(url)); switch (REQUEST_VERSION(request)) { case http_version_11: cherokee_buffer_add_str (buf, " HTTP/1.1" CRLF); break; case http_version_10: cherokee_buffer_add_str (buf, " HTTP/1.0" CRLF); break; default: SHOULDNT_HAPPEN; return ret_error; } /* Add "Host:" header - in HTTP/1.1 */ if (REQUEST_VERSION(request) == http_version_11) { cherokee_buffer_add_str (buf, "Host: "); cherokee_buffer_add_buffer (buf, URL_HOST(url)); cherokee_buffer_add_str (buf, CRLF); } /* Post information */ if (request->post_len != 0) { /* "Content-Length: " FMT_OFFSET CRLF, request->post_len; */ cherokee_buffer_add_str (buf, "Content-Length: "); cherokee_buffer_add_ullong10 (buf, (cullong_t) request->post_len); cherokee_buffer_add_str (buf, CRLF); } /* Add "Connection:" header */ if (REQUEST_KEEPALIVE(request)) { cherokee_buffer_add_str (buf, "Connection: Keep-Alive"CRLF); } else { cherokee_buffer_add_str (buf, "Connection: close"CRLF); } /* Authentication */ if (! cherokee_buffer_is_empty (&request->user) || ! cherokee_buffer_is_empty (&request->password)) { cherokee_buffer_clean (tmp1); cherokee_buffer_clean (tmp2); cherokee_buffer_add_buffer (tmp1, &request->user); cherokee_buffer_add_char (tmp1, ':'); cherokee_buffer_add_buffer (tmp1, &request->password); cherokee_buffer_encode_base64 (tmp1, tmp2); cherokee_buffer_add_str (buf, "Authorization: Basic "); cherokee_buffer_add_buffer (buf, tmp2); cherokee_buffer_add_str (buf, CRLF); } /* Extra headers */ if (! cherokee_buffer_is_empty (&request->extra_headers)) { cherokee_buffer_add_buffer (buf, &request->extra_headers); } /* Finish the header */ cherokee_buffer_add_str (buf, CRLF); return ret_ok; }
ret_t cherokee_handler_error_add_headers (cherokee_handler_error_t *hdl, cherokee_buffer_t *buffer) { cherokee_connection_t *conn = HANDLER_CONN(hdl); /* It has special headers on protocol upgrading */ switch (conn->upgrade) { case http_upgrade_nothing: break; case http_upgrade_tls10: cherokee_buffer_add_str (buffer, "Upgrade: TLS/1.0, HTTP/1.1"CRLF); break; case http_upgrade_http11: cherokee_buffer_add_str (buffer, "Upgrade: HTTP/1.1"CRLF); break; default: SHOULDNT_HAPPEN; } /* 1xx, 204 and 304 (Not Modified) responses have to be managed * by "content" handlers, anyway this test ensures that * it'll never send wrong and unrelated headers in case that * a 1xx, 204 or 304 response is managed by this handler. * 304 responses should only include the * Last-Modified, ETag, Expires and Cache-Control headers. */ if (!http_code_with_body (conn->error_code)) { return ret_ok; } if (cherokee_connection_should_include_length(conn)) { HANDLER(hdl)->support |= hsupport_length; if (conn->error_code == http_range_not_satisfiable) { /* The handler that attended the request has put the content * length in conn->range_end in order to allow it to send the * right length to the client. * * "Content-Range: bytes *" "/" FMT_OFFSET CRLF */ cherokee_buffer_add_str (buffer, "Content-Range: bytes */"); cherokee_buffer_add_ullong10(buffer, (cullong_t)conn->range_end); cherokee_buffer_add_str (buffer, CRLF); } cherokee_buffer_add_str (buffer, "Content-Length: "); cherokee_buffer_add_ulong10 (buffer, (culong_t) hdl->content.len); cherokee_buffer_add_str (buffer, CRLF); } /* Usual headers */ cherokee_buffer_add_str (buffer, "Content-Type: text/html"CRLF); if (http_type_400(conn->error_code) || http_type_500(conn->error_code)) { cherokee_buffer_add_str (buffer, "Cache-Control: no-cache"CRLF); cherokee_buffer_add_str (buffer, "Pragma: no-cache"CRLF); } return ret_ok; }
static ret_t build_log_string (cherokee_logger_ncsa_t *logger, cherokee_connection_t *cnt, cherokee_buffer_t *buf) { ret_t ret; const char *method; const char *username; const char *version; cuint_t method_len = 0; size_t username_len = 0; cuint_t version_len = 0; cherokee_buffer_t *referer = &logger->referer; cherokee_buffer_t *useragent = &logger->useragent; char ipaddr[CHE_INET_ADDRSTRLEN]; /* Look for the user */ if (cnt->validator && !cherokee_buffer_is_empty (&cnt->validator->user)) { username_len = cnt->validator->user.len; username = cnt->validator->user.buf; } else { username_len = 1; username = "******"; } /* Get the method and version strings */ ret = cherokee_http_method_to_string (cnt->header.method, &method, &method_len); if (unlikely (ret < ret_ok)) { method = ""; method_len = 0; } ret = cherokee_http_version_to_string (cnt->header.version, &version, &version_len); if (unlikely (ret < ret_ok)) { version = ""; version_len = 0; } /* Build the log string * * "%s - %s [%02d/%s/%d:%02d:%02d:%02d %c%02d%02d] \"%s %s %s\" %d " * FMT_OFFSET */ if (cherokee_buffer_is_empty (&cnt->logger_real_ip)) { memset (ipaddr, 0, sizeof(ipaddr)); cherokee_socket_ntop (&cnt->socket, ipaddr, sizeof(ipaddr)-1); cherokee_buffer_add (buf, ipaddr, strlen(ipaddr)); } else { cherokee_buffer_add_buffer (buf, &cnt->logger_real_ip); } cherokee_buffer_add_str (buf, " - "); cherokee_buffer_add (buf, username, username_len); /* " [date time] " */ cherokee_buffer_add_buffer (buf, &now); cherokee_buffer_add (buf, method, method_len); cherokee_buffer_add_char (buf, ' '); if (! cherokee_buffer_is_empty (&cnt->request_original)) { cherokee_buffer_add_buffer (buf, &cnt->request_original); if (! cherokee_buffer_is_empty (&cnt->query_string_original)) { cherokee_buffer_add_char (buf, '?'); cherokee_buffer_add_buffer (buf, &cnt->query_string_original); } } else { cherokee_buffer_add_buffer (buf, &cnt->request); if (! cherokee_buffer_is_empty (&cnt->query_string)) { cherokee_buffer_add_char (buf, '?'); cherokee_buffer_add_buffer (buf, &cnt->query_string); } } cherokee_buffer_add_char (buf, ' '); cherokee_buffer_add (buf, version, version_len); cherokee_buffer_add_str (buf, "\" "); if (unlikely (cnt->error_internal_code != http_unset)) { cherokee_buffer_add_long10 (buf, cnt->error_internal_code); } else { cherokee_buffer_add_long10 (buf, cnt->error_code); } cherokee_buffer_add_char (buf, ' '); cherokee_buffer_add_ullong10 (buf, cnt->tx); /* Look for the "combined" information */ if (!logger->combined) { cherokee_buffer_add_char (buf, '\n'); return ret_ok; } /* "combined" information */ cherokee_buffer_clean (referer); cherokee_buffer_clean (useragent); cherokee_header_copy_known (&cnt->header, header_referer, referer); cherokee_header_copy_known (&cnt->header, header_user_agent, useragent); cherokee_buffer_ensure_addlen (buf, 8 + referer->len + referer->len); if (referer->len > 0) { cherokee_buffer_add_str (buf, " \""); cherokee_buffer_add_buffer (buf, referer); cherokee_buffer_add_str (buf, "\" \""); } else { cherokee_buffer_add_str (buf, " \"-\" \""); } if (useragent->len > 0) { cherokee_buffer_add_buffer (buf, useragent); } cherokee_buffer_add_str (buf, "\"\n"); return ret_ok; }