int config_parse_file(server *srv, config_t *context, const char *fn) { tokenizer_t t; stream s; int ret; buffer *filename; if (buffer_is_empty(context->basedir) || (fn[0] == '/' || fn[0] == '\\') || (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) { filename = buffer_init_string(fn); } else { filename = buffer_init_buffer(context->basedir); buffer_append_string(filename, fn); } if (0 != stream_open(&s, filename)) { log_error_write(srv, __FILE__, __LINE__, "sbss", "opening configfile ", filename, "failed:", strerror(errno)); ret = -1; } else { tokenizer_init(&t, filename, s.start, s.size); ret = config_parse(srv, context, &t); } stream_close(&s); buffer_free(filename); return ret; }
static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) { switch(srv->errorlog_mode) { case ERRORLOG_PIPE: case ERRORLOG_FILE: case ERRORLOG_FD: if (-1 == srv->errorlog_fd) return -1; /* cache the generated timestamp */ if (srv->cur_ts != srv->last_generated_debug_ts) { buffer_prepare_copy(srv->ts_debug_str, 255); strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts))); srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1; srv->last_generated_debug_ts = srv->cur_ts; } buffer_copy_string_buffer(b, srv->ts_debug_str); buffer_append_string_len(b, CONST_STR_LEN(": (")); break; case ERRORLOG_SYSLOG: /* syslog is generating its own timestamps */ buffer_copy_string_len(b, CONST_STR_LEN("(")); break; } buffer_append_string(b, filename); buffer_append_string_len(b, CONST_STR_LEN(".")); buffer_append_long(b, line); buffer_append_string_len(b, CONST_STR_LEN(") ")); return 0; }
static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const char *fn) { if (buffer_is_empty(basedir) && (fn[0] == '/' || fn[0] == '\\') && (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) { t->file = buffer_init_string(fn); } else { t->file = buffer_init_buffer(basedir); buffer_append_string(t->file, fn); } if (0 != stream_open(&(t->s), t->file)) { log_error_write(srv, __FILE__, __LINE__, "sbss", "opening configfile ", t->file, "failed:", strerror(errno)); buffer_free(t->file); return -1; } t->input = t->s.start; t->offset = 0; t->size = t->s.size; t->line = 1; t->line_pos = 1; t->in_key = 1; t->in_brace = 0; t->in_cond = 0; return 0; }
static int mod_status_header_append(buffer *b, const char *key) { BUFFER_APPEND_STRING_CONST(b, " <tr>\n"); BUFFER_APPEND_STRING_CONST(b, " <th colspan=\"2\">"); buffer_append_string(b, key); BUFFER_APPEND_STRING_CONST(b, "</th>\n"); BUFFER_APPEND_STRING_CONST(b, " </tr>\n"); return 0; }
static int mod_status_header_append(buffer *b, const char *key) { buffer_append_string_len(b, CONST_STR_LEN(" <tr>\n")); buffer_append_string_len(b, CONST_STR_LEN(" <th colspan=\"2\">")); buffer_append_string(b, key); buffer_append_string_len(b, CONST_STR_LEN("</th>\n")); buffer_append_string_len(b, CONST_STR_LEN(" </tr>\n")); return 0; }
static ngx_int_t ngx_http_subs_match_fix_substituion(ngx_http_request_t *r, sub_pair_t *pair, ngx_buf_t *b, ngx_buf_t *dst) { u_char *sub_start; ngx_int_t count = 0; while(b->pos < b->last) { if (pair->once && pair->matched) { break; } sub_start = subs_memmem(b->pos, b->last - b->pos, pair->match.data, pair->match.len); if (sub_start == NULL) { break; } pair->matched++; count++; if (buffer_append_string(dst, b->pos, sub_start - b->pos, r->pool) == NULL) { return NGX_ERROR; } if (buffer_append_string(dst, pair->sub.data, pair->sub.len, r->pool) == NULL) { return NGX_ERROR; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "fixed string match: %p", sub_start); b->pos = sub_start + pair->match.len; if ((ngx_uint_t)(b->last - b->pos) < pair->match.len) break; } return count; }
static void proxy_append_header(connection *con, const char *key, const char *value) { data_string *ds_dst; if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) { ds_dst = data_string_init(); } buffer_copy_string(ds_dst->key, key); buffer_append_string(ds_dst->value, value); array_insert_unique(con->request.headers, (data_unset *)ds_dst); }
void md5String(const char* input1, const char* input2, char** out) { int i; buffer* b = buffer_init(); unsigned char signature[16]; MD5_CTX ctx; MD5_Init(&ctx); if(input1){ //Cdbg(1, "input1 %s", input1); MD5_Update(&ctx, input1, strlen(input1)); } if(input2){ //Cdbg(1, "input2 %s", input2); MD5_Update(&ctx, input2, strlen(input2)); } MD5_Final(signature, &ctx); char tempstring[2]; for(i=0; i<16; i++){ int x = signature[i]/16; sprintf(tempstring, "%x", x); buffer_append_string(b, tempstring); int y = signature[i]%16; sprintf(tempstring, "%x", y); buffer_append_string(b, tempstring); } //Cdbg(1, "result %s", b->ptr); int len = b->used + 1; *out = (char*)malloc(len); memset(*out, '\0', len); strcpy(*out, b->ptr); buffer_free(b); }
static handler_t mod_status_handle_server_status_text(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; buffer *b; double avg; time_t ts; char buf[32]; b = chunkqueue_get_append_buffer(con->write_queue); /* output total number of requests */ BUFFER_APPEND_STRING_CONST(b, "Total Accesses: "); avg = p->abs_requests; snprintf(buf, sizeof(buf) - 1, "%.0f", avg); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, "\n"); /* output total traffic out in kbytes */ BUFFER_APPEND_STRING_CONST(b, "Total kBytes: "); avg = p->abs_traffic_out / 1024; snprintf(buf, sizeof(buf) - 1, "%.0f", avg); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, "\n"); /* output uptime */ BUFFER_APPEND_STRING_CONST(b, "Uptime: "); ts = srv->cur_ts - srv->startup_ts; buffer_append_long(b, ts); BUFFER_APPEND_STRING_CONST(b, "\n"); /* output busy servers */ BUFFER_APPEND_STRING_CONST(b, "BusyServers: "); buffer_append_long(b, srv->conns->used); BUFFER_APPEND_STRING_CONST(b, "\n"); /* set text/plain output */ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain")); return 0; }
static void cgi_copy_err(chunkqueue *cq) { buffer *line = buffer_init(); chunk *c; for (c = cq->first; c; c = c->next) { off_t we_have; char *str, *nl; if (c->type != MEM_CHUNK) { ERROR("%s", "wrong chunk type"); chunk_set_done(c); continue; } we_have = c->mem->used - 1 - c->offset; str = c->mem->ptr + c->offset; if (we_have <= 0) continue; for ( ; NULL != (nl = strchr(str, '\n')); str = nl+1) { *nl = '\0'; if (!buffer_is_empty(line)) { buffer_append_string(line, str); cgi_log_err(SAFE_BUF_STR(line)); buffer_reset(line); } else { cgi_log_err(str); } } if (*str) { buffer_append_string(line, str); } chunk_set_done(c); } if (!buffer_is_empty(line)) { cgi_log_err(SAFE_BUF_STR(line)); } chunkqueue_remove_finished_chunks(cq); }
TEST(Buffer, SimpleCase) { buffer * buf; buf = buffer_new(3); buffer_append_string(buf, "K1"); EXPECT_EQ(buf->used, 2); buffer_camelify(buf); EXPECT_TRUE(strncmp((char*)buf->data, "K1", buf->used) == 0); buffer_destroy(buf); }
/** * VMNative: string_append( workshop , string ) * Accepts a workshop argument and a string. The string will be allocated * onto the buffer. */ static bool vmn_str_append(VM * vm, VMArg * arg, int argc) { VMLibData * data; Buffer * buffer; char * appendStr; /* check for proper number of arguments */ if(argc != 2) { vm_set_err(vm, VMERR_INCORRECT_NUMARGS); return false; } /* check argument 1 major type */ if(vmarg_type(arg[0]) != TYPE_LIBDATA) { vm_set_err(vm, VMERR_INVALID_TYPE_ARGUMENT); return false; } /* extract the libdata from the argument */ data = vmarg_libdata(arg[0]); /* check libdata type */ if(!vmlibdata_is_type(data, LIBSTR_STRING_TYPE, LIBSTR_STRING_TYPE_LEN)) { vm_set_err(vm, VMERR_INVALID_TYPE_ARGUMENT); return false; } /* check argument 2 type */ if(!vmarg_is_string(arg[1])) { vm_set_err(vm, VMERR_INVALID_TYPE_ARGUMENT); return false; } /* extract the buffer */ buffer = vmlibdata_data(data); appendStr = vmarg_string(arg[1]); /* append the string to the buffer * TODO: perhaps make it so this doesn't have to use strlen */ if(!buffer_append_string(buffer, appendStr, strlen(appendStr))) { vm_set_err(vm, VMERR_ALLOC_FAILED); return false; } /* push null result */ vmarg_push_null(vm); /* this function does return a value */ return true; }
void save_arpping_list(void) { #if EMBEDDED_EANBLE smb_srv_info_t* c; buffer* smbdav_list = buffer_init(); buffer_copy_string(smbdav_list, ""); for (c = smb_srv_info_list; c; c = c->next) { if(c->name->used == 0 || strcmp(c->name->ptr,"")==0) continue; char temp[50]="\0"; sprintf(temp, "%s<%s<%s<%d>", c->name->ptr, c->ip->ptr, c->mac->ptr, c->online); buffer_append_string(smbdav_list, temp); } Cdbg(DBE, "nvram_set_smbdav_str %s", smbdav_list->ptr); nvram_set_smbdav_str(smbdav_list->ptr); buffer_free(smbdav_list); #else unlink(g_temp_file); smb_srv_info_t* c; char mybuffer[100]; FILE* fp = fopen(g_temp_file, "w"); Cdbg(DBE, "save_arpping_list %s", g_temp_file); if(fp!=NULL){ smb_srv_info_t* c; for (c = smb_srv_info_list; c; c = c->next) { if(c->name->used == 0 || strcmp(c->name->ptr,"")==0) continue; fprintf(fp, "%s<%s<%s<%d\n", c->name->ptr, c->ip->ptr, c->mac->ptr, c->online); } fclose(fp); } #endif }
TEST(Buffer, Case) { buffer * buf; buf = buffer_new(1); buffer_append_char(buf, 'n'); EXPECT_EQ(buf->used, 1); EXPECT_EQ(buf->size, 1); buffer_append_string(buf, "Idium-a-nEw-breed-of-browser"); EXPECT_EQ(buf->used, 29); buffer_camelify(buf); EXPECT_TRUE(strncmp((char*)buf->data, "NIdium-A-NEw-Breed-Of-Browser ", buf->used) == 0); //@FIXME: EXPECT_TRUE(strncmp((char*)buf->data, "NidiumANewBreedOfBrowser ", buf->used) == 0); EXPECT_EQ(buf->used, 24); buffer_destroy(buf); }
void interleave( char* src, int charcnt, char** out ) { int src_len = strlen(src); int ic = src_len / charcnt; buffer* ret = buffer_init(); for( int i = 0; i < ic; i++ ) { for( int j = 0; j < charcnt; j++ ) { //ret += src.charAt( (j * ic) + i ); int x = (j * ic) + i; char tmps[8]="\0"; sprintf(tmps, "%c", *(src+x)); //Cdbg(DBE, "tmps = %s", tmps); buffer_append_string(ret, tmps); } } *out = (char*)malloc(ret->size+1); strcpy(*out, ret->ptr); buffer_free(ret); //Cdbg(DBE, "end interleave"); /* // example: input string "ABCDEFG", charcnt = 3 --> "ADGBE0CF0" var ret = ""; var ic = Math.ceil( src.length / charcnt ); for( var i = 0; i < ic; i++ ) { for( var j = 0; j < charcnt; j++ ) { ret += src.charAt( (j * ic) + i ); } } return ret; */ }
static ngx_int_t ngx_http_subs_body_filter_process_buffer(ngx_http_request_t *r, ngx_buf_t *b) { u_char *p, *last, *linefeed; ngx_int_t len, rc; ngx_http_subs_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_subs_filter_module); if (b == NULL) { return NGX_DECLINED; } p = b->pos; last = b->last; b->pos = b->last; ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "subs process in buffer: %p %uz, line_in buffer: %p %uz", b, last - p, ctx->line_in, ngx_buf_size(ctx->line_in)); if ((last - p) == 0 && ngx_buf_size(ctx->line_in) == 0){ return NGX_OK; } if ((last - p) == 0 && ngx_buf_size(ctx->line_in) && ctx->last) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "the last zero buffer, try to do substitution"); rc = ngx_http_subs_match(r, ctx); if (rc < 0) { return NGX_ERROR; } return NGX_OK; } while (p < last) { linefeed = memchr(p, LF, last - p); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "find linefeed: %p", linefeed); if (linefeed == NULL) { if (ctx->last) { linefeed = last - 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "the last buffer, not find linefeed"); } } if (linefeed) { len = linefeed - p + 1; if (buffer_append_string(ctx->line_in, p, len, r->pool) == NULL) { return NGX_ERROR; } p += len; rc = ngx_http_subs_match(r, ctx); if (rc < 0) { return NGX_ERROR; } } else { /* Not find linefeed in this chain, save the left data to line_in */ if (buffer_append_string(ctx->line_in, p, last - p, r->pool) == NULL) { return NGX_ERROR; } break; } } return NGX_OK; }
int http_response_write_header(server *srv, connection *con) { buffer *b; size_t i; int have_date = 0; int have_server = 0; b = chunkqueue_get_prepend_buffer(con->write_queue); if (con->request.http_version == HTTP_VERSION_1_1) { buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 ")); } else { buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 ")); } buffer_append_long(b, con->http_status); buffer_append_string_len(b, CONST_STR_LEN(" ")); buffer_append_string(b, get_http_status_name(con->http_status)); /* disable keep-alive if requested */ if (con->request_count > con->conf.max_keep_alive_requests || 0 == con->conf.max_keep_alive_idle) { con->keep_alive = 0; } else { con->keep_alive_idle = con->conf.max_keep_alive_idle; } if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) { if (con->keep_alive) { response_header_overwrite(srv, con, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive")); } else { response_header_overwrite(srv, con, CONST_STR_LEN("Connection"), CONST_STR_LEN("close")); } } if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { response_header_overwrite(srv, con, CONST_STR_LEN("Transfer-Encoding"), CONST_STR_LEN("chunked")); } /* add all headers */ for (i = 0; i < con->response.headers->used; i++) { data_string *ds; ds = (data_string *)con->response.headers->data[i]; if (ds->value->used && ds->key->used && 0 != strncasecmp(ds->key->ptr, CONST_STR_LEN("X-LIGHTTPD-")) && 0 != strncasecmp(ds->key->ptr, CONST_STR_LEN("X-Sendfile"))) { if (0 == strcasecmp(ds->key->ptr, "Date")) have_date = 1; if (0 == strcasecmp(ds->key->ptr, "Server")) have_server = 1; if (0 == strcasecmp(ds->key->ptr, "Content-Encoding") && 304 == con->http_status) continue; buffer_append_string_len(b, CONST_STR_LEN("\r\n")); buffer_append_string_buffer(b, ds->key); buffer_append_string_len(b, CONST_STR_LEN(": ")); #if 0 /** * the value might contain newlines, encode them with at least one white-space */ buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_HTTP_HEADER); #else buffer_append_string_buffer(b, ds->value); #endif } } if (!have_date) { /* HTTP/1.1 requires a Date: header */ buffer_append_string_len(b, CONST_STR_LEN("\r\nDate: ")); /* cache the generated timestamp */ if (srv->cur_ts != srv->last_generated_date_ts) { buffer_prepare_copy(srv->ts_date_str, 255); strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts))); srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1; srv->last_generated_date_ts = srv->cur_ts; } buffer_append_string_buffer(b, srv->ts_date_str); } if (!have_server) { if (buffer_is_empty(con->conf.server_tag)) { buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: " PACKAGE_DESC)); } else if (con->conf.server_tag->used > 1) { buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: ")); buffer_append_string_encoded(b, CONST_BUF_LEN(con->conf.server_tag), ENCODING_HTTP_HEADER); } } //- Jerry add 20110923 #if EMBEDDED_EANBLE char * ddns_host_n = nvram_get_ddns_host_name(); if(ddns_host_n){ buffer_append_string_len(b, CONST_STR_LEN("\r\nDDNS: ")); buffer_append_string(b, ddns_host_n); }else #endif buffer_append_string_len(b, CONST_STR_LEN("\r\nDDNS: ")); buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n")); con->bytes_header = b->used - 1; if (con->conf.log_response_header) { log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b); } return 0; }
static void https_add_ssl_entries(connection *con) { X509 *xs; X509_NAME *xn; X509_NAME_ENTRY *xe; int i, nentries; if ( SSL_get_verify_result(con->ssl) != X509_V_OK || !(xs = SSL_get_peer_certificate(con->ssl)) ) { return; } xn = X509_get_subject_name(xs); for (i = 0, nentries = X509_NAME_entry_count(xn); i < nentries; ++i) { int xobjnid; const char * xobjsn; data_string *envds; if (!(xe = X509_NAME_get_entry(xn, i))) { continue; } xobjnid = OBJ_obj2nid((ASN1_OBJECT*)X509_NAME_ENTRY_get_object(xe)); xobjsn = OBJ_nid2sn(xobjnid); if (!xobjsn) { continue; } if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) { envds = data_string_init(); } buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_S_DN_")); buffer_append_string(envds->key, xobjsn); buffer_copy_string_len( envds->value, (const char *)xe->value->data, xe->value->length ); /* pick one of the exported values as "authed user", for example * ssl.verifyclient.username = "******" or "SSL_CLIENT_S_DN_emailAddress" */ if (buffer_is_equal(con->conf.ssl_verifyclient_username, envds->key)) { buffer_copy_string_buffer(con->authed_user, envds->value); } array_insert_unique(con->environment, (data_unset *)envds); } if (con->conf.ssl_verifyclient_export_cert) { BIO *bio; if (NULL != (bio = BIO_new(BIO_s_mem()))) { data_string *envds; int n; PEM_write_bio_X509(bio, xs); n = BIO_pending(bio); if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) { envds = data_string_init(); } buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_CERT")); buffer_prepare_copy(envds->value, n+1); BIO_read(bio, envds->value->ptr, n); BIO_free(bio); envds->value->ptr[n] = '\0'; envds->value->used = n+1; array_insert_unique(con->environment, (data_unset *)envds); } } X509_free(xs); }
void save_sharelink_list(){ #if EMBEDDED_EANBLE share_link_info_t* c; buffer* sharelink_list = buffer_init(); buffer_copy_string(sharelink_list, ""); for (c = share_link_info_list; c; c = c->next) { if(c->toshare == 0) continue; buffer* temp = buffer_init(); buffer_copy_string_buffer(temp, c->shortpath); buffer_append_string(temp, "<"); buffer_append_string_buffer(temp, c->realpath); buffer_append_string(temp, "<"); buffer_append_string_buffer(temp, c->filename); buffer_append_string(temp, "<"); buffer_append_string_buffer(temp, c->auth); buffer_append_string(temp, "<"); char strTime[25] = {0}; sprintf(strTime, "%lu", c->expiretime); buffer_append_string(temp, strTime); buffer_append_string(temp, "<"); char strTime2[25] = {0}; sprintf(strTime2, "%lu", c->createtime); buffer_append_string(temp, strTime2); buffer_append_string(temp, ">"); buffer_append_string_buffer(sharelink_list, temp); buffer_free(temp); } nvram_set_sharelink_str(sharelink_list->ptr); buffer_free(sharelink_list); #else unlink(g_temp_sharelink_file); smb_srv_info_t* c; char mybuffer[100]; FILE* fp = fopen(g_temp_sharelink_file, "w"); if(fp!=NULL){ share_link_info_t* c; for (c = share_link_info_list; c; c = c->next) { if(c->toshare == 0) continue; fprintf(fp, "%s<%s<%s<%s<%lu<%lu\n", c->shortpath->ptr, c->realpath->ptr, c->filename->ptr, c->auth->ptr, c->expiretime, c->createtime); } fclose(fp); } #endif }
handler_t http_response_prepare(server *srv, connection *con) { handler_t r; /* looks like someone has already done a decision */ if (con->mode == DIRECT && (con->http_status != 0 && con->http_status != 200)) { /* remove a packets in the queue */ if (con->file_finished == 0) { chunkqueue_reset(con->write_queue); } return HANDLER_FINISHED; } /* no decision yet, build conf->filename */ if (con->mode == DIRECT && con->physical.path->used == 0) { char *qstr; /* we only come here when we have the parse the full request again * * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a * problem here as mod_setenv might get called multiple times * * fastcgi-auth might lead to a COMEBACK too * fastcgi again dead server too * * mod_compress might add headers twice too * * */ config_cond_cache_reset(srv, con); config_setup_connection(srv, con); /* Perhaps this could be removed at other places. */ if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "run condition"); } config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */ /** * prepare strings * * - uri.path_raw * - uri.path (secure) * - uri.query * */ /** * Name according to RFC 2396 * * - scheme * - authority * - path * - query * * (scheme)://(authority)(path)?(query)#fragment * * */ if (con->conf.is_ssl) { buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https")); } else { buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http")); } buffer_copy_string_buffer(con->uri.authority, con->request.http_host); buffer_to_lower(con->uri.authority); config_patch_connection(srv, con, COMP_HTTP_SCHEME); /* Scheme: */ config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */ config_patch_connection(srv, con, COMP_HTTP_REMOTE_IP); /* Client-IP */ config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */ config_patch_connection(srv, con, COMP_HTTP_USER_AGENT);/* User-Agent: */ config_patch_connection(srv, con, COMP_HTTP_LANGUAGE); /* Accept-Language: */ config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */ config_patch_connection(srv, con, COMP_HTTP_REQUEST_METHOD); /* REQUEST_METHOD */ /** their might be a fragment which has to be cut away */ if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) { con->request.uri->used = qstr - con->request.uri->ptr; con->request.uri->ptr[con->request.uri->used++] = '\0'; } /** extract query string from request.uri */ if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) { buffer_copy_string (con->uri.query, qstr + 1); buffer_copy_string_len(con->uri.path_raw, con->request.uri->ptr, qstr - con->request.uri->ptr); } else { buffer_reset (con->uri.query); buffer_copy_string_buffer(con->uri.path_raw, con->request.uri); } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- splitting Request-URI"); log_error_write(srv, __FILE__, __LINE__, "sb", "Request-URI : ", con->request.uri); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-scheme : ", con->uri.scheme); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-authority: ", con->uri.authority); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path_raw); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query); } /** * * call plugins * * - based on the raw URL * */ switch(r = plugins_call_handle_uri_raw(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: log_error_write(srv, __FILE__, __LINE__, "sd", "handle_uri_raw: unknown return value", r); break; } /* build filename * * - decode url-encodings (e.g. %20 -> ' ') * - remove path-modifiers (e.g. /../) */ if (con->request.http_method == HTTP_METHOD_OPTIONS && con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') { /* OPTIONS * ... */ buffer_copy_string_buffer(con->uri.path, con->uri.path_raw); } else { buffer_copy_string_buffer(srv->tmp_buf, con->uri.path_raw); buffer_urldecode_path(srv->tmp_buf); buffer_path_simplify(con->uri.path, srv->tmp_buf); } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- sanatising URI"); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path); } #ifdef USE_OPENSSL if (con->conf.is_ssl && con->conf.ssl_verifyclient) { https_add_ssl_entries(con); } #endif /** * * call plugins * * - based on the clean URL * */ config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */ config_patch_connection(srv, con, COMP_HTTP_QUERY_STRING); /* HTTPqs */ /* do we have to downgrade to 1.0 ? */ if (!con->conf.allow_http11) { con->request.http_version = HTTP_VERSION_1_0; } switch(r = plugins_call_handle_uri_clean(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: log_error_write(srv, __FILE__, __LINE__, ""); break; } if (con->request.http_method == HTTP_METHOD_OPTIONS && con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') { /* option requests are handled directly without checking of the path */ response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); con->http_status = 200; con->file_finished = 1; return HANDLER_FINISHED; } /*** * * border * * logical filename (URI) becomes a physical filename here * * * */ /* 1. stat() * ... ISREG() -> ok, go on * ... ISDIR() -> index-file -> redirect * * 2. pathinfo() * ... ISREG() * * 3. -> 404 * */ /* * SEARCH DOCUMENT ROOT */ /* set a default */ buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root); buffer_copy_string_buffer(con->physical.rel_path, con->uri.path); #if defined(__WIN32) || defined(__CYGWIN__) /* strip dots from the end and spaces * * windows/dos handle those filenames as the same file * * foo == foo. == foo..... == "foo... " == "foo.. ./" * * This will affect in some cases PATHINFO * * on native windows we could prepend the filename with \\?\ to circumvent * this behaviour. I have no idea how to push this through cygwin * * */ if (con->physical.rel_path->used > 1) { buffer *b = con->physical.rel_path; size_t i; if (b->used > 2 && b->ptr[b->used-2] == '/' && (b->ptr[b->used-3] == ' ' || b->ptr[b->used-3] == '.')) { b->ptr[b->used--] = '\0'; } for (i = b->used - 2; b->used > 1; i--) { if (b->ptr[i] == ' ' || b->ptr[i] == '.') { b->ptr[b->used--] = '\0'; } else { break; } } } #endif if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- before doc_root"); log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } /* the docroot plugin should set the doc_root and might also set the physical.path * for us (all vhost-plugins are supposed to set the doc_root) * */ switch(r = plugins_call_handle_docroot(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: log_error_write(srv, __FILE__, __LINE__, ""); break; } /* MacOS X and Windows can't distiguish between upper and lower-case * * convert to lower-case */ if (con->conf.force_lowercase_filenames) { buffer_to_lower(con->physical.rel_path); } /* the docroot plugins might set the servername, if they don't we take http-host */ if (buffer_is_empty(con->server_name)) { buffer_copy_string_buffer(con->server_name, con->uri.authority); } /** * create physical filename * -> physical.path = docroot + rel_path * */ int rel_path_used = con->physical.rel_path->used; char *rel_path_ptr = con->physical.rel_path->ptr; buffer_copy_string_buffer(con->physical.path, con->physical.doc_root); BUFFER_APPEND_SLASH(con->physical.path); buffer_copy_string_buffer(con->physical.basedir, con->physical.path); if (con->physical.rel_path->used && con->physical.rel_path->ptr[0] == '/') { if( rel_path_used > 5 && (rel_path_ptr[rel_path_used-5] == 'm') &&(rel_path_ptr[rel_path_used-4] == '3') &&(rel_path_ptr[rel_path_used-3] == 'u') &&(rel_path_ptr[rel_path_used-2] == '8') ) { buffer_append_string(con->physical.path,"1.m3u8"); } else if( rel_path_used > 3 && (rel_path_ptr[rel_path_used-3] == 't') &&(rel_path_ptr[rel_path_used-2] == 's') ) { buffer_append_string(con->physical.path,"1.ts"); } else buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2); } else { if( rel_path_used > 5 && (rel_path_ptr[rel_path_used-5] == 'm') &&(rel_path_ptr[rel_path_used-4] == '3') &&(rel_path_ptr[rel_path_used-3] == 'u') &&(rel_path_ptr[rel_path_used-2] == '8') ) { buffer_append_string(con->physical.path,"1.m3u8"); } else if( rel_path_used > 3 && (rel_path_ptr[rel_path_used-3] == 't') &&(rel_path_ptr[rel_path_used-2] == 's') ) { buffer_append_string(con->physical.path,"1.ts"); } else { buffer_append_string_buffer(con->physical.path, con->physical.rel_path); } //buffer_append_string(con->physical.path,"1.m3u8"); // buffer_append_string_buffer(con->physical.path, con->physical.rel_path); } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- after doc_root"); log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } switch(r = plugins_call_handle_physical(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: log_error_write(srv, __FILE__, __LINE__, ""); break; } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- logical -> physical"); log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } } /* * Noone catched away the file from normal path of execution yet (like mod_access) * * Go on and check of the file exists at all */ if (con->mode == DIRECT) { char *slash = NULL; char *pathinfo = NULL; int found = 0; stat_cache_entry *sce = NULL; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- handling physical path"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { /* file exists */ if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- file found"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } #ifdef HAVE_LSTAT if ((sce->is_symlink != 0) && !con->conf.follow_symlink) { con->http_status = 403; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; }; #endif if (S_ISDIR(sce->st.st_mode)) { if (con->uri.path->ptr[con->uri.path->used - 2] != '/') { /* redirect to .../ */ http_response_redirect_to_directory(srv, con); return HANDLER_FINISHED; } #ifdef HAVE_LSTAT } else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) { #else } else if (!S_ISREG(sce->st.st_mode)) { #endif /* any special handling of non-reg files ?*/ } } else { switch (errno) { case EACCES: con->http_status = 403; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; case ENAMETOOLONG: /* file name to be read was too long. return 404 */ case ENOENT: con->http_status = 404; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- file not found"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; case ENOTDIR: /* PATH_INFO ! :) */ break; default: /* we have no idea what happend. let's tell the user so. */ con->http_status = 500; buffer_reset(con->physical.path); log_error_write(srv, __FILE__, __LINE__, "ssbsb", "file not found ... or so: ", strerror(errno), con->uri.path, "->", con->physical.path); return HANDLER_FINISHED; } /* not found, perhaps PATHINFO */ buffer_copy_string_buffer(srv->tmp_buf, con->physical.path); do { if (slash) { buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr); } else { buffer_copy_string_buffer(con->physical.path, srv->tmp_buf); } if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { found = S_ISREG(sce->st.st_mode); break; } if (pathinfo != NULL) { *pathinfo = '\0'; } slash = strrchr(srv->tmp_buf->ptr, '/'); if (pathinfo != NULL) { /* restore '/' */ *pathinfo = '/'; } if (slash) pathinfo = slash; } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (con->physical.basedir->used - 2))); if (found == 0) { /* no it really doesn't exists */ con->http_status = 404; if (con->conf.log_file_not_found) { log_error_write(srv, __FILE__, __LINE__, "sbsb", "file not found:", con->uri.path, "->", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; } #ifdef HAVE_LSTAT if ((sce->is_symlink != 0) && !con->conf.follow_symlink) { con->http_status = 403; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; }; #endif /* we have a PATHINFO */ if (pathinfo) { buffer_copy_string(con->request.pathinfo, pathinfo); /* * shorten uri.path */ con->uri.path->used -= strlen(pathinfo); con->uri.path->ptr[con->uri.path->used - 1] = '\0'; } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- after pathinfo check"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path); log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo); } } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } /* call the handlers */ switch(r = plugins_call_handle_subrequest_start(srv, con)) { case HANDLER_GO_ON: /* request was not handled */ break; case HANDLER_FINISHED: default: if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished"); } /* something strange happend */ return r; } /* if we are still here, no one wanted the file, status 403 is ok I think */ if (con->mode == DIRECT && con->http_status == 0) { switch (con->request.http_method) { case HTTP_METHOD_OPTIONS: con->http_status = 200; break; default: con->http_status = 403; } return HANDLER_FINISHED; } } switch(r = plugins_call_handle_subrequest(srv, con)) { case HANDLER_GO_ON: /* request was not handled, looks like we are done */ return HANDLER_FINISHED; case HANDLER_FINISHED: /* request is finished */ default: /* something strange happend */ return r; } /* can't happen */ return HANDLER_COMEBACK; }
/* ** Perform a reduce action and the shift that must immediately ** follow the reduce. */ static void yy_reduce( yyParser *yypParser, /* The parser */ int yyruleno /* Number of the rule by which to reduce */ ){ int yygoto; /* The next state */ int yyact; /* The next action */ YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ configparserARG_FETCH; yymsp = &yypParser->yystack[yypParser->yyidx]; #ifndef NDEBUG if( yyTraceFILE && yyruleno>=0 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, yyRuleName[yyruleno]); } #endif /* NDEBUG */ switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example ** follows: ** case 0: ** #line <lineno> <grammarfile> ** { ... } // User supplied code ** #line <lineno> <thisfile> ** break; */ case 0: /* No destructor defined for metalines */ break; case 1: /* No destructor defined for metalines */ /* No destructor defined for metaline */ break; case 2: break; case 3: /* No destructor defined for varline */ break; case 4: /* No destructor defined for global */ break; case 5: #line 115 "./configparser.y" { yymsp[-1].minor.yy78 = NULL; } #line 822 "configparser.c" yy_destructor(1,&yymsp[0].minor); break; case 6: /* No destructor defined for include */ break; case 7: /* No destructor defined for include_shell */ break; case 8: yy_destructor(1,&yymsp[0].minor); break; case 9: #line 144 "./configparser.y" { if (ctx->ok) { buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43); if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) { fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n", ctx->current->context_ndx, ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr); ctx->ok = 0; } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) { array_insert_unique(ctx->current->value, yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } else { fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", ctx->current->context_ndx, ctx->current->key->ptr, yymsp[0].minor.yy41->key->ptr); ctx->ok = 0; yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } } buffer_free(yymsp[-2].minor.yy43); yymsp[-2].minor.yy43 = NULL; } #line 859 "configparser.c" yy_destructor(2,&yymsp[-1].minor); break; case 10: #line 168 "./configparser.y" { array *vars = ctx->current->value; data_unset *du; if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) { fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n", ctx->current->context_ndx, ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr); ctx->ok = 0; } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) { /* exists in current block */ du = configparser_merge_data(du, yymsp[0].minor.yy41); if (NULL == du) { ctx->ok = 0; } else { buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43); array_replace(vars, du); } yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) { du = configparser_merge_data(du, yymsp[0].minor.yy41); if (NULL == du) { ctx->ok = 0; du->free(du); } else { buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43); array_insert_unique(ctx->current->value, du); } yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); } else { buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43); array_insert_unique(ctx->current->value, yymsp[0].minor.yy41); } buffer_free(yymsp[-2].minor.yy43); yymsp[-2].minor.yy43 = NULL; yymsp[0].minor.yy41 = NULL; } #line 903 "configparser.c" yy_destructor(3,&yymsp[-1].minor); break; case 11: #line 208 "./configparser.y" { if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) { yygotominor.yy43 = buffer_init_string("var."); buffer_append_string_buffer(yygotominor.yy43, yymsp[0].minor.yy0); buffer_free(yymsp[0].minor.yy0); yymsp[0].minor.yy0 = NULL; } else { yygotominor.yy43 = yymsp[0].minor.yy0; yymsp[0].minor.yy0 = NULL; } } #line 919 "configparser.c" break; case 12: #line 220 "./configparser.y" { yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41); if (NULL == yygotominor.yy41) { ctx->ok = 0; } yymsp[-2].minor.yy41 = NULL; yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } #line 932 "configparser.c" yy_destructor(5,&yymsp[-1].minor); break; case 13: #line 230 "./configparser.y" { yygotominor.yy41 = yymsp[0].minor.yy41; yymsp[0].minor.yy41 = NULL; } #line 941 "configparser.c" break; case 14: #line 235 "./configparser.y" { yygotominor.yy41 = NULL; if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) { char *env; if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) { data_string *ds; ds = data_string_init(); buffer_append_string(ds->value, env); yygotominor.yy41 = (data_unset *)ds; } else { fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4); ctx->ok = 0; } } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) { fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr); ctx->ok = 0; } if (!yygotominor.yy41) { /* make a dummy so it won't crash */ yygotominor.yy41 = (data_unset *)data_string_init(); } buffer_free(yymsp[0].minor.yy43); yymsp[0].minor.yy43 = NULL; } #line 971 "configparser.c" break; case 15: #line 262 "./configparser.y" { yygotominor.yy41 = (data_unset *)data_string_init(); buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0); buffer_free(yymsp[0].minor.yy0); yymsp[0].minor.yy0 = NULL; } #line 981 "configparser.c" break; case 16: #line 269 "./configparser.y" { yygotominor.yy41 = (data_unset *)data_integer_init(); ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10); buffer_free(yymsp[0].minor.yy0); yymsp[0].minor.yy0 = NULL; } #line 991 "configparser.c" break; case 17: #line 275 "./configparser.y" { yygotominor.yy41 = (data_unset *)data_array_init(); array_free(((data_array *)(yygotominor.yy41))->value); ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40; yymsp[0].minor.yy40 = NULL; } #line 1001 "configparser.c" break; case 18: #line 281 "./configparser.y" { yygotominor.yy40 = array_init(); } #line 1008 "configparser.c" yy_destructor(8,&yymsp[-1].minor); yy_destructor(9,&yymsp[0].minor); break; case 19: #line 284 "./configparser.y" { yygotominor.yy40 = yymsp[-1].minor.yy40; yymsp[-1].minor.yy40 = NULL; } #line 1018 "configparser.c" yy_destructor(8,&yymsp[-2].minor); yy_destructor(9,&yymsp[0].minor); break; case 20: #line 289 "./configparser.y" { if (buffer_is_empty(yymsp[0].minor.yy41->key) || NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) { array_insert_unique(yymsp[-2].minor.yy40, yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } else { fprintf(stderr, "Duplicate array-key: %s\n", yymsp[0].minor.yy41->key->ptr); ctx->ok = 0; yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } yygotominor.yy40 = yymsp[-2].minor.yy40; yymsp[-2].minor.yy40 = NULL; } #line 1040 "configparser.c" yy_destructor(10,&yymsp[-1].minor); break; case 21: #line 306 "./configparser.y" { yygotominor.yy40 = yymsp[-1].minor.yy40; yymsp[-1].minor.yy40 = NULL; } #line 1049 "configparser.c" yy_destructor(10,&yymsp[0].minor); break; case 22: #line 311 "./configparser.y" { yygotominor.yy40 = array_init(); array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } #line 1059 "configparser.c" break; case 23: #line 317 "./configparser.y" { yygotominor.yy41 = yymsp[0].minor.yy41; yymsp[0].minor.yy41 = NULL; } #line 1067 "configparser.c" break; case 24: #line 321 "./configparser.y" { buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43); buffer_free(yymsp[-2].minor.yy43); yymsp[-2].minor.yy43 = NULL; yygotominor.yy41 = yymsp[0].minor.yy41; yymsp[0].minor.yy41 = NULL; } #line 1079 "configparser.c" yy_destructor(11,&yymsp[-1].minor); break; case 25: yy_destructor(1,&yymsp[0].minor); break; case 26: break; case 27: #line 333 "./configparser.y" { data_config *dc; dc = (data_config *)array_get_element(ctx->srv->config_context, "global"); assert(dc); configparser_push(ctx, dc, 0); } #line 1095 "configparser.c" yy_destructor(12,&yymsp[0].minor); break; case 28: #line 340 "./configparser.y" { data_config *cur; cur = ctx->current; configparser_pop(ctx); assert(cur && ctx->current); yygotominor.yy78 = cur; } #line 1110 "configparser.c" /* No destructor defined for globalstart */ yy_destructor(13,&yymsp[-2].minor); /* No destructor defined for metalines */ yy_destructor(14,&yymsp[0].minor); break; case 29: #line 351 "./configparser.y" { assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx); yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78; yymsp[-3].minor.yy78->next = yymsp[0].minor.yy78; yygotominor.yy78 = yymsp[0].minor.yy78; yymsp[-3].minor.yy78 = NULL; yymsp[0].minor.yy78 = NULL; } #line 1126 "configparser.c" /* No destructor defined for eols */ yy_destructor(15,&yymsp[-1].minor); break; case 30: #line 360 "./configparser.y" { yygotominor.yy78 = yymsp[0].minor.yy78; yymsp[0].minor.yy78 = NULL; } #line 1136 "configparser.c" break; case 31: #line 365 "./configparser.y" { data_config *cur; cur = ctx->current; configparser_pop(ctx); assert(cur && ctx->current); yygotominor.yy78 = cur; } #line 1150 "configparser.c" /* No destructor defined for context */ yy_destructor(13,&yymsp[-2].minor); /* No destructor defined for metalines */ yy_destructor(14,&yymsp[0].minor); break; case 32: #line 376 "./configparser.y" { data_config *dc; buffer *b, *rvalue, *op; if (ctx->ok && yymsp[0].minor.yy41->type != TYPE_STRING) { fprintf(stderr, "rvalue must be string"); ctx->ok = 0; } switch(yymsp[-1].minor.yy27) { case CONFIG_COND_NE: op = buffer_init_string("!="); break; case CONFIG_COND_EQ: op = buffer_init_string("=="); break; case CONFIG_COND_NOMATCH: op = buffer_init_string("!~"); break; case CONFIG_COND_MATCH: op = buffer_init_string("=~"); break; default: assert(0); return; } b = buffer_init(); buffer_copy_string_buffer(b, ctx->current->key); buffer_append_string(b, "/"); buffer_append_string_buffer(b, yymsp[-5].minor.yy0); buffer_append_string_buffer(b, yymsp[-3].minor.yy43); buffer_append_string_buffer(b, op); rvalue = ((data_string*)yymsp[0].minor.yy41)->value; buffer_append_string_buffer(b, rvalue); if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) { configparser_push(ctx, dc, 0); } else { struct { comp_key_t comp; char *comp_key; size_t len; } comps[] = { { COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) }, { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) }, { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) }, { COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) }, { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) }, { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"user-agent\"]" ) }, { COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) }, { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) }, { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) }, { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") }, { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") }, { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") }, { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) }, { COMP_UNSET, NULL, 0 }, }; size_t i; dc = data_config_init(); buffer_copy_string_buffer(dc->key, b); buffer_copy_string_buffer(dc->op, op); buffer_copy_string_buffer(dc->comp_key, yymsp[-5].minor.yy0); buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\"")); buffer_append_string_buffer(dc->comp_key, yymsp[-3].minor.yy43); buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]")); dc->cond = yymsp[-1].minor.yy27; for (i = 0; comps[i].comp_key; i ++) { if (buffer_is_equal_string( dc->comp_key, comps[i].comp_key, comps[i].len)) { dc->comp = comps[i].comp; break; } } if (COMP_UNSET == dc->comp) { fprintf(stderr, "error comp_key %s", dc->comp_key->ptr); ctx->ok = 0; } switch(yymsp[-1].minor.yy27) { case CONFIG_COND_NE: case CONFIG_COND_EQ: dc->string = buffer_init_buffer(rvalue); break; case CONFIG_COND_NOMATCH: case CONFIG_COND_MATCH: { #ifdef HAVE_PCRE_H const char *errptr; int erroff; if (NULL == (dc->regex = pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) { dc->string = buffer_init_string(errptr); dc->cond = CONFIG_COND_UNSET; fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n", rvalue->ptr, errptr, erroff); ctx->ok = 0; } else if (NULL == (dc->regex_study = pcre_study(dc->regex, 0, &errptr)) && errptr != NULL) { fprintf(stderr, "studying regex failed: %s -> %s\n", rvalue->ptr, errptr); ctx->ok = 0; } else { dc->string = buffer_init_buffer(rvalue); } #else fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n" "(perhaps just a missing pcre-devel package ?) \n", yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy43->ptr); ctx->ok = 0; #endif break; } default: fprintf(stderr, "unknown condition for $%s[%s]\n", yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy43->ptr); ctx->ok = 0; break; } configparser_push(ctx, dc, 1); } buffer_free(b); buffer_free(op); buffer_free(yymsp[-5].minor.yy0); yymsp[-5].minor.yy0 = NULL; buffer_free(yymsp[-3].minor.yy43); yymsp[-3].minor.yy43 = NULL; yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } #line 1298 "configparser.c" yy_destructor(16,&yymsp[-6].minor); yy_destructor(18,&yymsp[-4].minor); yy_destructor(19,&yymsp[-2].minor); break; case 33: #line 516 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_EQ; } #line 1308 "configparser.c" yy_destructor(20,&yymsp[0].minor); break; case 34: #line 519 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_MATCH; } #line 1316 "configparser.c" yy_destructor(21,&yymsp[0].minor); break; case 35: #line 522 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_NE; } #line 1324 "configparser.c" yy_destructor(22,&yymsp[0].minor); break; case 36: #line 525 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_NOMATCH; } #line 1332 "configparser.c" yy_destructor(23,&yymsp[0].minor); break; case 37: #line 529 "./configparser.y" { yygotominor.yy43 = NULL; if (ctx->ok) { if (yymsp[0].minor.yy41->type == TYPE_STRING) { yygotominor.yy43 = buffer_init_buffer(((data_string*)yymsp[0].minor.yy41)->value); } else if (yymsp[0].minor.yy41->type == TYPE_INTEGER) { yygotominor.yy43 = buffer_init(); buffer_copy_long(yygotominor.yy43, ((data_integer *)yymsp[0].minor.yy41)->value); } else { fprintf(stderr, "operand must be string"); ctx->ok = 0; } } yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } #line 1353 "configparser.c" break; case 38: #line 546 "./configparser.y" { if (ctx->ok) { if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) { ctx->ok = 0; } buffer_free(yymsp[0].minor.yy43); yymsp[0].minor.yy43 = NULL; } } #line 1366 "configparser.c" yy_destructor(24,&yymsp[-1].minor); break; case 39: #line 556 "./configparser.y" { if (ctx->ok) { if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) { ctx->ok = 0; } buffer_free(yymsp[0].minor.yy43); yymsp[0].minor.yy43 = NULL; } } #line 1380 "configparser.c" yy_destructor(25,&yymsp[-1].minor); break; }; yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yypParser->yyidx -= yysize; yyact = yy_find_reduce_action(yypParser,yygoto); if( yyact < YYNSTATE ){ yy_shift(yypParser,yyact,yygoto,&yygotominor); }else if( yyact == YYNSTATE + YYNRULE + 1 ){ yy_accept(yypParser); } }
static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) { #ifdef HAVE_PCRE_H plugin_data *p = p_data; size_t i; /* * REWRITE URL * * e.g. redirect /base/ to /index.php?section=base * */ mod_redirect_patch_connection(srv, con, p); buffer_copy_string_buffer(p->match_buf, con->request.uri); for (i = 0; i < p->conf.redirect->used; i++) { pcre *match; pcre_extra *extra; const char *pattern; size_t pattern_len; int n; pcre_keyvalue *kv = p->conf.redirect->kv[i]; # define N 10 int ovec[N * 3]; match = kv->key; extra = kv->key_extra; pattern = kv->value->ptr; pattern_len = kv->value->used - 1; if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { log_error_write(srv, __FILE__, __LINE__, "sd", "execution error while matching: ", n); return HANDLER_ERROR; } } else { const char **list; size_t start, end; size_t k; /* it matched */ pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list); /* search for $[0-9] */ buffer_reset(p->location); start = 0; end = pattern_len; for (k = 0; k < pattern_len; k++) { if ((pattern[k] == '$' || pattern[k] == '%') && isdigit((unsigned char)pattern[k + 1])) { /* got one */ size_t num = pattern[k + 1] - '0'; end = k; buffer_append_string_len(p->location, pattern + start, end - start); if (pattern[k] == '$') { /* n is always > 0 */ if (num < (size_t)n) { buffer_append_string(p->location, list[num]); } } else { config_append_cond_match_buffer(con, p->conf.context, p->location, num); } k++; start = k + 1; } } buffer_append_string_len(p->location, pattern + start, pattern_len - start); pcre_free(list); response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location)); con->http_status = 301; con->file_finished = 1; return HANDLER_FINISHED; } } #undef N #else UNUSED(srv); UNUSED(con); UNUSED(p_data); #endif return HANDLER_GO_ON; }
int plugins_load(server *srv) { plugin *p; int (*init)(plugin *pl); const char *error; size_t i, j; for (i = 0; i < srv->srvconf.modules->used; i++) { data_string *d = (data_string *)srv->srvconf.modules->data[i]; char *modules = d->value->ptr; for (j = 0; j < i; j++) { if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "Cannot load plugin", d->value, "more than once, please fix your config (we may not accept such configs in future releases"); continue; } } buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir); buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/")); buffer_append_string(srv->tmp_buf, modules); #if defined(__WIN32) || defined(__CYGWIN__) buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll")); #else buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so")); #endif p = plugin_init(); #ifdef __WIN32 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed", lpMsgBuf, srv->tmp_buf); plugin_free(p); return -1; } #else if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:", srv->tmp_buf, dlerror()); plugin_free(p); return -1; } #endif buffer_reset(srv->tmp_buf); buffer_copy_string(srv->tmp_buf, modules); buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init")); #ifdef __WIN32 init = GetProcAddress(p->lib, srv->tmp_buf->ptr); if (init == NULL) { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf); plugin_free(p); return -1; } #else #if 1 init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr); #else *(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr); #endif if ((error = dlerror()) != NULL) { log_error_write(srv, __FILE__, __LINE__, "s", error); plugin_free(p); return -1; } #endif if ((*init)(p)) { log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" ); plugin_free(p); return -1; } #if 0 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" ); #endif plugins_register(srv, p); } return 0; }
/* * Do the substitutions from ctx->line_in * and output the chain buffers to ctx->out * */ static ngx_int_t ngx_http_subs_match(ngx_http_request_t *r, ngx_http_subs_ctx_t *ctx) { ngx_buf_t *src, *dst, *temp; ngx_log_t *log; ngx_int_t count, match_count; sub_pair_t *pairs, *pair; ngx_uint_t i; count = 0; match_count = 0; log = r->connection->log; src = ctx->line_in; dst = ctx->line_dst; pairs = (sub_pair_t *) ctx->sub_pairs->elts; for (i = 0; i < ctx->sub_pairs->nelts; i++) { pair = &pairs[i]; if (!pair->has_captured) { if (pair->sub.data == NULL) { if (ngx_http_script_run(r, &pair->sub, pair->sub_lengths->elts, 0, pair->sub_values->elts) == NULL) { goto failed; } } } else { pair->sub.data = NULL; pair->sub.len = 0; } /* exchange the src and dst buffer */ if (dst->pos != dst->last) { temp = src; src = dst; dst = temp; ngx_buffer_init(dst); } if ((!pair->regex) && ((ngx_uint_t)(src->last - src->pos) < pair->match.len)) { continue; } if (pair->once && pair->matched) { continue; } if (pair->sub.data == NULL && !pair->has_captured) { if (ngx_http_script_run(r, &pair->sub, pair->sub_lengths->elts, 0, pair->sub_values->elts) == NULL) { goto failed; } } /* regex substitution */ if (pair->regex || pair->insensitive) { count = ngx_http_subs_match_regex_substituion(r, pair, src, dst); if (count == NGX_ERROR) { goto failed; } } else { /* fixed string substituion */ count = ngx_http_subs_match_fix_substituion(r, pair, src, dst); if (count == NGX_ERROR) { goto failed; } } /* no match. */ if (count == 0){ continue; } if (src->pos < src->last) { if (buffer_append_string(dst, src->pos, src->last - src->pos, r->pool) == NULL) { goto failed; } src->pos = src->last; } /* match */ match_count += count; } /* no match last time */ if (dst->pos == dst->last){ dst = src; } if (ngx_http_subs_out_chain_append(r, ctx, dst) != NGX_OK) { goto failed; } ngx_buffer_init(ctx->line_in); ngx_buffer_init(ctx->line_dst); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "match counts: %i", match_count); return match_count; failed: ngx_log_error(NGX_LOG_ERR, log, 0, "[subs_filter] ngx_http_subs_match error."); return -1; }
int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { lua_State *L; int ret = -1; buffer *b; b = buffer_init(); /* push the lua file to the interpreter and see what happends */ L = luaL_newstate(); luaL_openlibs(L); /* register functions */ lua_register(L, "md5", f_crypto_md5); lua_register(L, "file_mtime", f_file_mtime); lua_register(L, "file_isreg", f_file_isreg); lua_register(L, "file_isdir", f_file_isreg); lua_register(L, "dir_files", f_dir_files); #ifdef USE_MEMCACHED lua_pushlightuserdata(L, p->conf.memc); lua_pushcclosure(L, f_memcache_get_long, 1); lua_setglobal(L, "memcache_get_long"); lua_pushlightuserdata(L, p->conf.memc); lua_pushcclosure(L, f_memcache_get_string, 1); lua_setglobal(L, "memcache_get_string"); lua_pushlightuserdata(L, p->conf.memc); lua_pushcclosure(L, f_memcache_exists, 1); lua_setglobal(L, "memcache_exists"); #endif /* register CGI environment */ lua_newtable(L); { int header_tbl = lua_gettop(L); c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)); c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)); c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path)); c_to_lua_push(L, header_tbl, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)); if (!buffer_string_is_empty(con->request.pathinfo)) { c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)); } c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir)); c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl)); } lua_setglobal(L, "request"); /* register GET parameter */ lua_newtable(L); { int get_tbl = lua_gettop(L); buffer_copy_buffer(b, con->uri.query); cache_export_get_params(L, get_tbl, b); buffer_reset(b); } lua_setglobal(L, "get"); /* 2 default constants */ lua_pushinteger(L, 0); lua_setglobal(L, "CACHE_HIT"); lua_pushinteger(L, 1); lua_setglobal(L, "CACHE_MISS"); /* load lua program */ ret = luaL_loadfile(L, fn->ptr); if (0 != ret) { log_error_write(srv, __FILE__, __LINE__, "sbsS", "failed loading cml_lua script", fn, ":", lua_tostring(L, -1)); goto error; } if (lua_pcall(L, 0, 1, 0)) { log_error_write(srv, __FILE__, __LINE__, "sbsS", "failed running cml_lua script", fn, ":", lua_tostring(L, -1)); goto error; } /* get return value */ ret = (int)lua_tointeger(L, -1); lua_pop(L, 1); /* fetch the data from lua */ lua_to_c_get_string(L, "trigger_handler", p->trigger_handler); if (0 == lua_to_c_get_string(L, "output_contenttype", b)) { response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b)); } if (ret == 0) { /* up to now it is a cache-hit, check if all files exist */ int curelem; time_t mtime = 0; if (!lua_to_c_is_table(L, "output_include")) { log_error_write(srv, __FILE__, __LINE__, "s", "output_include is missing or not a table"); ret = -1; goto error; } lua_getglobal(L, "output_include"); curelem = lua_gettop(L); /* HOW-TO build a etag ? * as we don't just have one file we have to take the stat() * from all base files, merge them and build the etag from * it later. * * The mtime of the content is the mtime of the freshest base file * * */ lua_pushnil(L); /* first key */ while (lua_next(L, curelem) != 0) { /* key' is at index -2 and value' at index -1 */ if (lua_isstring(L, -1)) { const char *s = lua_tostring(L, -1); struct stat st; int fd; /* the file is relative, make it absolute */ if (s[0] != '/') { buffer_copy_buffer(b, p->basedir); buffer_append_string(b, lua_tostring(L, -1)); } else { buffer_copy_string(b, lua_tostring(L, -1)); } fd = stat_cache_open_rdonly_fstat(srv, con, b, &st); if (fd < 0) { /* stat failed */ switch(errno) { case ENOENT: /* a file is missing, call the handler to generate it */ if (!buffer_string_is_empty(p->trigger_handler)) { ret = 1; /* cache-miss */ log_error_write(srv, __FILE__, __LINE__, "s", "a file is missing, calling handler"); break; } else { /* handler not set -> 500 */ ret = -1; log_error_write(srv, __FILE__, __LINE__, "s", "a file missing and no handler set"); break; } break; default: break; } } else { chunkqueue_append_file_fd(con->write_queue, b, fd, 0, st.st_size); if (st.st_mtime > mtime) mtime = st.st_mtime; } } else { /* not a string */ ret = -1; log_error_write(srv, __FILE__, __LINE__, "s", "not a string"); break; } lua_pop(L, 1); /* removes value'; keeps key' for next iteration */ } lua_settop(L, curelem - 1); if (ret == 0) { data_string *ds; char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")]; con->file_finished = 1; ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"); if (0 == mtime) mtime = time(NULL); /* default last-modified to now */ /* no Last-Modified specified */ if (NULL == ds) { strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime)); response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1); ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"); force_assert(NULL != ds); } if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, ds->value)) { /* ok, the client already has our content, * no need to send it again */ chunkqueue_reset(con->write_queue); ret = 0; /* cache-hit */ } } else { chunkqueue_reset(con->write_queue); } } if (ret == 1 && !buffer_string_is_empty(p->trigger_handler)) { /* cache-miss */ buffer_copy_buffer(con->uri.path, p->baseurl); buffer_append_string_buffer(con->uri.path, p->trigger_handler); buffer_copy_buffer(con->physical.path, p->basedir); buffer_append_string_buffer(con->physical.path, p->trigger_handler); chunkqueue_reset(con->write_queue); } error: lua_close(L); buffer_free(b); return ret /* cache-error */; }
static int http_list_directory(server *srv, connection *con, plugin_data *p, buffer *dir) { DIR *dp; buffer *out; struct dirent *dent; struct stat st; char *path, *path_file; size_t i; int hide_dotfiles = p->conf.hide_dot_files; dirls_list_t dirs, files, *list; dirls_entry_t *tmp; char sizebuf[sizeof("999.9K")]; char datebuf[sizeof("2005-Jan-01 22:23:24")]; size_t k; const char *content_type; long name_max; #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) char attrval[128]; int attrlen; #endif #ifdef HAVE_LOCALTIME_R struct tm tm; #endif if (buffer_string_is_empty(dir)) return -1; i = buffer_string_length(dir); #ifdef HAVE_PATHCONF if (0 >= (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) { /* some broken fs (fuse) return 0 instead of -1 */ #ifdef NAME_MAX name_max = NAME_MAX; #else name_max = 255; /* stupid default */ #endif } #elif defined __WIN32 name_max = FILENAME_MAX; #else name_max = NAME_MAX; #endif path = malloc(i + name_max + 1); force_assert(NULL != path); memcpy(path, dir->ptr, i+1); path_file = path + i; if (NULL == (dp = opendir(path))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "opendir failed:", dir, strerror(errno)); free(path); return -1; } dirs.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE); force_assert(dirs.ent); dirs.size = DIRLIST_BLOB_SIZE; dirs.used = 0; files.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE); force_assert(files.ent); files.size = DIRLIST_BLOB_SIZE; files.used = 0; while ((dent = readdir(dp)) != NULL) { unsigned short exclude_match = 0; if (dent->d_name[0] == '.') { if (hide_dotfiles) continue; if (dent->d_name[1] == '\0') continue; if (dent->d_name[1] == '.' && dent->d_name[2] == '\0') continue; } if (p->conf.hide_readme_file && !buffer_string_is_empty(p->conf.show_readme)) { if (strcmp(dent->d_name, p->conf.show_readme->ptr) == 0) continue; } if (p->conf.hide_header_file && !buffer_string_is_empty(p->conf.show_header)) { if (strcmp(dent->d_name, p->conf.show_header->ptr) == 0) continue; } /* compare d_name against excludes array * elements, skipping any that match. */ #ifdef HAVE_PCRE_H for(i = 0; i < p->conf.excludes->used; i++) { int n; #define N 10 int ovec[N * 3]; pcre *regex = p->conf.excludes->ptr[i]->regex; if ((n = pcre_exec(regex, NULL, dent->d_name, strlen(dent->d_name), 0, 0, ovec, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { log_error_write(srv, __FILE__, __LINE__, "sd", "execution error while matching:", n); /* aborting would require a lot of manual cleanup here. * skip instead (to not leak names that break pcre matching) */ exclude_match = 1; break; } } else { exclude_match = 1; break; } } if (exclude_match) { continue; } #endif i = strlen(dent->d_name); /* NOTE: the manual says, d_name is never more than NAME_MAX * so this should actually not be a buffer-overflow-risk */ if (i > (size_t)name_max) continue; memcpy(path_file, dent->d_name, i + 1); if (stat(path, &st) != 0) continue; list = &files; if (S_ISDIR(st.st_mode)) list = &dirs; if (list->used == list->size) { list->size += DIRLIST_BLOB_SIZE; list->ent = (dirls_entry_t**) realloc(list->ent, sizeof(dirls_entry_t*) * list->size); force_assert(list->ent); } tmp = (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + i); tmp->mtime = st.st_mtime; tmp->size = st.st_size; tmp->namelen = i; memcpy(DIRLIST_ENT_NAME(tmp), dent->d_name, i + 1); list->ent[list->used++] = tmp; } closedir(dp); if (dirs.used) http_dirls_sort(dirs.ent, dirs.used); if (files.used) http_dirls_sort(files.ent, files.used); out = buffer_init(); http_list_directory_header(srv, con, p, out); /* directories */ for (i = 0; i < dirs.used; i++) { tmp = dirs.ent[i]; #ifdef HAVE_LOCALTIME_R localtime_r(&(tmp->mtime), &tm); strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm); #else strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime))); #endif buffer_append_string_len(out, CONST_STR_LEN("<tr class=\"d\"><td class=\"n\"><a href=\"")); buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART); buffer_append_string_len(out, CONST_STR_LEN("/\">")); buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("</a>/</td><td class=\"m\">")); buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1); buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"s\">- </td><td class=\"t\">Directory</td></tr>\n")); free(tmp); } /* files */ for (i = 0; i < files.used; i++) { tmp = files.ent[i]; content_type = NULL; #if defined(HAVE_XATTR) if (con->conf.use_xattr) { memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1); attrlen = sizeof(attrval) - 1; if (attr_get(path, srv->srvconf.xattr_name->ptr, attrval, &attrlen, 0) == 0) { attrval[attrlen] = '\0'; content_type = attrval; } } #elif defined(HAVE_EXTATTR) if (con->conf.use_xattr) { memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1); if(-1 != (attrlen = extattr_get_file(path, EXTATTR_NAMESPACE_USER, srv->srvconf.xattr_name->ptr, attrval, sizeof(attrval)-1))) { attrval[attrlen] = '\0'; content_type = attrval; } } #endif if (content_type == NULL) { content_type = "application/octet-stream"; for (k = 0; k < con->conf.mimetypes->used; k++) { data_string *ds = (data_string *)con->conf.mimetypes->data[k]; size_t ct_len; if (buffer_is_empty(ds->key)) continue; ct_len = buffer_string_length(ds->key); if (tmp->namelen < ct_len) continue; if (0 == strncasecmp(DIRLIST_ENT_NAME(tmp) + tmp->namelen - ct_len, ds->key->ptr, ct_len)) { content_type = ds->value->ptr; break; } } } #ifdef HAVE_LOCALTIME_R localtime_r(&(tmp->mtime), &tm); strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm); #else strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime))); #endif http_list_directory_sizefmt(sizebuf, sizeof(sizebuf), tmp->size); buffer_append_string_len(out, CONST_STR_LEN("<tr><td class=\"n\"><a href=\"")); buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART); buffer_append_string_len(out, CONST_STR_LEN("\">")); buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("</a></td><td class=\"m\">")); buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1); buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"s\">")); buffer_append_string(out, sizebuf); buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"t\">")); buffer_append_string(out, content_type); buffer_append_string_len(out, CONST_STR_LEN("</td></tr>\n")); free(tmp); } free(files.ent); free(dirs.ent); free(path); http_list_directory_footer(srv, con, p, out); /* Insert possible charset to Content-Type */ if (buffer_string_is_empty(p->conf.encoding)) { response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); } else { buffer_copy_string_len(p->content_charset, CONST_STR_LEN("text/html; charset=")); buffer_append_string_buffer(p->content_charset, p->conf.encoding); response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset)); } con->file_finished = 1; chunkqueue_append_buffer(con->write_queue, out); buffer_free(out); return 0; }
static ngx_int_t ngx_http_subs_match_regex_substituion(ngx_http_request_t *r, sub_pair_t *pair, ngx_buf_t *b, ngx_buf_t *dst) { ngx_str_t line; ngx_log_t *log; ngx_int_t rc, count = 0; log = r->connection->log; if (pair->captures == NULL || pair->ncaptures == 0) { pair->ncaptures = (NGX_HTTP_MAX_CAPTURES + 1) * 3; pair->captures = ngx_palloc(r->pool, pair->ncaptures * sizeof(int)); if (pair->captures == NULL) { return NGX_ERROR; } } while (b->pos < b->last) { if (pair->once && pair->matched) { break; } line.data = b->pos; line.len = b->last - b->pos; rc = ngx_regex_exec(pair->match_regex, &line, (int *) pair->captures, pair->ncaptures); if (rc == NGX_REGEX_NO_MATCHED) { break; } else if(rc < 0) { ngx_log_error(NGX_LOG_ERR, log, 0, ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", rc, &line, &pair->match); return NGX_ERROR; } pair->matched++; count++; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, log, 0, "regex match:%i, start:%d, end:%d ", rc, pair->captures[0], pair->captures[1]); if (pair->has_captured) { r->captures = pair->captures; r->ncaptures = pair->ncaptures; r->captures_data = line.data; if (ngx_http_script_run(r, &pair->sub, pair->sub_lengths->elts, 0, pair->sub_values->elts) == NULL) { ngx_log_error(NGX_LOG_ALERT, log, 0, "[subs_filter] ngx_http_script_run error."); return NGX_ERROR; } } if (buffer_append_string(dst, b->pos, pair->captures[0], r->pool) == NULL) { return NGX_ERROR; } if (buffer_append_string(dst, pair->sub.data, pair->sub.len, r->pool) == NULL) { return NGX_ERROR; } b->pos = b->pos + pair->captures[1]; } return count; }
static handler_t mod_status_handle_server_status_html(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; buffer *b; size_t j; double avg; char multiplier = '\0'; char buf[32]; time_t ts; int days, hours, mins, seconds; b = chunkqueue_get_append_buffer(con->write_queue); BUFFER_COPY_STRING_CONST(b, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" " <head>\n" " <title>Status</title>\n"); BUFFER_APPEND_STRING_CONST(b, " <style type=\"text/css\">\n" " table.status { border: black solid thin; }\n" " td.int { background-color: #f0f0f0; text-align: right }\n" " td.string { background-color: #f0f0f0; text-align: left }\n" " th.status { background-color: black; color: white; font-weight: bold; }\n" " a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n" " span.sortarrow { color: white; text-decoration: none; }\n" " </style>\n"); if (p->conf.sort) { BUFFER_APPEND_STRING_CONST(b, "<script type=\"text/javascript\">\n" "// <!--\n" "var sort_column;\n" "var prev_span = null;\n"); BUFFER_APPEND_STRING_CONST(b, "function get_inner_text(el) {\n" " if((typeof el == 'string')||(typeof el == 'undefined'))\n" " return el;\n" " if(el.innerText)\n" " return el.innerText;\n" " else {\n" " var str = \"\";\n" " var cs = el.childNodes;\n" " var l = cs.length;\n" " for (i=0;i<l;i++) {\n" " if (cs[i].nodeType==1) str += get_inner_text(cs[i]);\n" " else if (cs[i].nodeType==3) str += cs[i].nodeValue;\n" " }\n" " }\n" " return str;\n" "}\n"); BUFFER_APPEND_STRING_CONST(b, "function sortfn(a,b) {\n" " var at = get_inner_text(a.cells[sort_column]);\n" " var bt = get_inner_text(b.cells[sort_column]);\n" " if (a.cells[sort_column].className == 'int') {\n" " return parseInt(at)-parseInt(bt);\n" " } else {\n" " aa = at.toLowerCase();\n" " bb = bt.toLowerCase();\n" " if (aa==bb) return 0;\n" " else if (aa<bb) return -1;\n" " else return 1;\n" " }\n" "}\n"); BUFFER_APPEND_STRING_CONST(b, "function resort(lnk) {\n" " var span = lnk.childNodes[1];\n" " var table = lnk.parentNode.parentNode.parentNode.parentNode;\n" " var rows = new Array();\n" " for (j=1;j<table.rows.length;j++)\n" " rows[j-1] = table.rows[j];\n" " sort_column = lnk.parentNode.cellIndex;\n" " rows.sort(sortfn);\n"); BUFFER_APPEND_STRING_CONST(b, " if (prev_span != null) prev_span.innerHTML = '';\n" " if (span.getAttribute('sortdir')=='down') {\n" " span.innerHTML = '↑';\n" " span.setAttribute('sortdir','up');\n" " rows.reverse();\n" " } else {\n" " span.innerHTML = '↓';\n" " span.setAttribute('sortdir','down');\n" " }\n" " for (i=0;i<rows.length;i++)\n" " table.tBodies[0].appendChild(rows[i]);\n" " prev_span = span;\n" "}\n" "// -->\n" "</script>\n"); } BUFFER_APPEND_STRING_CONST(b, " </head>\n" " <body>\n"); /* connection listing */ BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>"); BUFFER_APPEND_STRING_CONST(b, "<table summary=\"status\" class=\"status\">"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">"); buffer_append_string_buffer(b, con->uri.authority); BUFFER_APPEND_STRING_CONST(b, " ("); buffer_append_string_buffer(b, con->server_name); BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">"); ts = srv->cur_ts - srv->startup_ts; days = ts / (60 * 60 * 24); ts %= (60 * 60 * 24); hours = ts / (60 * 60); ts %= (60 * 60); mins = ts / (60); ts %= (60); seconds = ts; if (days) { buffer_append_long(b, days); BUFFER_APPEND_STRING_CONST(b, " days "); } if (hours) { buffer_append_long(b, hours); BUFFER_APPEND_STRING_CONST(b, " hours "); } if (mins) { buffer_append_long(b, mins); BUFFER_APPEND_STRING_CONST(b, " min "); } buffer_append_long(b, seconds); BUFFER_APPEND_STRING_CONST(b, " s"); BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">"); ts = srv->startup_ts; strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts)); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); avg = p->abs_requests; mod_status_get_multiplier(&avg, &multiplier, 1000); buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); avg = p->abs_traffic_out; mod_status_get_multiplier(&avg, &multiplier, 1024); sprintf(buf, "%.2f", avg); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); avg = p->abs_requests / (srv->cur_ts - srv->startup_ts); mod_status_get_multiplier(&avg, &multiplier, 1000); buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts); mod_status_get_multiplier(&avg, &multiplier, 1024); sprintf(buf, "%.2f", avg); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n"); for (j = 0, avg = 0; j < 5; j++) { avg += p->mod_5s_requests[j]; } avg /= 5; BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); mod_status_get_multiplier(&avg, &multiplier, 1000); buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n"); for (j = 0, avg = 0; j < 5; j++) { avg += p->mod_5s_traffic_out[j]; } avg /= 5; BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); mod_status_get_multiplier(&avg, &multiplier, 1024); sprintf(buf, "%.2f", avg); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "</table>\n"); BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n"); BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n"); BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n"); BUFFER_APPEND_STRING_CONST(b, "q = request-start, Q = request-end\n"); BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n"); BUFFER_APPEND_STRING_CONST(b, "<b>"); buffer_append_long(b, srv->conns->used); BUFFER_APPEND_STRING_CONST(b, " connections</b>\n"); for (j = 0; j < srv->conns->used; j++) { connection *c = srv->conns->ptr[j]; const char *state = connection_get_short_state(c->state); buffer_append_string_len(b, state, 1); if (((j + 1) % 50) == 0) { BUFFER_APPEND_STRING_CONST(b, "\n"); } } BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n"); BUFFER_APPEND_STRING_CONST(b, "<table summary=\"status\" class=\"status\">\n"); BUFFER_APPEND_STRING_CONST(b, "<tr>"); mod_status_header_append_sort(b, p_d, "Client IP"); mod_status_header_append_sort(b, p_d, "Read"); mod_status_header_append_sort(b, p_d, "Written"); mod_status_header_append_sort(b, p_d, "State"); mod_status_header_append_sort(b, p_d, "Time"); mod_status_header_append_sort(b, p_d, "Host"); mod_status_header_append_sort(b, p_d, "URI"); mod_status_header_append_sort(b, p_d, "File"); BUFFER_APPEND_STRING_CONST(b, "</tr>\n"); for (j = 0; j < srv->conns->used; j++) { connection *c = srv->conns->ptr[j]; BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">"); buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr))); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); if (con->request.content_length) { buffer_append_long(b, c->request_content_queue->bytes_in); BUFFER_APPEND_STRING_CONST(b, "/"); buffer_append_long(b, c->request.content_length); } else { BUFFER_APPEND_STRING_CONST(b, "0/0"); } BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); buffer_append_off_t(b, chunkqueue_written(c->write_queue)); BUFFER_APPEND_STRING_CONST(b, "/"); buffer_append_off_t(b, chunkqueue_length(c->write_queue)); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); buffer_append_string(b, connection_get_state(c->state)); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); buffer_append_long(b, srv->cur_ts - c->request_start); BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); if (buffer_is_empty(c->server_name)) { buffer_append_string_buffer(b, c->uri.authority); } else { buffer_append_string_buffer(b, c->server_name); } BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); if (!buffer_is_empty(c->uri.path)) { buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML); } BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); buffer_append_string_buffer(b, c->physical.path); BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); } BUFFER_APPEND_STRING_CONST(b, "</table>\n"); BUFFER_APPEND_STRING_CONST(b, " </body>\n" "</html>\n" ); response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); return 0; }
static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) { size_t k; int auth_required = 0, auth_satisfied = 0; char *http_authorization = NULL; data_string *ds; mod_auth_plugin_data *p = p_d; array *req; /* select the right config */ mod_auth_patch_connection(srv, con, p); if (p->conf.auth_require == NULL) return HANDLER_GO_ON; /* * AUTH * */ /* do we have to ask for auth ? */ auth_required = 0; auth_satisfied = 0; /* search auth-directives for path */ for (k = 0; k < p->conf.auth_require->used; k++) { buffer *require = p->conf.auth_require->data[k]->key; if (require->used == 0) continue; if (con->uri.path->used < require->used) continue; /* if we have a case-insensitive FS we have to lower-case the URI here too */ if (con->conf.force_lowercase_filenames) { if (0 == strncasecmp(con->uri.path->ptr, require->ptr, require->used - 1)) { auth_required = 1; break; } } else { if (0 == strncmp(con->uri.path->ptr, require->ptr, require->used - 1)) { auth_required = 1; break; } } } /* nothing to do for us */ if (auth_required == 0) return HANDLER_GO_ON; req = ((data_array *)(p->conf.auth_require->data[k]))->value; /* try to get Authorization-header */ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) { http_authorization = ds->value->ptr; } if (ds && ds->value && ds->value->used) { char *auth_realm; data_string *method; method = (data_string *)array_get_element(req, "method"); /* parse auth-header */ if (NULL != (auth_realm = strchr(http_authorization, ' '))) { int auth_type_len = auth_realm - http_authorization; if ((auth_type_len == 5) && (0 == strncasecmp(http_authorization, "Basic", auth_type_len))) { if (0 == strcmp(method->value->ptr, "basic")) { auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1); } } else if ((auth_type_len == 6) && (0 == strncasecmp(http_authorization, "Digest", auth_type_len))) { if (0 == strcmp(method->value->ptr, "digest")) { if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) { con->http_status = 400; con->mode = DIRECT; /* a field was missing */ return HANDLER_FINISHED; } } } else { log_error_write(srv, __FILE__, __LINE__, "ss", "unknown authentification type:", http_authorization); } } } if (!auth_satisfied) { data_string *method, *realm; method = (data_string *)array_get_element(req, "method"); realm = (data_string *)array_get_element(req, "realm"); con->http_status = 401; con->mode = DIRECT; if (0 == strcmp(method->value->ptr, "basic")) { buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("Basic realm=\"")); buffer_append_string_buffer(p->tmp_buf, realm->value); buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\"")); response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf)); } else if (0 == strcmp(method->value->ptr, "digest")) { char hh[33]; http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh); buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("Digest realm=\"")); buffer_append_string_buffer(p->tmp_buf, realm->value); buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\", nonce=\"")); buffer_append_string(p->tmp_buf, hh); buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\", qop=\"auth\"")); response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf)); } else { /* evil */ } return HANDLER_FINISHED; } else { /* the REMOTE_USER header */ buffer_copy_string_buffer(con->authed_user, p->auth_user); } return HANDLER_GO_ON; }
/** * 输出日志. * 日志的格式: * 2009-11-25 22:31:25: (filename.line) information * * 参数fmt的说明如下: * 's':字符串 'b':buffer 'd':int 'o':off_t 'x':int的十六进制 * 上面的几个参数,在输出相应的值后都追加一个空格' '。 * 如果参数为大写,则不追加空格。 * */ int log_error_write(server * srv, const char *filename, unsigned int line, const char *fmt, ...) { pthread_mutex_lock(&srv -> log_lock); va_list ap; switch (srv->errorlog_mode) { case ERRORLOG_FILE: case ERRORLOG_STDERR: /* * 日志文件和标准错误输出要设定日志的时间。 */ if (srv->cur_ts != srv->last_generated_debug_ts) { buffer_prepare_copy(srv->ts_debug_str, 1024); strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts))); srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1; srv->last_generated_debug_ts = srv->cur_ts; } buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str); buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(": (")); break; case ERRORLOG_SYSLOG: /* * syslog自己产生时间 */ buffer_copy_string_len(srv->errorlog_buf, CONST_STR_LEN("(")); break; } buffer_append_string(srv->errorlog_buf, filename); buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(".")); buffer_append_long(srv->errorlog_buf, line); buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(") ")); //根据字符串fmt来遍历可变参数。 for (va_start(ap, fmt); *fmt; fmt++) { int d; char *s; buffer *b; off_t o; switch (*fmt) { case 's': /* string */ s = va_arg(ap, char *); buffer_append_string(srv->errorlog_buf, s); buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" ")); break; case 'b': /* buffer */ b = va_arg(ap, buffer *); buffer_append_string_buffer(srv->errorlog_buf, b); buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" ")); break; case 'd': /* int */ d = va_arg(ap, int); buffer_append_long(srv->errorlog_buf, d); buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" ")); break; case 'o': /* off_t */ o = va_arg(ap, off_t); buffer_append_off_t(srv->errorlog_buf, o); buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" ")); break; case 'x': /* int (hex) */ d = va_arg(ap, int); buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("0x")); buffer_append_long_hex(srv->errorlog_buf, d); buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" ")); break; case 'S': /* string */ s = va_arg(ap, char *); buffer_append_string(srv->errorlog_buf, s); break; case 'B': /* buffer */ b = va_arg(ap, buffer *); buffer_append_string_buffer(srv->errorlog_buf, b); break; case 'D': /* int */ d = va_arg(ap, int); buffer_append_long(srv->errorlog_buf, d); break; case 'O': /* off_t */ o = va_arg(ap, off_t); buffer_append_off_t(srv->errorlog_buf, o); break; case 'X': /* int (hex) */ d = va_arg(ap, int); buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("0x")); buffer_append_long_hex(srv->errorlog_buf, d); break; case '(': case ')': case '<': case '>': case ',': case ' ': buffer_append_string_len(srv->errorlog_buf, fmt, 1); break; } } va_end(ap); switch (srv->errorlog_mode) { case ERRORLOG_FILE: buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("\n")); write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1); break; case ERRORLOG_STDERR: buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("\n")); write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1); break; case ERRORLOG_SYSLOG: syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr); break; } pthread_mutex_unlock(&srv -> log_lock); return 0; }