ret_t cherokee_buffer_add_buffer (cherokee_buffer_t *buf, cherokee_buffer_t *buf2) { return cherokee_buffer_add (buf, buf2->buf, buf2->len); }
ret_t cherokee_handler_proxy_conn_recv_headers (cherokee_handler_proxy_conn_t *pconn, cherokee_buffer_t *body, cherokee_boolean_t flexible) { ret_t ret; char *end; cuint_t sep_len; size_t size = 0; /* Read */ ret = cherokee_socket_bufread (&pconn->socket, &pconn->header_in_raw, DEFAULT_RECV_SIZE, &size); switch (ret) { case ret_ok: break; case ret_eof: case ret_error: return ret; case ret_eagain: if (cherokee_buffer_is_empty (&pconn->header_in_raw)) { return ret_eagain; } break; default: RET_UNKNOWN(ret); } /* Look for the end of header */ ret = cherokee_find_header_end (&pconn->header_in_raw, &end, &sep_len); switch (ret) { case ret_ok: break; case ret_not_found: return ret_eagain; default: /* Did not success */ if (! flexible) { goto error; } /* Plan B! */ TRACE (ENTRIES, "Header end not found. Being more flexible about malformed headers\n"); ret = find_header_end_flexible (&pconn->header_in_raw, &end, &sep_len); switch (ret) { case ret_ok: break; case ret_not_found: return ret_eagain; default: goto error; } } /* Copy the body if there is any */ size = (pconn->header_in_raw.buf + pconn->header_in_raw.len) - (end + sep_len); cherokee_buffer_add (body, end+sep_len, size); cherokee_buffer_drop_ending (&pconn->header_in_raw, size); return ret_ok; error: LOG_ERROR (CHEROKEE_ERROR_PROXY_HEADER_PARSE, pconn->header_in_raw.len, pconn->header_in_raw.buf); return ret_error; }
static ret_t cherokee_url_parse_guts (cherokee_url_t *url, cherokee_buffer_t *url_buf, cherokee_buffer_t *user_ret, cherokee_buffer_t *password_ret) { ret_t ret; cuint_t len = 0 ; char *port; char *slash; char *server; char *arroba; char *tmp; /* Drop protocol, if exists.. */ ret = parse_protocol (url, url_buf->buf, &len); if (unlikely(ret < ret_ok)) return ret_error; tmp = url_buf->buf + len; /* User (and password) */ arroba = strchr (tmp, '@'); if (arroba != NULL) { char *sep; sep = strchr (tmp, ':'); if (sep == NULL) { cherokee_buffer_clean (user_ret); cherokee_buffer_add (user_ret, tmp, arroba - tmp); } else { cherokee_buffer_clean (user_ret); cherokee_buffer_add (user_ret, tmp, sep - tmp); sep++; cherokee_buffer_clean (password_ret); cherokee_buffer_add (password_ret, sep, arroba - sep); } tmp = arroba + 1; } /* Split the host/request */ server = tmp; len = strlen (server); slash = strpbrk (server, "/\\"); if (slash == NULL) { cherokee_buffer_add (&url->request, "/", 1); cherokee_buffer_add (&url->host, server, len); } else { cherokee_buffer_add (&url->request, slash, len-(slash-server)); cherokee_buffer_add (&url->host, server, slash-server); } /* Drop up the port, if exists.. */ port = strchr (url->host.buf, ':'); if (port != NULL) { /* Read port number */ if (slash != NULL) *slash = '\0'; URL_PORT(url) = atoi (port+1); if (slash != NULL) *slash = '/'; /* .. and remove it */ ret = cherokee_buffer_drop_ending (&url->host, strlen(port)); if (unlikely(ret < ret_ok)) return ret; } #if 0 cherokee_url_print (url); #endif return ret_ok; }
static ret_t fork_and_execute_cgi_win32 (cherokee_handler_cgi_t *cgi) { int re; PROCESS_INFORMATION pi; STARTUPINFO si; char *cmd; cherokee_buffer_t cmd_line = CHEROKEE_BUF_INIT; cherokee_buffer_t exec_dir = CHEROKEE_BUF_INIT; cherokee_connection_t *conn = HANDLER_CONN(cgi); SECURITY_ATTRIBUTES saSecAtr; HANDLE hProc; HANDLE hChildStdinRd = INVALID_HANDLE_VALUE; HANDLE hChildStdinWr = INVALID_HANDLE_VALUE; HANDLE hChildStdoutRd = INVALID_HANDLE_VALUE; HANDLE hChildStdoutWr = INVALID_HANDLE_VALUE; /* Create the environment for the process */ add_environment (cgi, conn); cherokee_buffer_add (&cgi->envp, "\0", 1); /* Command line */ cmd = HDL_CGI_BASE(cgi)->executable.buf; cherokee_buffer_add (&cmd_line, cmd, strlen(cmd)); // cherokee_buffer_add_va (&cmd_line, " \"%s\"", HDL_CGI_BASE(cgi)->param.buf); /* Execution directory */ if (! cherokee_buffer_is_empty (&conn->effective_directory)) { cherokee_buffer_add_buffer (&exec_dir, &conn->effective_directory); } else { char *file = strrchr (cmd, '/'); char *end = HDL_CGI_BASE(cgi)->executable.buf + HDL_CGI_BASE(cgi)->executable.len; cherokee_buffer_add (&exec_dir, cmd, HDL_CGI_BASE(cgi)->executable.len - (end - file)); } /* Set the bInheritHandle flag so pipe handles are inherited. */ memset(&saSecAtr, 0, sizeof(SECURITY_ATTRIBUTES)); saSecAtr.nLength = sizeof(SECURITY_ATTRIBUTES); saSecAtr.lpSecurityDescriptor = NULL; saSecAtr.bInheritHandle = TRUE; /* Create the pipes */ hProc = GetCurrentProcess(); re = CreatePipe (&hChildStdoutRd, &hChildStdoutWr, &saSecAtr, 0); if (!re) return ret_error; re = CreatePipe (&hChildStdinRd, &hChildStdinWr, &saSecAtr, 0); if (!re) return ret_error; /* Make them inheritable */ re = DuplicateHandle (hProc, hChildStdoutRd, hProc, &hChildStdoutRd, 0, TRUE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); if (!re) return ret_error; re = DuplicateHandle (hProc, hChildStdinWr, hProc, &hChildStdinWr, 0, TRUE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); if (!re) return ret_error; /* Starting information */ ZeroMemory (&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.hStdOutput = hChildStdoutWr; si.hStdError = hChildStdoutWr; si.hStdInput = hChildStdinRd; si.dwFlags |= STARTF_USESTDHANDLES; TRACE (ENTRIES, "exec %s dir %s\n", cmd_line.buf, exec_dir.buf); /* Launch the child process */ re = CreateProcess (cmd, /* ApplicationName */ cmd_line.buf, /* Command line */ NULL, /* Process handle not inheritable */ NULL, /* Thread handle not inheritable */ TRUE, /* Handle inheritance */ 0, /* Creation flags */ cgi->envp.buf, /* Use parent's environment block */ exec_dir.buf, /* Use parent's starting directory */ &si, /* Pointer to STARTUPINFO structure */ &pi); /* Pointer to PROCESS_INFORMATION structure */ CloseHandle (hChildStdinRd); CloseHandle (hChildStdoutWr); if (!re) { LOG_ERROR (CHEROKEE_ERROR_HANDLER_CGI_CREATEPROCESS, GetLastError()); CloseHandle (pi.hProcess); CloseHandle (pi.hThread); conn->error_code = http_internal_error; return ret_error; } cherokee_buffer_mrproper (&cmd_line); cherokee_buffer_mrproper (&exec_dir); cgi->thread = pi.hThread; cgi->process = pi.hProcess; /* Wait for the CGI process to be ready */ WaitForInputIdle (pi.hProcess, INFINITE); /* Extract the file descriptors */ cgi->pipeInput = _open_osfhandle((LONG)hChildStdoutRd, O_BINARY|_O_RDONLY); if (! conn->post.len <= 0) { CloseHandle (hChildStdinWr); } else { cgi->pipeOutput = _open_osfhandle((LONG)hChildStdinWr, O_BINARY|_O_WRONLY); } TRACE (ENTRIES, "In fd %d, Out fd %d\n", cgi->pipeInput, cgi->pipeOutput); return ret_ok; }
ret_t cherokee_handler_tmi_read_post (cherokee_handler_tmi_t *hdl) { zmq_msg_t message; int re; ret_t ret; ret_t ret_final; cherokee_buffer_t *post = &HANDLER_THREAD(hdl)->tmp_buf1; cherokee_buffer_t *encoded = &HANDLER_THREAD(hdl)->tmp_buf2; cherokee_connection_t *conn = HANDLER_CONN(hdl); /* Check for the post info */ if (! conn->post.has_info) { conn->error_code = http_bad_request; return ret_error; } cherokee_buffer_clean (post); ret = cherokee_post_read (&conn->post, &conn->socket, post); switch (ret) { case ret_ok: cherokee_connection_update_timeout (conn); break; case ret_eagain: ret = cherokee_thread_deactive_to_polling (HANDLER_THREAD(hdl), HANDLER_CONN(hdl), conn->socket.socket, FDPOLL_MODE_READ, false); if (ret != ret_ok) { return ret_error; } else { return ret_eagain; } default: conn->error_code = http_bad_request; return ret_error; } TRACE (ENTRIES, "Post contains: '%s'\n", post->buf); re = cherokee_post_read_finished (&conn->post); ret_final = re ? ret_ok : ret_eagain; cherokee_buffer_clean(encoded); if (hdl->encoder != NULL) { if (ret == ret_ok) { cherokee_encoder_flush(hdl->encoder, post, encoded); } else { cherokee_encoder_encode(hdl->encoder, post, encoded); } } else { encoded = post; } cherokee_buffer_add_buffer(&hdl->output, post); if (ret_final == ret_ok) { cherokee_buffer_t *tmp = &HANDLER_THREAD(hdl)->tmp_buf1; cherokee_handler_tmi_props_t *props = HANDLER_TMI_PROPS(hdl); zmq_msg_t envelope; zmq_msg_t message; cuint_t len; if ((cherokee_buffer_is_empty (&conn->web_directory)) || (cherokee_buffer_is_ending (&conn->web_directory, '/'))) { len = conn->web_directory.len; } else { len = conn->web_directory.len + 1; } cherokee_buffer_clean (tmp); cherokee_buffer_add (tmp, conn->request.buf + len, conn->request.len - len); TRACE(ENTRIES, "ZeroMQ: incomming path '%s'\n", tmp->buf); zmq_msg_init_size (&envelope, tmp->len); memcpy (zmq_msg_data (&envelope), tmp->buf, tmp->len); zmq_msg_init_size (&message, hdl->output.len); memcpy (zmq_msg_data (&message), hdl->output.buf, hdl->output.len); /* Atomic Section */ CHEROKEE_MUTEX_LOCK (&props->mutex); zmq_msg_send (&envelope, props->socket, ZMQ_DONTWAIT | ZMQ_SNDMORE); zmq_msg_send (&message, props->socket, ZMQ_DONTWAIT); CHEROKEE_MUTEX_UNLOCK (&props->mutex); zmq_msg_close (&envelope); zmq_msg_close (&message); #ifdef LIBXML_PUSH_ENABLED if (hdl->validate_xml) { if (hdl->inflated) { hdl->strm.avail_in = hdl->output.len; hdl->strm.next_in = hdl->output.buf; /* run inflate() on input until output buffer not full */ do { #define CHUNK 131072 int have; char out[CHUNK]; hdl->strm.avail_out = CHUNK; hdl->strm.next_out = out; hdl->z_ret = inflate(&(hdl->strm), Z_NO_FLUSH); switch (hdl->z_ret) { case Z_NEED_DICT: hdl->z_ret = Z_DATA_ERROR; /* and fall through */ case Z_DATA_ERROR: case Z_MEM_ERROR: case Z_STREAM_ERROR: hdl->z_ret = Z_STREAM_ERROR; return ret_ok; } have = CHUNK - hdl->strm.avail_out; xmlParseChunk(hdl->ctxt, out, have, 0); } while (hdl->strm.avail_out == 0); } else { xmlParseChunk(hdl->ctxt, hdl->output.buf, hdl->output.len, 0); } } #endif } return ret_final; }
ret_t cherokee_handler_admin_read_post (cherokee_handler_admin_t *hdl) { int re; ret_t ret; char *tmp; cherokee_buffer_t post = CHEROKEE_BUF_INIT; cherokee_buffer_t line = CHEROKEE_BUF_INIT; cherokee_connection_t *conn = HANDLER_CONN(hdl); /* Check for the post info */ if (! conn->post.has_info) { conn->error_code = http_bad_request; return ret_error; } /* Process line per line */ ret = cherokee_post_read (&conn->post, &conn->socket, &post); switch (ret) { case ret_ok: case ret_eagain: break; default: conn->error_code = http_bad_request; return ret_error; } /* Parse */ TRACE (ENTRIES, "Post contains: '%s'\n", post.buf); cherokee_dwriter_list_open (&hdl->dwriter); for (tmp = post.buf;;) { char *end1 = strchr (tmp, CHR_LF); char *end2 = strchr (tmp, CHR_CR); char *end = cherokee_min_str (end1, end2); if (end == NULL) break; if (end - tmp < 2) break; /* Copy current line and go to the next one */ cherokee_buffer_add (&line, tmp, end - tmp); while ((*end == CHR_CR) || (*end == CHR_LF)) end++; tmp = end; /* Process current line */ ret = process_request_line (hdl, &line); if (ret == ret_error) { conn->error_code = http_bad_request; ret = ret_error; goto exit2; } /* Clean up for the next iteration */ cherokee_buffer_clean (&line); } cherokee_dwriter_list_close (&hdl->dwriter); /* There might be more POST to read */ re = cherokee_post_read_finished (&conn->post); ret = re ? ret_ok : ret_eagain; exit2: cherokee_buffer_mrproper (&post); cherokee_buffer_mrproper (&line); return ret; }
void cherokee_trace_do_trace (const char *entry, const char *file, int line, const char *func, const char *fmt, ...) { ret_t ret; char *p; char *lentry; char *lentry_end; va_list args; cherokee_connection_t *conn; cherokee_buffer_t *trace_modules = &trace.modules; cherokee_boolean_t do_log = false; cherokee_buffer_t entries = CHEROKEE_BUF_INIT; /* Prevents loops */ if (disabled) { return; } disabled = true; /* Return ASAP if nothing is being traced */ if (cherokee_buffer_is_empty (&trace.modules)) { goto out; } /* Check the connection source, if possible */ if (trace.from_filter != NULL) { conn = CONN (CHEROKEE_THREAD_PROP_GET (thread_connection_ptr)); /* No conn, no trace entry */ if (conn == NULL) { goto out; } if (conn->socket.socket < 0) { goto out; } /* Skip the trace if the conn doesn't match */ ret = cherokee_access_ip_match (trace.from_filter, &conn->socket); if (ret != ret_ok) { goto out; } } /* Also, check for 'all' */ p = strstr (trace_modules->buf, "all"); if (p == NULL) { /* Parse the In-code module string */ cherokee_buffer_add (&entries, entry, strlen(entry)); for (lentry = entries.buf;;) { lentry_end = strchr (lentry, ','); if (lentry_end) *lentry_end = '\0'; /* Check the type */ p = strstr (trace_modules->buf, lentry); if (p) { char *tmp = p + strlen(lentry); if ((*tmp == '\0') || (*tmp == ',') || (*tmp == ' ')) do_log = true; } if ((lentry_end == NULL) || (do_log)) break; lentry = lentry_end + 1; } /* Return if trace entry didn't match with the configured list */ if (! do_log) { goto out; } } /* Format the message and log it: * 'entries' is not needed at this stage, reuse it */ cherokee_buffer_clean (&entries); if (trace.print_thread) { int len; char tmp[32+1]; static int longest_len = 0; len = snprintf (tmp, 32+1, "%llX", (unsigned long long) CHEROKEE_THREAD_SELF); longest_len = MAX (longest_len, len); cherokee_buffer_add_str (&entries, "{0x"); cherokee_buffer_add_char_n (&entries, '0', longest_len - len); cherokee_buffer_add (&entries, tmp, len); cherokee_buffer_add_str (&entries, "} "); } if (trace.print_time) { cherokee_buffer_add_char (&entries, '['); cherokee_buf_add_bogonow (&entries, true); cherokee_buffer_add_str (&entries, "] "); } cherokee_buffer_add_va (&entries, "%18s:%04d (%30s): ", file, line, func); va_start (args, fmt); cherokee_buffer_add_va_list (&entries, (char *)fmt, args); va_end (args); if (trace.use_syslog) { cherokee_syslog (LOG_DEBUG, &entries); } else { #ifdef HAVE_FLOCKFILE flockfile (stdout); #endif fprintf (stdout, "%s", entries.buf); #ifdef HAVE_FUNLOCKFILE funlockfile (stdout); #endif } out: cherokee_buffer_mrproper (&entries); disabled = false; }
static ret_t process_chunk (cherokee_post_t *post, cherokee_buffer_t *in, cherokee_buffer_t *out) { char *p; char *begin; char *end; ssize_t content_size; TRACE (ENTRIES, "Post in-buffer len=%d\n", in->len); p = in->buf; begin = in->buf; while (true) { end = in->buf + in->len; /* Iterate through the number */ while ((p < end) && (((*p >= '0') && (*p <= '9')) || ((*p >= 'a') && (*p <= 'f')) || ((*p >= 'A') && (*p <= 'F')))) p++; if (unlikely (p+2 > end)) { return ret_ok; } /* Check the CRLF after the length */ if (p[0] != CHR_CR) { return ret_error; } if (p[1] != CHR_LF) { return ret_error; } p += 2; /* Read the length */ content_size = (size_t) strtoul (begin, NULL, 16); if (unlikely (content_size < 0)) { return ret_error; } /* Check if there's enough info */ if (content_size == 0) { post->chunked.last = true; } else if (p + content_size + 2 > end) { TRACE (ENTRIES, "Unfinished chunk(len="FMT_OFFSET"), has=%d, out->len="FMT_OFFSET"\n", content_size, (int)(end-p), out->len); break; } /* Last block check */ if (post->chunked.last) { TRACE(ENTRIES, "Last chunk: %s\n", "exiting"); if (post->chunked.retransmit) { cherokee_buffer_add_str (out, "0" CRLF); } begin = p; break; } /* Move the information */ if (post->chunked.retransmit) { cherokee_buffer_add (out, begin, (p + content_size + 2) - begin); } else { cherokee_buffer_add (out, p, content_size); } TRACE (ENTRIES, "Processing chunk len=%d\n", content_size); /* Next iteration */ begin = p + content_size + 2; p = begin; } /* Clean up in-buffer */ if (begin != in->buf) { cherokee_buffer_move_to_begin (in, begin - in->buf); } /* Very unlikely, but still possible */ if (! cherokee_buffer_is_empty(in)) { TRACE (ENTRIES, "There are %d left-over bytes in the post buffer -> incoming header", in->len); /* cherokee_buffer_add_buffer (&conn->incoming_header, in); */ /* cherokee_buffer_clean (in); */ } TRACE (ENTRIES, "Un-chunked buffer len=%d\n", out->len); return ret_ok; }
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_validator_plain_check (cherokee_validator_plain_t *plain, cherokee_connection_t *conn) { int re; ret_t ret; const char *p; const char *end; cherokee_buffer_t *fpass; cherokee_buffer_t file = CHEROKEE_BUF_INIT; cherokee_buffer_t buser = CHEROKEE_BUF_INIT; cherokee_buffer_t bpass = CHEROKEE_BUF_INIT; /* Sanity check */ if (unlikely ((conn->validator == NULL) || cherokee_buffer_is_empty(&conn->validator->user))) { return ret_error; } /* Get the full path to the file */ ret = cherokee_validator_file_get_full_path (VFILE(plain), conn, &fpass, &CONN_THREAD(conn)->tmp_buf1); if (ret != ret_ok) { ret = ret_error; goto out; } /* Read its contents */ ret = cherokee_buffer_read_file (&file, fpass->buf); if (ret != ret_ok) { ret = ret_error; goto out; } if (! cherokee_buffer_is_ending(&file, '\n')) cherokee_buffer_add_str (&file, "\n"); p = file.buf; end = file.buf + file.len; while (p < end) { char *eol; char *colon; /* Look for the EOL */ eol = strchr (p, '\n'); if (eol == NULL) { ret = ret_ok; goto out; } *eol = '\0'; /* Skip comments */ if (p[0] == '#') goto next; colon = strchr (p, ':'); if (colon == NULL) { goto next; } /* Is it the right user? */ cherokee_buffer_clean (&buser); cherokee_buffer_add (&buser, p, colon - p); re = cherokee_buffer_cmp_buf (&buser, &conn->validator->user); if (re != 0) goto next; /* Check the password */ cherokee_buffer_clean (&bpass); cherokee_buffer_add (&bpass, colon+1, eol - (colon+1)); switch (conn->req_auth_type) { case http_auth_basic: /* Empty password */ if (cherokee_buffer_is_empty (&bpass) && cherokee_buffer_is_empty (&conn->validator->passwd)) { ret = ret_ok; goto out; } /* Check the passwd */ re = cherokee_buffer_cmp_buf (&bpass, &conn->validator->passwd); if (re != 0) ret = ret_deny; goto out; case http_auth_digest: ret = cherokee_validator_digest_check (VALIDATOR(plain), &bpass, conn); goto out; default: SHOULDNT_HAPPEN; } /* A user entry has been tested and failed */ ret = ret_deny; goto out; next: p = eol + 1; /* Reached the end without success */ if (p >= end) { ret = ret_deny; goto out; } } out: cherokee_buffer_mrproper (&file); cherokee_buffer_mrproper (&buser); cherokee_buffer_mrproper (&bpass); return ret; }
static ret_t fork_and_execute_cgi_via_spawner(cherokee_handler_cgi_t *cgi) { int re; int pid = -1; cherokee_connection_t *conn = HANDLER_CONN(cgi); cherokee_handler_cgi_base_t *cgi_base = HDL_CGI_BASE(cgi); ret_t ret; uid_t uid; gid_t gid; cherokee_buffer_t empty = CHEROKEE_BUF_INIT; cherokee_buffer_t username = CHEROKEE_BUF_INIT; cherokee_services_fdmap_t fd_map; cherokee_buffer_t *chdir = NULL; cherokee_buffer_t chdir_backing = CHEROKEE_BUF_INIT; struct passwd ent; char ent_tmp[1024]; struct { int cgi[2]; int server[2]; } pipes; TRACE (ENTRIES, "Trying to create CGI via spawner\n"); if (! cherokee_buffer_is_empty (&conn->effective_directory)) { chdir = &conn->effective_directory; } else { int ofs = cgi_base->executable.len - 1; while (ofs >= 0 && cgi_base->executable.buf[ofs] != '/') { ofs--; } TRACE (ENTRIES, "While building chdir, ofs=%d\n", ofs); if (ofs < 0 || cherokee_buffer_add (&chdir_backing, cgi_base->executable.buf, ofs + 1) != ret_ok) { conn->error_code = http_internal_error; TRACE (ENTRIES, "Failed, cannot build chdir entry\n"); cherokee_buffer_mrproper(&chdir_backing); return ret_error; } chdir = &chdir_backing; } /* Creates the pipes ... */ re = cherokee_pipe (pipes.cgi); re |= cherokee_pipe (pipes.server); if (re != 0) { conn->error_code = http_internal_error; cherokee_buffer_mrproper(&chdir_backing); TRACE (ENTRIES, "Failed, cannot build pipes\n"); return ret_error; } if (HANDLER_CGI_PROPS(cgi_base)->change_user) { struct stat nocache_info; struct stat *info; cherokee_iocache_entry_t *io_entry = NULL; cherokee_server_t *srv = CONN_SRV(conn); cherokee_handler_cgi_base_props_t *props = HANDLER_CGI_BASE_PROPS(cgi); ret = cherokee_io_stat (srv->iocache, &cgi_base->executable, props->use_cache, &nocache_info, &io_entry, &info); if (ret != ret_ok) { info = &nocache_info; nocache_info.st_uid = getuid(); nocache_info.st_gid = getgid(); } uid = info->st_uid; gid = info->st_gid; cherokee_iocache_entry_unref(&io_entry); } else { /* Not changing, so launch as the same uid/gid as the worker */ uid = getuid(); gid = getgid(); } /* Determine the username of the owner of the file */ ret = cherokee_getpwuid(uid, &ent, ent_tmp, sizeof (ent_tmp)); if (ret != ret_ok || cherokee_buffer_add(&username, ent.pw_name, strlen(ent.pw_name) != ret_ok)) { cherokee_fd_close(pipes.cgi[0]); cherokee_fd_close(pipes.cgi[1]); cherokee_fd_close(pipes.server[0]); cherokee_fd_close(pipes.server[1]); conn->error_code = http_internal_error; cherokee_buffer_mrproper(&chdir_backing); cherokee_buffer_mrproper(&username); TRACE (ENTRIES, "Failed, Unable to retrieve username for uid %d\n", uid); return ret_error; } /* Update the environment ready to run */ add_environment (cgi, conn); /* Set up the FD map */ fd_map.fd_in = pipes.server[0]; fd_map.fd_out = pipes.cgi[1]; if ((CONN_VSRV(conn)->error_writer != NULL) && (CONN_VSRV(conn)->error_writer->fd != -1)) { fd_map.fd_err = CONN_VSRV(conn)->error_writer->fd; } else { fd_map.fd_err = fd_map.fd_out; } TRACE (ENTRIES, "Doing Spawn\n"); ret = cherokee_services_client_spawn (&cgi_base->executable, &username, uid, gid, &empty, chdir, false, cgi->envp, CONN_VSRV(conn)->error_writer, &pid, &fd_map); cherokee_buffer_mrproper(&chdir_backing); cherokee_buffer_mrproper(&username); /* Close the client FDs */ cherokee_fd_close (pipes.server[0]); cherokee_fd_close (pipes.cgi[1]); /* Did we fail to try to spawn? */ if (ret != ret_ok) { /* Close the server FDs too */ cherokee_fd_close (pipes.server[1]); cherokee_fd_close (pipes.cgi[0]); TRACE (ENTRIES, "Failed to spawn\n"); return ret; } /* Did we try, but fail, to spawn? */ if (pid == -1) { /* Close the server FDs too */ cherokee_fd_close (pipes.server[1]); cherokee_fd_close (pipes.cgi[0]); TRACE (ENTRIES, "Spawned, but failed server side\n"); return ret_error; } /* Successfully launched */ cgi->pid = pid; cgi->pipeInput = pipes.cgi[0]; cgi->pipeOutput = pipes.server[1]; /* Set to Input to NON-BLOCKING */ _fd_set_properties (cgi->pipeInput, O_NDELAY|O_NONBLOCK, 0); TRACE (ENTRIES, "CGI running, PID=%d\n", pid); 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; }
ret_t cherokee_handler_secdownload_new (cherokee_handler_t **hdl, void *cnt, cherokee_module_props_t *props) { int re; ret_t ret; char *p; cuint_t path_len; time_t time_url; char *time_s; cherokee_buffer_t md5 = CHEROKEE_BUF_INIT; cherokee_connection_t *conn = CONN(cnt); TRACE(ENTRIES, "Analyzing request '%s'\n", conn->request.buf); /* Sanity check */ if (conn->request.len <= 1 + 32 + 2) { TRACE(ENTRIES, "Malformed URL. Too short: len=%d.\n", conn->request.len); conn->error_code = http_not_found; return ret_error; } if (conn->request.buf[0] != '/') { TRACE(ENTRIES, "Malformed URL: %s\n", "Not slash (1)"); conn->error_code = http_not_found; return ret_error; } p = conn->request.buf + 1; if (check_hex (p, 32)) { TRACE(ENTRIES, "Malformed URL: %s\n", "No MD5"); conn->error_code = http_not_found; return ret_error; } p += 32; if (*p != '/') { TRACE(ENTRIES, "Malformed URL: %s\n", "Not slash (2)"); conn->error_code = http_not_found; return ret_error; } p += 1; time_s = p; if (check_hex (p, 8)) { TRACE(ENTRIES, "Malformed URL: %s\n", "No MD5 (2)"); conn->error_code = http_not_found; return ret_error; } p += 8; /* Check the time */ time_url = get_time (time_s); if ((cherokee_bogonow_now - time_url) > (int)PROP_SECDOWN(props)->timeout) { TRACE(ENTRIES, "Time out: %d (now=%d)\n", time_url, cherokee_bogonow_now); conn->error_code = http_gone; return ret_error; } /* Check the MD5 * [secret][path][hex(time)] */ path_len = (conn->request.buf + conn->request.len) - p; cherokee_buffer_add_buffer (&md5, &PROP_SECDOWN(props)->secret); cherokee_buffer_add (&md5, p, path_len); cherokee_buffer_add (&md5, time_s, 8); cherokee_buffer_encode_md5_digest (&md5); re = strncasecmp (md5.buf, &conn->request.buf[1], 32); if (re != 0) { TRACE(ENTRIES, "MD5 (%s) didn't match\n", md5.buf); cherokee_buffer_mrproper(&md5); conn->error_code = http_access_denied; return ret_error; } cherokee_buffer_mrproper (&md5); /* At this point the request has been validated */ if (cherokee_buffer_is_empty (&conn->request_original)) { cherokee_buffer_add_buffer (&conn->request_original, &conn->request); cherokee_buffer_add_buffer (&conn->query_string_original, &conn->query_string); } cherokee_buffer_clean (&conn->request); cherokee_buffer_add (&conn->request, p, path_len); /* Instance the File handler */ ret = cherokee_handler_file_new (hdl, cnt, MODULE_PROPS(PROP_SECDOWN(props)->props_file)); if (ret != ret_ok) return ret_ok; return ret_ok; }
static ret_t downloader_header_read (cherokee_downloader_t *downloader, cherokee_buffer_t *tmp1, cherokee_buffer_t *tmp2) { ret_t ret; cuint_t len; size_t read_ = 0; cherokee_socket_t *sock = &downloader->socket; cherokee_http_t error_code = http_bad_request; UNUSED(tmp2); ret = cherokee_socket_bufread (sock, &downloader->reply_header, DEFAULT_RECV_SIZE, &read_); switch (ret) { case ret_eof: return ret_eof; case ret_eagain: return ret_eagain; case ret_ok: /* Count */ downloader->info.headers_recv += read_; /* Check the header. Is it complete? */ ret = cherokee_header_has_header (downloader->header, &downloader->reply_header, 0); switch (ret) { case ret_ok: break; case ret_not_found: /* It needs to read more headers ... */ return ret_eagain; default: /* Too many initial CRLF */ return ret_error; } /* Parse the header */ ret = cherokee_header_parse (downloader->header, &downloader->reply_header, &error_code); if (unlikely (ret != ret_ok)) return ret_error; /* Look for the length, it will need to drop out the header from the buffer */ cherokee_header_get_length (downloader->header, &len); /* Maybe it has some body */ if (downloader->reply_header.len > len) { uint32_t body_chunk; /* Skip the CRLF separator and copy the body */ len += 2; body_chunk = downloader->reply_header.len - len; downloader->info.body_recv += body_chunk; cherokee_buffer_add (&downloader->body, downloader->reply_header.buf + len, body_chunk); cherokee_buffer_drop_ending (&downloader->reply_header, body_chunk); } /* Try to read the "Content-Length" response header */ ret = cherokee_header_has_known (downloader->header, header_content_length); if (ret == ret_ok) { cherokee_buffer_clean (tmp1); ret = cherokee_header_copy_known (downloader->header, header_content_length, tmp1); if (ret == ret_ok) { ret = cherokee_atou (tmp1->buf, &downloader->content_length); #ifdef TRACE_ENABLED if (ret == ret_ok) { TRACE (ENTRIES, "Known length: %d bytes\n", downloader->content_length); } else { TRACE (ENTRIES, "Could not parse Content-Length\n"); } #endif } } return ret_ok; case ret_error: /* Opsss.. something has failed */ return ret_error; default: RET_UNKNOWN (ret); return ret; } return ret_error; }
ret_t cherokee_buffer_add_buffer_slice (cherokee_buffer_t *buf, cherokee_buffer_t *buf2, ssize_t begin, ssize_t end) { ssize_t pos_end; ssize_t pos_begin; /* Ensure there's something to copy */ if (unlikely (cherokee_buffer_is_empty (buf2))) return ret_ok; if ((end != CHEROKEE_BUF_SLIDE_NONE) && (begin != CHEROKEE_BUF_SLIDE_NONE)) { pos_begin = (begin > 0) ? begin : buf2->len - abs(begin); pos_end = (end > 0) ? end : buf2->len - abs(end); if (pos_end <= pos_begin) { return ret_ok; } } /* Check the end */ if (end == CHEROKEE_BUF_SLIDE_NONE) { /* [__:] */ pos_end = buf2->len; } else { if (end > 0) { /* [__:x] */ pos_end = end; } else { if ((-end) <= buf2->len) { /* [__:-x] */ pos_end = buf2->len - (-end); } else { /* [__:-xxxxx] */ return ret_ok; } } } /* Check the beginning */ if (begin == CHEROKEE_BUF_SLIDE_NONE) { /* [:__] */ pos_begin = 0; } else { if (begin >= 0) { if (begin > buf2->len) { /* [xxxx:__] */ pos_begin = buf2->len; } else { /* [x:__] */ pos_begin = begin; } } else { if ((-begin) < buf2->len) { /* [-x:__] */ pos_begin = buf2->len - (-begin); } else { /* [-xxxx:__] */ pos_begin = 0; } } } /* Sanity check */ if (unlikely ((pos_begin < 0) || (pos_end < 0) || (pos_end > buf2->len) || (pos_end < pos_begin))) { return ret_ok; } /* Copy the substring */ return cherokee_buffer_add (buf, buf2->buf + pos_begin, pos_end - pos_begin); }
/* Methods implementation */ static ret_t process_package (cherokee_handler_fcgi_t *hdl, cherokee_buffer_t *inbuf, cherokee_buffer_t *outbuf) { FCGI_Header *header; cuint_t len; char *data; cuint_t type; cuint_t id; cuint_t padding; /* Is there enough information? */ if (inbuf->len < sizeof(FCGI_Header)) return ret_ok; /* At least there is a header */ header = (FCGI_Header *)inbuf->buf; if (header->version != 1) { cherokee_buffer_print_debug (inbuf, -1); LOG_ERROR_S (CHEROKEE_ERROR_HANDLER_FCGI_VERSION); return ret_error; } if (header->type != FCGI_STDERR && header->type != FCGI_STDOUT && header->type != FCGI_END_REQUEST) { cherokee_buffer_print_debug (inbuf, -1); LOG_ERROR_S (CHEROKEE_ERROR_HANDLER_FCGI_PARSING); return ret_error; } /* Read the header */ type = header->type; padding = header->paddingLength; id = (header->requestIdB0 | (header->requestIdB1 << 8)); len = (header->contentLengthB0 | (header->contentLengthB1 << 8)); data = inbuf->buf + FCGI_HEADER_LEN; /* printf ("have %d, hdr=%d exp_len=%d pad=%d\n", inbuf->len, FCGI_HEADER_LEN, len, padding); */ /* Is the package complete? */ if (len + padding > inbuf->len - FCGI_HEADER_LEN) { /* printf ("Incomplete: %d < %d\n", len + padding, inbuf->len - FCGI_HEADER_LEN); */ return ret_ok; } /* It has received the full package content */ switch (type) { case FCGI_STDERR: /* printf ("READ:STDERR (%d): %s", len, data?data:""); */ LOG_ERROR (CHEROKEE_ERROR_HANDLER_FCGI_STDERR, data); /* Debug mode */ if (SOURCE_INT(hdl->src_ref)->debug) { PRINT_MSG ("%.*s\n", len, data); } break; case FCGI_STDOUT: /* printf ("READ:STDOUT eof=%d: %d", HDL_CGI_BASE(hdl)->got_eof, len); */ cherokee_buffer_add (outbuf, data, len); break; case FCGI_END_REQUEST: /* printf ("READ:END"); */ HDL_CGI_BASE(hdl)->got_eof = true; break; default: SHOULDNT_HAPPEN; } cherokee_buffer_move_to_begin (inbuf, len + FCGI_HEADER_LEN + padding); /* printf ("- FCGI left %d\n", inbuf->len); */ return ret_eagain; }
ret_t cherokee_validator_parse_digest (cherokee_validator_t *validator, char *str, cuint_t str_len) { cuint_t len; char *end; char *entry; char *comma; char *equal; cherokee_buffer_t auth = CHEROKEE_BUF_INIT; cherokee_buffer_t *entry_buf; /* Copy authentication string */ cherokee_buffer_add (&auth, str, str_len); entry = auth.buf; end = auth.buf + auth.len; do { /* Skip some chars */ while ((*entry == CHR_SP) || (*entry == CHR_CR) || (*entry == CHR_LF)) entry++; /* Check for the end */ if (entry >= end) break; comma = strchr(entry, ','); if (equal_str (entry, "nc")) { entry_buf = &validator->nc; } else if (equal_str (entry, "uri")) { entry_buf = &validator->uri; } else if (equal_str (entry, "qop")) { entry_buf = &validator->qop; } else if (equal_str (entry, "realm")) { entry_buf = &validator->realm; } else if (equal_str (entry, "nonce")) { entry_buf = &validator->nonce; } else if (equal_str (entry, "cnonce")) { entry_buf = &validator->cnonce; } else if (equal_str (entry, "username")) { entry_buf = &validator->user; } else if (equal_str (entry, "response")) { entry_buf = &validator->response; } else if (equal_str (entry, "algorithm")) { entry_buf = &validator->algorithm; } else { entry = comma + 1; continue; } /* Split the string [1] */ if (comma) *comma = '\0'; equal = strchr (entry, '='); if (equal == NULL) { if (comma) *comma = ','; /* [1] */ continue; } /* Check for "s and skip it */ equal += (equal[1] == '"') ? 2 : 1; len = strlen(equal); while ((len > 0) && ((equal[len-1] == '"') || (equal[len-1] == CHR_CR) || (equal[len-1] == CHR_LF))) len--; /* Copy the entry value */ cherokee_buffer_add (entry_buf, equal, len); /* Resore [1], and prepare next loop */ if (comma) *comma = ','; entry = comma + 1; } while (comma != NULL); #if 0 printf ("nc %s\n", validator->nc.buf); printf ("uri %s\n", validator->uri.buf); printf ("qop %s\n", validator->qop.buf); printf ("realm %s\n", validator->realm.buf); printf ("nonce %s\n", validator->nonce.buf); printf ("cnonce %s\n", validator->cnonce.buf); printf ("username %s\n", validator->user.buf); printf ("reponse %s\n", validator->response.buf); printf ("algorithm %s\n", validator->algorithm.buf); #endif /* Clean up and exit */ cherokee_buffer_mrproper (&auth); return ret_ok; }
static ret_t local_file_exists (cherokee_rule_extensions_t *rule, cherokee_connection_t *conn, cherokee_config_entry_t *ret_conf) { ret_t ret; struct stat *info; struct stat nocache_info; cherokee_boolean_t is_file; cherokee_iocache_entry_t *io_entry = NULL; cherokee_server_t *srv = CONN_SRV(conn); cherokee_buffer_t *tmp = THREAD_TMP_BUF1(CONN_THREAD(conn)); UNUSED(rule); /* Build the full path */ cherokee_buffer_clean (tmp); if (ret_conf->document_root != NULL) { /* A previous non-final rule set a custom document root */ cherokee_buffer_add_buffer (tmp, ret_conf->document_root); } else { cherokee_buffer_add_buffer (tmp, &conn->local_directory); } if (! cherokee_buffer_is_empty (&conn->web_directory)) { cherokee_buffer_add (tmp, conn->request.buf + conn->web_directory.len, conn->request.len - conn->web_directory.len); } else { cherokee_buffer_add_buffer (tmp, &conn->request); } /* Check the local file */ ret = cherokee_io_stat (srv->iocache, tmp, rule->use_iocache, &nocache_info, &io_entry, &info); if (ret == ret_ok) { is_file = S_ISREG(info->st_mode); } if (io_entry) { cherokee_iocache_entry_unref (&io_entry); } /* Report and return */ if (ret != ret_ok) { TRACE(ENTRIES, "Rule extensions: almost matched '%s', but file does not exist\n", tmp->buf); return ret_not_found; } if (! is_file) { TRACE(ENTRIES, "Rule extensions: almost matched '%s', but it is not a file\n", tmp->buf); return ret_not_found; } return ret_ok; }
static ret_t common_server_initialization (cherokee_server_t *srv) { ret_t ret; struct sigaction act; /* Signals it handles */ memset(&act, 0, sizeof(act)); /* SIGPIPE */ act.sa_handler = SIG_IGN; sigaction (SIGPIPE, &act, NULL); /* Signal Handler */ act.sa_sigaction = signals_handler; act.sa_flags = SA_SIGINFO; sigaction (SIGHUP, &act, NULL); sigaction (SIGUSR2, &act, NULL); sigaction (SIGSEGV, &act, NULL); sigaction (SIGTERM, &act, NULL); sigaction (SIGINT, &act, NULL); sigaction (SIGCHLD, &act, NULL); #ifdef SIGBUS sigaction (SIGBUS, &act, NULL); #endif if (document_root != NULL) { cherokee_buffer_t tmp = CHEROKEE_BUF_INIT; cherokee_buffer_t droot = CHEROKEE_BUF_INIT; /* Sanity check */ if (port > 0xFFFF) { PRINT_ERROR ("Port %d is out of limits\n", port); return ret_error; } /* Build the configuration string */ cherokee_buffer_add (&droot, document_root, strlen(document_root)); cherokee_path_arg_eval (&droot); cherokee_buffer_add_va (&tmp, "server!bind!1!port = %d\n" "vserver!1!document_root = %s\n" BASIC_CONFIG, port, droot.buf); /* Apply it */ ret = cherokee_server_read_config_string (srv, &tmp); cherokee_buffer_mrproper (&tmp); cherokee_buffer_mrproper (&droot); if (ret != ret_ok) { PRINT_MSG ("Couldn't start serving directory %s\n", document_root); return ret_error; } } else { const char *config; /* Check parameter inconsistencies */ if (port_set) { PRINT_MSG ("The -p parameter can only be used in conjunction with -r."); return ret_error; } /* Read the configuration file */ config = (config_file) ? config_file : DEFAULT_CONFIG_FILE; ret = cherokee_server_read_config_file (srv, config); if (ret != ret_ok) { PRINT_MSG ("Couldn't read the config file: %s\n", config); return ret_error; } } if (daemon_mode) cherokee_server_daemonize (srv); ret = cherokee_server_initialize (srv); if (ret != ret_ok) return ret_error; cherokee_server_unlock_threads (srv); return ret_ok; }
static ret_t parse (cherokee_handler_ssi_t *hdl, cherokee_buffer_t *in, cherokee_buffer_t *out) { 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); return ret_ok; } q = strstr (p + 5, "-->"); if (q == NULL) return ret_error; 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: 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: TRACE(ENTRIES, "Including file '%s'\n", fpath.buf); cherokee_buffer_read_file (out, fpath.buf); 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) { char tmp[50]; strftime (tmp, sizeof(tmp), "%d-%b-%Y %H:%M", localtime(&info.st_mtime)); cherokee_buffer_add (out, tmp, strlen(tmp)); } break; default: SHOULDNT_HAPPEN; } } /* !ignore */ break; default: SHOULDNT_HAPPEN; } /* switch(op) */ } /* while */ return ret_ok; }