static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) { UNUSED(srv); buffer_append_string_len(out, CONST_STR_LEN( "</tbody>\n" "</table>\n" "</div>\n" )); if (!buffer_string_is_empty(p->conf.show_readme)) { /* if we have a README file, display it in <pre class="readme"></pre> */ buffer *rb = p->conf.show_readme; if (rb->ptr[0] != '/') { buffer_copy_buffer(p->tmp_buf, con->physical.path); buffer_append_path_len(p->tmp_buf, CONST_BUF_LEN(p->conf.show_readme)); rb = p->tmp_buf; } http_list_directory_include_file(out, con->conf.follow_symlink, rb, "readme", p->conf.encode_readme); } if(p->conf.auto_layout) { buffer_append_string_len(out, CONST_STR_LEN( "<div class=\"foot\">" )); if (!buffer_string_is_empty(p->conf.set_footer)) { buffer_append_string_buffer(out, p->conf.set_footer); } else { buffer_append_string_buffer(out, con->conf.server_tag); } buffer_append_string_len(out, CONST_STR_LEN( "</div>\n" )); if (!buffer_string_is_empty(p->conf.external_js)) { buffer_append_string_len(out, CONST_STR_LEN("<script type=\"text/javascript\" src=\"")); buffer_append_string_buffer(out, p->conf.external_js); buffer_append_string_len(out, CONST_STR_LEN("\"></script>\n")); } else if (buffer_is_empty(p->conf.external_js)) { http_dirlist_append_js_table_resort(out, con); } buffer_append_string_len(out, CONST_STR_LEN( "</body>\n" "</html>\n" )); } }
int log_error_open(server *srv) { #ifdef HAVE_SYSLOG_H /* perhaps someone wants to use syslog() */ openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON); #endif srv->errorlog_mode = ERRORLOG_FD; srv->errorlog_fd = STDERR_FILENO; if (srv->srvconf.errorlog_use_syslog) { srv->errorlog_mode = ERRORLOG_SYSLOG; } else if (!buffer_string_is_empty(srv->srvconf.errorlog_file)) { const char *logfile = srv->srvconf.errorlog_file->ptr; if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) { return -1; } srv->errorlog_mode = (logfile[0] == '|') ? ERRORLOG_PIPE : ERRORLOG_FILE; } log_error_write(srv, __FILE__, __LINE__, "s", "server started"); if (srv->errorlog_mode == ERRORLOG_FD && !srv->srvconf.dont_daemonize) { /* We can only log to stderr in dont-daemonize mode; * if we do daemonize and no errorlog file is specified, we log into /dev/null */ srv->errorlog_fd = -1; } if (!buffer_string_is_empty(srv->srvconf.breakagelog_file)) { int breakage_fd; const char *logfile = srv->srvconf.breakagelog_file->ptr; if (srv->errorlog_mode == ERRORLOG_FD) { srv->errorlog_fd = dup(STDERR_FILENO); fd_close_on_exec(srv->errorlog_fd); } if (-1 == (breakage_fd = open_logfile_or_pipe(srv, logfile))) { return -1; } if (STDERR_FILENO != breakage_fd) { dup2(breakage_fd, STDERR_FILENO); close(breakage_fd); } } else if (!srv->srvconf.dont_daemonize) { /* move stderr to /dev/null */ openDevNull(STDERR_FILENO); } return 0; }
static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) { plugin_data *p = p_data; /* * cache the last successfull translation from hostname (authority) to docroot * - this saves us a stat() call * */ mod_simple_vhost_patch_connection(srv, con, p); /* build_doc_root() requires a server_root; skip module if simple-vhost.server-root is not set * or set to an empty string (especially don't cache any results!) */ if (buffer_string_is_empty(p->conf.server_root)) return HANDLER_GO_ON; if (!buffer_string_is_empty(p->conf.docroot_cache_key) && !buffer_string_is_empty(con->uri.authority) && buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) { /* cache hit */ buffer_copy_buffer(con->server_name, p->conf.docroot_cache_servername); buffer_copy_buffer(con->physical.doc_root, p->conf.docroot_cache_value); } else { /* build document-root */ if (buffer_string_is_empty(con->uri.authority) || build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) { /* not found, fallback the default-host */ if (0 == build_doc_root(srv, con, p, p->doc_root, p->conf.default_host)) { /* default host worked */ buffer_copy_buffer(con->server_name, p->conf.default_host); buffer_copy_buffer(con->physical.doc_root, p->doc_root); /* do not cache default host */ } return HANDLER_GO_ON; } /* found host */ buffer_copy_buffer(con->server_name, con->uri.authority); buffer_copy_buffer(con->physical.doc_root, p->doc_root); /* copy to cache */ buffer_copy_buffer(p->conf.docroot_cache_key, con->uri.authority); buffer_copy_buffer(p->conf.docroot_cache_value, p->doc_root); buffer_copy_buffer(p->conf.docroot_cache_servername, con->server_name); } return HANDLER_GO_ON; }
static void http_dirlist_append_js_table_resort (buffer *b, connection *con) { char col = '0'; char ascending = '0'; if (!buffer_string_is_empty(con->uri.query)) { const char *qs = con->uri.query->ptr; do { if (qs[0] == 'C' && qs[1] == '=') { switch (qs[2]) { case 'N': col = '0'; break; case 'M': col = '1'; break; case 'S': col = '2'; break; case 'T': case 'D': col = '3'; break; default: break; } } else if (qs[0] == 'O' && qs[1] == '=') { switch (qs[2]) { case 'A': ascending = '1'; break; case 'D': ascending = '0'; break; default: break; } } } while ((qs = strchr(qs, '&')) && *++qs); } buffer_append_string_len(b, CONST_STR_LEN("\n<script type=\"text/javascript\">\n// <!--\n\n")); buffer_append_string_len(b, js_simple_table_resort, sizeof(js_simple_table_resort)-1); buffer_append_string_len(b, js_simple_table_init_sort, sizeof(js_simple_table_init_sort)-1); buffer_append_string_len(b, CONST_STR_LEN("\ninit_sort(")); buffer_append_string_len(b, &col, 1); buffer_append_string_len(b, CONST_STR_LEN(", ")); buffer_append_string_len(b, &ascending, 1); buffer_append_string_len(b, CONST_STR_LEN(");\n\n// -->\n</script>\n\n")); }
static int split_get_params(array *get_params, buffer *qrystr) { size_t is_key = 1, klen = 0; char *key = qrystr->ptr, *val = NULL; if (buffer_string_is_empty(qrystr)) return 0; for (size_t i = 0, len = buffer_string_length(qrystr); i <= len; ++i) { switch(qrystr->ptr[i]) { case '=': if (is_key) { val = qrystr->ptr + i + 1; klen = (size_t)(qrystr->ptr + i - key); is_key = 0; } break; case '&': case '\0': /* fin symbol */ if (!is_key) { /* we need at least a = since the last & */ array_insert_key_value(get_params, key, klen, val, qrystr->ptr + i - val); } key = qrystr->ptr + i + 1; val = NULL; is_key = 1; break; } } return 0; }
int ssi_val_tobool(ssi_val_t *B) { if (B->type == SSI_TYPE_STRING) { return !buffer_string_is_empty(B->str); } else { return B->bo; } }
static void chunk_reset(chunk *c) { if (NULL == c) return; c->type = MEM_CHUNK; buffer_reset(c->mem); if (c->file.is_temp && !buffer_string_is_empty(c->file.name)) { unlink(c->file.name->ptr); } buffer_reset(c->file.name); if (c->file.fd != -1) { close(c->file.fd); c->file.fd = -1; } if (MAP_FAILED != c->file.mmap.start) { munmap(c->file.mmap.start, c->file.mmap.length); c->file.mmap.start = MAP_FAILED; } c->file.start = c->file.length = c->file.mmap.offset = 0; c->file.mmap.length = 0; c->file.is_temp = 0; c->offset = 0; c->next = NULL; }
void chunkqueue_get_memory(chunkqueue *cq, char **mem, size_t *len, size_t min_size, size_t alloc_size) { static const size_t REALLOC_MAX_SIZE = 256; chunk *c; buffer *b; char *dummy_mem; size_t dummy_len; force_assert(NULL != cq); if (NULL == mem) mem = &dummy_mem; if (NULL == len) len = &dummy_len; /* default values: */ if (0 == min_size) min_size = 1024; if (0 == alloc_size) alloc_size = 4096; if (alloc_size < min_size) alloc_size = min_size; if (NULL != cq->last && MEM_CHUNK == cq->last->type) { size_t have; b = cq->last->mem; have = buffer_string_space(b); /* unused buffer: allocate space */ if (buffer_string_is_empty(b)) { buffer_string_prepare_copy(b, alloc_size); have = buffer_string_space(b); } /* if buffer is really small just make it bigger */ else if (have < min_size && b->size <= REALLOC_MAX_SIZE) { size_t cur_len = buffer_string_length(b); size_t new_size = cur_len + min_size, append; if (new_size < alloc_size) new_size = alloc_size; append = new_size - cur_len; if (append >= min_size) { buffer_string_prepare_append(b, append); have = buffer_string_space(b); } } /* return pointer into existing buffer if large enough */ if (have >= min_size) { *mem = b->ptr + buffer_string_length(b); *len = have; return; } } /* allocate new chunk */ c = chunkqueue_get_unused_chunk(cq); c->type = MEM_CHUNK; chunkqueue_append_chunk(cq, c); b = c->mem; buffer_string_prepare_append(b, alloc_size); *mem = b->ptr + buffer_string_length(b); *len = buffer_string_space(b); }
static void accesslog_append_escaped(buffer *dest, buffer *str) { char *ptr, *start, *end; /* replaces non-printable chars with \xHH where HH is the hex representation of the byte */ /* exceptions: " => \", \ => \\, whitespace chars => \n \t etc. */ if (buffer_string_is_empty(str)) return; buffer_string_prepare_append(dest, buffer_string_length(str)); for (ptr = start = str->ptr, end = str->ptr + buffer_string_length(str); ptr < end; ptr++) { unsigned char const c = (unsigned char) *ptr; if (c >= ' ' && c <= '~' && c != '"' && c != '\\') { /* nothing to change, add later as one block */ } else { /* copy previous part */ if (start < ptr) { buffer_append_string_len(dest, start, ptr - start); } start = ptr + 1; switch (c) { case '"': BUFFER_APPEND_STRING_CONST(dest, "\\\""); break; case '\\': BUFFER_APPEND_STRING_CONST(dest, "\\\\"); break; case '\b': BUFFER_APPEND_STRING_CONST(dest, "\\b"); break; case '\n': BUFFER_APPEND_STRING_CONST(dest, "\\n"); break; case '\r': BUFFER_APPEND_STRING_CONST(dest, "\\r"); break; case '\t': BUFFER_APPEND_STRING_CONST(dest, "\\t"); break; case '\v': BUFFER_APPEND_STRING_CONST(dest, "\\v"); break; default: { /* non printable char => \xHH */ char hh[5] = {'\\','x',0,0,0}; char h = c / 16; hh[2] = (h > 9) ? (h - 10 + 'A') : (h + '0'); h = c % 16; hh[3] = (h > 9) ? (h - 10 + 'A') : (h + '0'); buffer_append_string_len(dest, &hh[0], 4); } break; } } } if (start < end) { buffer_append_string_len(dest, start, end - start); } }
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 int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) { stat_cache_entry *sce = NULL; force_assert(!buffer_string_is_empty(p->conf.server_root)); buffer_string_prepare_copy(out, 127); buffer_copy_buffer(out, p->conf.server_root); if (!buffer_string_is_empty(host)) { /* a hostname has to start with a alpha-numerical character * and must not contain a slash "/" */ char *dp; buffer_append_slash(out); if (NULL == (dp = strchr(host->ptr, ':'))) { buffer_append_string_buffer(out, host); } else { buffer_append_string_len(out, host->ptr, dp - host->ptr); } } buffer_append_slash(out); if (buffer_string_length(p->conf.document_root) > 1 && p->conf.document_root->ptr[0] == '/') { buffer_append_string_len(out, p->conf.document_root->ptr + 1, buffer_string_length(p->conf.document_root) - 1); } else { buffer_append_string_buffer(out, p->conf.document_root); buffer_append_slash(out); } if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) { if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), out); } return -1; } else if (!S_ISDIR(sce->st.st_mode)) { return -1; } return 0; }
static handler_t mod_status_handler(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; if (con->mode != DIRECT) return HANDLER_GO_ON; mod_status_patch_connection(srv, con, p); if (!buffer_string_is_empty(p->conf.status_url) && buffer_is_equal(p->conf.status_url, con->uri.path)) { return mod_status_handle_server_status(srv, con, p_d); } else if (!buffer_string_is_empty(p->conf.config_url) && buffer_is_equal(p->conf.config_url, con->uri.path)) { return mod_status_handle_server_config(srv, con, p_d); } else if (!buffer_string_is_empty(p->conf.statistics_url) && buffer_is_equal(p->conf.statistics_url, con->uri.path)) { return mod_status_handle_server_statistics(srv, con, p_d); } return HANDLER_GO_ON; }
static secdl_algorithm algorithm_from_string(buffer *name) { size_t ndx; if (buffer_string_is_empty(name)) return SECDL_INVALID; for (ndx = 1; ndx < sizeof(secdl_algorithm_names)/sizeof(secdl_algorithm_names[0]); ++ndx) { if (0 == strcmp(secdl_algorithm_names[ndx], name->ptr)) return (secdl_algorithm)ndx; } return SECDL_INVALID; }
void chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) { chunk *c; if (buffer_string_is_empty(mem)) return; c = chunkqueue_get_unused_chunk(cq); c->type = MEM_CHUNK; force_assert(NULL != c->mem); buffer_move(c->mem, mem); chunkqueue_prepend_chunk(cq, c); }
static int buffer_copy_dirname(buffer *dst, buffer *file) { size_t i; if (buffer_string_is_empty(file)) return -1; for (i = buffer_string_length(file); i > 0; i--) { if (file->ptr[i] == '/') { buffer_copy_string_len(dst, file->ptr, i); return 0; } } return -1; }
static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) { UNUSED(srv); buffer_append_string_len(out, CONST_STR_LEN( "</tbody>\n" "</table>\n" "</div>\n" )); if (p->conf.show_readme) { stream s; /* if we have a README file, display it in <pre class="readme"></pre> */ buffer_copy_buffer(p->tmp_buf, con->physical.path); buffer_append_slash(p->tmp_buf); buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("README.txt")); if (-1 != stream_open(&s, p->tmp_buf)) { if (p->conf.encode_readme) { buffer_append_string_len(out, CONST_STR_LEN("<pre class=\"readme\">")); buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("</pre>")); } else { buffer_append_string_len(out, s.start, s.size); } } stream_close(&s); } if(p->conf.auto_layout) { buffer_append_string_len(out, CONST_STR_LEN( "<div class=\"foot\">" )); if (!buffer_string_is_empty(p->conf.set_footer)) { buffer_append_string_buffer(out, p->conf.set_footer); } else if (buffer_is_empty(con->conf.server_tag)) { buffer_append_string_len(out, CONST_STR_LEN(PACKAGE_DESC)); } else { buffer_append_string_buffer(out, con->conf.server_tag); } buffer_append_string_len(out, CONST_STR_LEN( "</div>\n" "</body>\n" "</html>\n" )); } }
static handler_t cgi_handle_fdevent(server *srv, void *ctx, int revents) { handler_ctx *hctx = ctx; connection *con = hctx->remote_conn; joblist_append(srv, con); if (revents & FDEVENT_IN) { handler_t rc = cgi_recv_response(srv, hctx);/*(might invalidate hctx)*/ if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/ } /* perhaps this issue is already handled */ if (revents & FDEVENT_HUP) { if (con->file_started) { /* drain any remaining data from kernel pipe buffers * even if (con->conf.stream_response_body * & FDEVENT_STREAM_RESPONSE_BUFMIN) * since event loop will spin on fd FDEVENT_HUP event * until unregistered. */ handler_t rc; do { rc = cgi_recv_response(srv,hctx);/*(might invalidate hctx)*/ } while (rc == HANDLER_GO_ON); /*(unless HANDLER_GO_ON)*/ return rc; /* HANDLER_FINISHED or HANDLER_COMEBACK or HANDLER_ERROR */ } else if (!buffer_string_is_empty(hctx->response_header)) { /* unfinished header package which is a body in reality */ con->file_started = 1; if (0 != http_chunk_append_buffer(srv, con, hctx->response_header)) { cgi_connection_close(srv, hctx); return HANDLER_ERROR; } } else { # if 0 log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents); # endif } cgi_connection_close(srv, hctx); } else if (revents & FDEVENT_ERR) { /* kill all connections to the cgi process */ cgi_connection_close(srv, hctx); #if 1 log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR"); #endif return HANDLER_ERROR; } return HANDLER_FINISHED; }
void chunkqueue_use_memory(chunkqueue *cq, size_t len) { buffer *b; force_assert(NULL != cq); force_assert(NULL != cq->last && MEM_CHUNK == cq->last->type); b = cq->last->mem; if (len > 0) { buffer_commit(b, len); } else if (buffer_string_is_empty(b)) { /* unused buffer: can't remove chunk easily from * end of list, so just reset the buffer */ buffer_reset(b); } }
static handler_t cgi_handle_fdevent(server *srv, void *ctx, int revents) { handler_ctx *hctx = ctx; connection *con = hctx->remote_conn; joblist_append(srv, con); if (revents & FDEVENT_IN) { handler_t rc = cgi_recv_response(srv, hctx);/*(might invalidate hctx)*/ if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/ } /* perhaps this issue is already handled */ if (revents & (FDEVENT_HUP|FDEVENT_RDHUP)) { if (con->file_started) { /* drain any remaining data from kernel pipe buffers * even if (con->conf.stream_response_body * & FDEVENT_STREAM_RESPONSE_BUFMIN) * since event loop will spin on fd FDEVENT_HUP event * until unregistered. */ handler_t rc; const unsigned short flags = con->conf.stream_response_body; con->conf.stream_response_body &= ~FDEVENT_STREAM_RESPONSE_BUFMIN; con->conf.stream_response_body |= FDEVENT_STREAM_RESPONSE_POLLRDHUP; do { rc = cgi_recv_response(srv,hctx);/*(might invalidate hctx)*/ } while (rc == HANDLER_GO_ON); /*(unless HANDLER_GO_ON)*/ con->conf.stream_response_body = flags; return rc; /* HANDLER_FINISHED or HANDLER_COMEBACK or HANDLER_ERROR */ } else if (!buffer_string_is_empty(hctx->response)) { /* unfinished header package which is a body in reality */ con->file_started = 1; if (0 != http_chunk_append_buffer(srv, con, hctx->response)) { cgi_connection_close(srv, hctx); return HANDLER_ERROR; } if (0 == con->http_status) con->http_status = 200; /* OK */ } cgi_connection_close(srv, hctx); } else if (revents & FDEVENT_ERR) { /* kill all connections to the cgi process */ cgi_connection_close(srv, hctx); return HANDLER_ERROR; } return HANDLER_FINISHED; }
static MYSQL * mod_authn_mysql_sock_connect(server *srv, plugin_config *pconf) { if (NULL != pconf->mysql_conn) { /* reuse open db connection if same ptrs to host user pass db port */ if ( pconf->mysql_conn_host == pconf->auth_mysql_host && pconf->mysql_conn_user == pconf->auth_mysql_user && pconf->mysql_conn_pass == pconf->auth_mysql_pass && pconf->mysql_conn_db == pconf->auth_mysql_db && pconf->mysql_conn_port == pconf->auth_mysql_port) { return pconf->mysql_conn; } mod_authn_mysql_sock_close(pconf); } /* !! mysql_init() is not thread safe !! (see MySQL doc) */ pconf->mysql_conn = mysql_init(NULL); if (mysql_real_connect(pconf->mysql_conn, pconf->auth_mysql_host->ptr, pconf->auth_mysql_user->ptr, pconf->auth_mysql_pass->ptr, pconf->auth_mysql_db->ptr, pconf->auth_mysql_port, !buffer_string_is_empty(pconf->auth_mysql_socket) ? pconf->auth_mysql_socket->ptr : NULL, CLIENT_IGNORE_SIGPIPE)) { /* (copy ptrs to config data (has lifetime until server shutdown)) */ pconf->mysql_conn_host = pconf->auth_mysql_host; pconf->mysql_conn_user = pconf->auth_mysql_user; pconf->mysql_conn_pass = pconf->auth_mysql_pass; pconf->mysql_conn_db = pconf->auth_mysql_db; pconf->mysql_conn_port = pconf->auth_mysql_port; return pconf->mysql_conn; } else { /*(note: any of these params might be buffers with b->ptr == NULL)*/ log_error_write(srv, __FILE__, __LINE__, "sbsb"/*sb*/"sbss", "opening connection to mysql:", pconf->auth_mysql_host, "user:"******"pass:"******"db:", pconf->auth_mysql_db, "failed:", mysql_error(pconf->mysql_conn)); mod_authn_mysql_sock_close(pconf); return NULL; } }
char* buffer_string_prepare_append(buffer *b, size_t size) { force_assert(NULL != b); if (buffer_string_is_empty(b)) { return buffer_string_prepare_copy(b, size); } else { size_t req_size = b->used + size; /* not empty, b->used already includes a terminating 0 */ force_assert(req_size >= b->used); /* check for overflow: unsigned overflow is defined to wrap around */ force_assert(req_size >= b->used); buffer_realloc(b, req_size); return b->ptr + b->used - 1; } }
int log_error_write_multiline_buffer(server *srv, const char *filename, unsigned int line, buffer *multiline, const char *fmt, ...) { va_list ap; size_t prefix_len; buffer *b = srv->errorlog_buf; char *pos, *end, *current_line; if (buffer_string_is_empty(multiline)) return 0; if (-1 == log_buffer_prepare(b, srv, filename, line)) return 0; va_start(ap, fmt); log_buffer_append_printf(b, fmt, ap); va_end(ap); prefix_len = buffer_string_length(b); current_line = pos = multiline->ptr; end = multiline->ptr + buffer_string_length(multiline); for ( ; pos <= end ; ++pos) { switch (*pos) { case '\n': case '\r': case '\0': /* handles end of string */ if (current_line < pos) { /* truncate to prefix */ buffer_string_set_length(b, prefix_len); buffer_append_string_len(b, current_line, pos - current_line); log_write(srv, b); } current_line = pos + 1; break; default: break; } } return 0; }
static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) { size_t i; /* no filename set */ if (files->used == 0) return HANDLER_GO_ON; /** * execute all files and jump out on the first !HANDLER_GO_ON */ for (i = 0; i < files->used; i++) { data_string *ds = (data_string *)files->data[i]; handler_t ret; if (buffer_string_is_empty(ds->value)) continue; ret = magnet_attract(srv, con, p, ds->value); if (ret != HANDLER_GO_ON) return ret; } return HANDLER_GO_ON; }
static void chunk_reset(chunk *c) { if (NULL == c) return; c->type = MEM_CHUNK; buffer_reset(c->mem); if (c->file.is_temp && !buffer_string_is_empty(c->file.name)) { unlink(c->file.name->ptr); } buffer_reset(c->file.name); if(c->type == SMB_CHUNK){ if (c->file.fd != -1) { smbc_close(c->file.fd); Cdbg(DBE,"close smb file-------------------------------->remote computer"); c->file.fd = -1; } } else{ if (c->file.fd != -1) { close(c->file.fd); c->file.fd = -1; } if (MAP_FAILED != c->file.mmap.start) { munmap(c->file.mmap.start, c->file.mmap.length); c->file.mmap.start = MAP_FAILED; } } c->file.start = c->file.length = c->file.mmap.offset = 0; c->file.mmap.length = 0; c->file.is_temp = 0; c->offset = 0; c->next = NULL; }
static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) { UNUSED(srv); buffer_append_string_len(out, CONST_STR_LEN( "</tbody>\n" "</table>\n" "</div>\n" )); if (p->conf.show_readme) { /* if we have a README file, display it in <pre class="readme"></pre> */ buffer_copy_buffer(p->tmp_buf, con->physical.path); buffer_append_slash(p->tmp_buf); buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("README.txt")); http_list_directory_include_file(out, p->tmp_buf, "readme", p->conf.encode_readme); } if(p->conf.auto_layout) { buffer_append_string_len(out, CONST_STR_LEN( "<div class=\"foot\">" )); if (!buffer_string_is_empty(p->conf.set_footer)) { buffer_append_string_buffer(out, p->conf.set_footer); } else { buffer_append_string_buffer(out, con->conf.server_tag); } buffer_append_string_len(out, CONST_STR_LEN( "</div>\n" "</body>\n" "</html>\n" )); } }
static void data_string_print(const data_unset *d, int depth) { data_string *ds = (data_string *)d; size_t i, len; UNUSED(depth); /* empty and uninitialized strings */ if (buffer_string_is_empty(ds->value)) { fputs("\"\"", stdout); return; } /* print out the string as is, except prepend " with backslash */ putc('"', stdout); len = buffer_string_length(ds->value); for (i = 0; i < len; i++) { unsigned char c = ds->value->ptr[i]; if (c == '"') { fputs("\\\"", stdout); } else { putc(c, stdout); } } putc('"', stdout); }
static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) { buffer *l; server_socket *srv_sock = con->srv_socket; /* check parent first */ if (dc->parent && dc->parent->context_ndx) { /** * a nested conditional * * if the parent is not decided yet or false, we can't be true either */ if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->key); } switch (config_check_cond_cached(srv, con, dc->parent)) { case COND_RESULT_FALSE: return COND_RESULT_FALSE; case COND_RESULT_UNSET: return COND_RESULT_UNSET; default: break; } } if (dc->prev) { /** * a else branch * * we can only be executed, if all of our previous brothers * are false */ if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "sb", "go prev", dc->prev->key); } /* make sure prev is checked first */ config_check_cond_cached(srv, con, dc->prev); /* one of prev set me to FALSE */ switch (con->cond_cache[dc->context_ndx].result) { case COND_RESULT_FALSE: return con->cond_cache[dc->context_ndx].result; default: break; } } if (!con->conditional_is_valid[dc->comp]) { if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "dss", dc->comp, dc->key->ptr, con->conditional_is_valid[dc->comp] ? "yeah" : "nej"); } return COND_RESULT_UNSET; } /* pass the rules */ switch (dc->comp) { case COMP_HTTP_HOST: { char *ck_colon = NULL, *val_colon = NULL; if (!buffer_string_is_empty(con->uri.authority)) { /* * append server-port to the HTTP_POST if necessary */ l = con->uri.authority; switch(dc->cond) { case CONFIG_COND_NE: case CONFIG_COND_EQ: ck_colon = strchr(dc->string->ptr, ':'); val_colon = strchr(l->ptr, ':'); if (NULL != ck_colon && NULL == val_colon) { /* condition "host:port" but client send "host" */ buffer_copy_buffer(srv->cond_check_buf, l); buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":")); buffer_append_int(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr))); l = srv->cond_check_buf; } else if (NULL != val_colon && NULL == ck_colon) { /* condition "host" but client send "host:port" */ buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr); l = srv->cond_check_buf; } break; default: break; } #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT } else if (!buffer_string_is_empty(con->tlsext_server_name)) { l = con->tlsext_server_name; #endif } else { l = srv->empty_string; } break; } case COMP_HTTP_REMOTE_IP: { char *nm_slash; /* handle remoteip limitations * * "10.0.0.1" is provided for all comparisions * * only for == and != we support * * "10.0.0.1/24" */ if ((dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE) && (con->dst_addr.plain.sa_family == AF_INET) && (NULL != (nm_slash = strchr(dc->string->ptr, '/')))) { int nm_bits; long nm; char *err; struct in_addr val_inp; if (*(nm_slash+1) == '\0') { log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string); return COND_RESULT_FALSE; } nm_bits = strtol(nm_slash + 1, &err, 10); if (*err) { log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, err); return COND_RESULT_FALSE; } if (nm_bits > 32 || nm_bits < 0) { log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: invalid netmask:", dc->string, err); return COND_RESULT_FALSE; } /* take IP convert to the native */ buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr); #ifdef __WIN32 if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf); return COND_RESULT_FALSE; } #else if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) { log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf); return COND_RESULT_FALSE; } #endif /* build netmask */ nm = nm_bits ? htonl(~((1 << (32 - nm_bits)) - 1)) : 0; if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) { return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE; } else { return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE; } } else { l = con->dst_addr_buf; } break; } case COMP_HTTP_SCHEME: l = con->uri.scheme; break; case COMP_HTTP_URL: l = con->uri.path; break; case COMP_HTTP_QUERY_STRING: l = con->uri.query; break; case COMP_SERVER_SOCKET: l = srv_sock->srv_token; break; case COMP_HTTP_REFERER: { data_string *ds; if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) { l = ds->value; } else { l = srv->empty_string; } break; } case COMP_HTTP_COOKIE: { data_string *ds; if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) { l = ds->value; } else { l = srv->empty_string; } break; } case COMP_HTTP_USER_AGENT: { data_string *ds; if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) { l = ds->value; } else { l = srv->empty_string; } break; } case COMP_HTTP_REQUEST_METHOD: { const char *method = get_http_method_name(con->request.http_method); /* we only have the request method as const char but we need a buffer for comparing */ buffer_copy_string(srv->tmp_buf, method); l = srv->tmp_buf; break; } case COMP_HTTP_LANGUAGE: { data_string *ds; if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Language"))) { l = ds->value; } else { l = srv->empty_string; } break; } default: return COND_RESULT_FALSE; } if (NULL == l) { if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key, "(", l, ") compare to NULL"); } return COND_RESULT_FALSE; } if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key, "(", l, ") compare to ", dc->string); } switch(dc->cond) { case CONFIG_COND_NE: case CONFIG_COND_EQ: if (buffer_is_equal(l, dc->string)) { return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE; } else { return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE; } break; #ifdef HAVE_PCRE_H case CONFIG_COND_NOMATCH: case CONFIG_COND_MATCH: { cond_cache_t *cache = &con->cond_cache[dc->context_ndx]; int n; #ifndef elementsof #define elementsof(x) (sizeof(x) / sizeof(x[0])) #endif n = pcre_exec(dc->regex, dc->regex_study, CONST_BUF_LEN(l), 0, 0, cache->matches, elementsof(cache->matches)); cache->patterncount = n; if (n > 0) { cache->comp_value = l; cache->comp_type = dc->comp; return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE; } else { /* cache is already cleared */ return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE; } break; } #endif default: /* no way */ break; } return COND_RESULT_FALSE; }
static int magnet_stat(lua_State *L) { buffer *sb = magnet_checkbuffer(L, 1); server *srv = magnet_get_server(L); connection *con = magnet_get_connection(L); stat_cache_entry *sce = NULL; handler_t res; res = stat_cache_get_entry(srv, con, sb, &sce); buffer_free(sb); if (HANDLER_GO_ON != res) { lua_pushnil(L); return 1; } lua_newtable(L); // return value lua_pushboolean(L, S_ISREG(sce->st.st_mode)); lua_setfield(L, -2, "is_file"); lua_pushboolean(L, S_ISDIR(sce->st.st_mode)); lua_setfield(L, -2, "is_dir"); lua_pushboolean(L, S_ISCHR(sce->st.st_mode)); lua_setfield(L, -2, "is_char"); lua_pushboolean(L, S_ISBLK(sce->st.st_mode)); lua_setfield(L, -2, "is_block"); lua_pushboolean(L, S_ISSOCK(sce->st.st_mode)); lua_setfield(L, -2, "is_socket"); lua_pushboolean(L, S_ISLNK(sce->st.st_mode)); lua_setfield(L, -2, "is_link"); lua_pushboolean(L, S_ISFIFO(sce->st.st_mode)); lua_setfield(L, -2, "is_fifo"); lua_pushinteger(L, sce->st.st_mtime); lua_setfield(L, -2, "st_mtime"); lua_pushinteger(L, sce->st.st_ctime); lua_setfield(L, -2, "st_ctime"); lua_pushinteger(L, sce->st.st_atime); lua_setfield(L, -2, "st_atime"); lua_pushinteger(L, sce->st.st_uid); lua_setfield(L, -2, "st_uid"); lua_pushinteger(L, sce->st.st_gid); lua_setfield(L, -2, "st_gid"); lua_pushinteger(L, sce->st.st_size); lua_setfield(L, -2, "st_size"); lua_pushinteger(L, sce->st.st_ino); lua_setfield(L, -2, "st_ino"); if (!buffer_string_is_empty(sce->etag)) { /* we have to mutate the etag */ buffer *b = buffer_init(); etag_mutate(b, sce->etag); lua_pushlstring(L, CONST_BUF_LEN(b)); buffer_free(b); } else { lua_pushnil(L); } lua_setfield(L, -2, "etag"); if (!buffer_string_is_empty(sce->content_type)) { lua_pushlstring(L, CONST_BUF_LEN(sce->content_type)); } else { lua_pushnil(L); } lua_setfield(L, -2, "content-type"); return 1; }
static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_ctx *hctx, buffer *cgi_handler) { pid_t pid; int to_cgi_fds[2]; int from_cgi_fds[2]; struct stat st; UNUSED(p); #ifndef __WIN32 if (!buffer_string_is_empty(cgi_handler)) { /* stat the exec file */ if (-1 == (stat(cgi_handler->ptr, &st))) { log_error_write(srv, __FILE__, __LINE__, "sbss", "stat for cgi-handler", cgi_handler, "failed:", strerror(errno)); return -1; } } if (pipe_cloexec(to_cgi_fds)) { log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno)); return -1; } if (pipe_cloexec(from_cgi_fds)) { close(to_cgi_fds[0]); close(to_cgi_fds[1]); log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno)); return -1; } /* fork, execve */ switch (pid = fork()) { case 0: { /* child */ char **args; int argc; int i = 0; char_array env; char *c; const char *s; http_cgi_opts opts = { 0, 0, NULL, NULL }; /* move stdout to from_cgi_fd[1] */ dup2(from_cgi_fds[1], STDOUT_FILENO); #ifndef FD_CLOEXEC close(from_cgi_fds[1]); /* not needed */ close(from_cgi_fds[0]); #endif /* move the stdin to to_cgi_fd[0] */ dup2(to_cgi_fds[0], STDIN_FILENO); #ifndef FD_CLOEXEC close(to_cgi_fds[0]); /* not needed */ close(to_cgi_fds[1]); #endif /* create environment */ env.ptr = NULL; env.size = 0; env.used = 0; http_cgi_headers(srv, con, &opts, cgi_env_add, &env); /* for valgrind */ if (NULL != (s = getenv("LD_PRELOAD"))) { cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s)); } if (NULL != (s = getenv("LD_LIBRARY_PATH"))) { cgi_env_add(&env, CONST_STR_LEN("LD_LIBRARY_PATH"), s, strlen(s)); } #ifdef __CYGWIN__ /* CYGWIN needs SYSTEMROOT */ if (NULL != (s = getenv("SYSTEMROOT"))) { cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s)); } #endif if (env.size == env.used) { env.size += 16; env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr)); } env.ptr[env.used] = NULL; /* set up args */ argc = 3; args = malloc(sizeof(*args) * argc); force_assert(args); i = 0; if (!buffer_string_is_empty(cgi_handler)) { args[i++] = cgi_handler->ptr; } args[i++] = con->physical.path->ptr; args[i ] = NULL; /* search for the last / */ if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) { /* handle special case of file in root directory */ const char* physdir = (c == con->physical.path->ptr) ? "/" : con->physical.path->ptr; /* temporarily shorten con->physical.path to directory without terminating '/' */ *c = '\0'; /* change to the physical directory */ if (-1 == chdir(physdir)) { log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path); } *c = '/'; } /* we don't need the client socket */ for (i = 3; i < 256; i++) { if (i != srv->errorlog_fd) close(i); } /* exec the cgi */ execve(args[0], args, env.ptr); /* most log files may have been closed/redirected by this point, * though stderr might still point to lighttpd.breakage.log */ perror(args[0]); _exit(1); } case -1: /* error */ log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno)); close(from_cgi_fds[0]); close(from_cgi_fds[1]); close(to_cgi_fds[0]); close(to_cgi_fds[1]); return -1; default: { /* parent process */ close(from_cgi_fds[1]); close(to_cgi_fds[0]); /* register PID and wait for them asynchronously */ hctx->pid = pid; hctx->fd = from_cgi_fds[0]; hctx->fde_ndx = -1; ++srv->cur_fds; if (0 == con->request.content_length) { close(to_cgi_fds[1]); } else { /* there is content to send */ if (-1 == fdevent_fcntl_set_nb(srv->ev, to_cgi_fds[1])) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); close(to_cgi_fds[1]); cgi_connection_close(srv, hctx); return -1; } if (0 != cgi_write_request(srv, hctx, to_cgi_fds[1])) { close(to_cgi_fds[1]); cgi_connection_close(srv, hctx); return -1; } ++srv->cur_fds; } fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx); if (-1 == fdevent_fcntl_set_nb(srv->ev, hctx->fd)) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); cgi_connection_close(srv, hctx); return -1; } fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); break; } } return 0; #else return -1; #endif }
handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_cache_entry **ret_sce) { #ifdef HAVE_FAM_H fam_dir_entry *fam_dir = NULL; int dir_ndx = -1; splay_tree *dir_node = NULL; #endif stat_cache_entry *sce = NULL; stat_cache *sc; struct stat st; size_t k; int fd; struct stat lst; #ifdef DEBUG_STAT_CACHE size_t i; #endif int file_ndx; splay_tree *file_node = NULL; *ret_sce = NULL; /* * check if the directory for this file has changed */ sc = srv->stat_cache; buffer_copy_buffer(sc->hash_key, name); buffer_append_int(sc->hash_key, con->conf.follow_symlink); file_ndx = hashme(sc->hash_key); sc->files = splaytree_splay(sc->files, file_ndx); #ifdef DEBUG_STAT_CACHE for (i = 0; i < ctrl.used; i++) { if (ctrl.ptr[i] == file_ndx) break; } #endif if (sc->files && (sc->files->key == file_ndx)) { #ifdef DEBUG_STAT_CACHE /* it was in the cache */ force_assert(i < ctrl.used); #endif /* we have seen this file already and * don't stat() it again in the same second */ file_node = sc->files; sce = file_node->data; /* check if the name is the same, we might have a collision */ if (buffer_is_equal(name, sce->name)) { if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) { if (sce->stat_ts == srv->cur_ts) { *ret_sce = sce; return HANDLER_GO_ON; } } } else { /* oops, a collision, * * file_node is used by the FAM check below to see if we know this file * and if we can save a stat(). * * BUT, the sce is not reset here as the entry into the cache is ok, we * it is just not pointing to our requested file. * * */ file_node = NULL; } } else { #ifdef DEBUG_STAT_CACHE if (i != ctrl.used) { log_error_write(srv, __FILE__, __LINE__, "xSB", file_ndx, "was already inserted but not found in cache, ", name); } force_assert(i == ctrl.used); #endif } #ifdef HAVE_FAM_H /* dir-check */ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { if (0 != buffer_copy_dirname(sc->dir_name, name)) { log_error_write(srv, __FILE__, __LINE__, "sb", "no '/' found in filename:", name); return HANDLER_ERROR; } buffer_copy_buffer(sc->hash_key, sc->dir_name); buffer_append_int(sc->hash_key, con->conf.follow_symlink); dir_ndx = hashme(sc->hash_key); sc->dirs = splaytree_splay(sc->dirs, dir_ndx); if (sc->dirs && (sc->dirs->key == dir_ndx)) { dir_node = sc->dirs; } if (dir_node && file_node) { /* we found a file */ sce = file_node->data; fam_dir = dir_node->data; if (fam_dir->version == sce->dir_version) { /* the stat()-cache entry is still ok */ *ret_sce = sce; return HANDLER_GO_ON; } } } #endif /* * *lol* * - open() + fstat() on a named-pipe results in a (intended) hang. * - stat() if regular file + open() to see if we can read from it is better * * */ if (-1 == stat(name->ptr, &st)) { return HANDLER_ERROR; } if (S_ISREG(st.st_mode)) { /* fix broken stat/open for symlinks to reg files with appended slash on freebsd,osx */ if (name->ptr[buffer_string_length(name) - 1] == '/') { errno = ENOTDIR; return HANDLER_ERROR; } /* try to open the file to check if we can read it */ if (-1 == (fd = open(name->ptr, O_RDONLY))) { return HANDLER_ERROR; } close(fd); } if (NULL == sce) { #ifdef DEBUG_STAT_CACHE int osize = splaytree_size(sc->files); #endif sce = stat_cache_entry_init(); buffer_copy_buffer(sce->name, name); sc->files = splaytree_insert(sc->files, file_ndx, sce); #ifdef DEBUG_STAT_CACHE if (ctrl.size == 0) { ctrl.size = 16; ctrl.used = 0; ctrl.ptr = malloc(ctrl.size * sizeof(*ctrl.ptr)); } else if (ctrl.size == ctrl.used) { ctrl.size += 16; ctrl.ptr = realloc(ctrl.ptr, ctrl.size * sizeof(*ctrl.ptr)); } ctrl.ptr[ctrl.used++] = file_ndx; force_assert(sc->files); force_assert(sc->files->data == sce); force_assert(osize + 1 == splaytree_size(sc->files)); #endif } sce->st = st; sce->stat_ts = srv->cur_ts; /* catch the obvious symlinks * * this is not a secure check as we still have a race-condition between * the stat() and the open. We can only solve this by * 1. open() the file * 2. fstat() the fd * * and keeping the file open for the rest of the time. But this can * only be done at network level. * * per default it is not a symlink * */ #ifdef HAVE_LSTAT sce->is_symlink = 0; /* we want to only check for symlinks if we should block symlinks. */ if (!con->conf.follow_symlink) { if (stat_cache_lstat(srv, name, &lst) == 0) { #ifdef DEBUG_STAT_CACHE log_error_write(srv, __FILE__, __LINE__, "sb", "found symlink", name); #endif sce->is_symlink = 1; } /* * we assume "/" can not be symlink, so * skip the symlink stuff if our path is / **/ else if (buffer_string_length(name) > 1) { buffer *dname; char *s_cur; dname = buffer_init(); buffer_copy_buffer(dname, name); while ((s_cur = strrchr(dname->ptr, '/'))) { buffer_string_set_length(dname, s_cur - dname->ptr); if (dname->ptr == s_cur) { #ifdef DEBUG_STAT_CACHE log_error_write(srv, __FILE__, __LINE__, "s", "reached /"); #endif break; } #ifdef DEBUG_STAT_CACHE log_error_write(srv, __FILE__, __LINE__, "sbs", "checking if", dname, "is a symlink"); #endif if (stat_cache_lstat(srv, dname, &lst) == 0) { sce->is_symlink = 1; #ifdef DEBUG_STAT_CACHE log_error_write(srv, __FILE__, __LINE__, "sb", "found symlink", dname); #endif break; }; }; buffer_free(dname); }; }; #endif if (S_ISREG(st.st_mode)) { /* determine mimetype */ buffer_reset(sce->content_type); #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) if (con->conf.use_xattr) { stat_cache_attr_get(sce->content_type, name->ptr); } #endif /* xattr did not set a content-type. ask the config */ if (buffer_string_is_empty(sce->content_type)) { size_t namelen = buffer_string_length(name); for (k = 0; k < con->conf.mimetypes->used; k++) { data_string *ds = (data_string *)con->conf.mimetypes->data[k]; buffer *type = ds->key; size_t typelen = buffer_string_length(type); if (buffer_is_empty(type)) continue; /* check if the right side is the same */ if (typelen > namelen) continue; if (0 == strncasecmp(name->ptr + namelen - typelen, type->ptr, typelen)) { buffer_copy_buffer(sce->content_type, ds->value); break; } } } etag_create(sce->etag, &(sce->st), con->etag_flags); } else if (S_ISDIR(st.st_mode)) { etag_create(sce->etag, &(sce->st), con->etag_flags); } #ifdef HAVE_FAM_H if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { /* is this directory already registered ? */ if (!dir_node) { fam_dir = fam_dir_entry_init(); buffer_copy_buffer(fam_dir->name, sc->dir_name); fam_dir->version = 1; fam_dir->req = calloc(1, sizeof(FAMRequest)); if (0 != FAMMonitorDirectory(&sc->fam, fam_dir->name->ptr, fam_dir->req, fam_dir)) { log_error_write(srv, __FILE__, __LINE__, "sbsbs", "monitoring dir failed:", fam_dir->name, "file:", name, FamErrlist[FAMErrno]); fam_dir_entry_free(&sc->fam, fam_dir); fam_dir = NULL; } else { int osize = 0; if (sc->dirs) { osize = sc->dirs->size; } sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); force_assert(sc->dirs); force_assert(sc->dirs->data == fam_dir); force_assert(osize == (sc->dirs->size - 1)); } } else { fam_dir = dir_node->data; } /* bind the fam_fc to the stat() cache entry */ if (fam_dir) { sce->dir_version = fam_dir->version; } } #endif *ret_sce = sce; return HANDLER_GO_ON; }