static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; size_t s_len; unsigned long last_max = ULONG_MAX; int max_usage = INT_MAX; int ndx = -1; size_t k; buffer *fn; data_array *extension = NULL; size_t path_info_offset; if (con->mode != DIRECT) return HANDLER_GO_ON; /* Possibly, we processed already this request */ if (con->file_started == 1) return HANDLER_GO_ON; mod_proxy_patch_connection(srv, con, p); fn = con->uri.path; if (fn->used == 0) { return HANDLER_ERROR; } s_len = fn->used - 1; path_info_offset = 0; if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "proxy - start"); } /* check if extension matches */ for (k = 0; k < p->conf.extensions->used; k++) { data_array *ext = NULL; size_t ct_len; ext = (data_array *)p->conf.extensions->data[k]; if (ext->key->used == 0) continue; ct_len = ext->key->used - 1; if (s_len < ct_len) continue; /* check extension in the form "/proxy_pattern" */ if (*(ext->key->ptr) == '/') { if (strncmp(fn->ptr, ext->key->ptr, ct_len) == 0) { if (s_len > ct_len + 1) { char *pi_offset; if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) { path_info_offset = pi_offset - fn->ptr; } } extension = ext; break; } } else if (0 == strncmp(fn->ptr + s_len - ct_len, ext->key->ptr, ct_len)) { /* check extension in the form ".fcg" */ extension = ext; break; } } if (NULL == extension) { return HANDLER_GO_ON; } if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "proxy - ext found"); } if (extension->value->used == 1) { if ( ((data_proxy *)extension->value->data[0])->is_disabled ) { ndx = -1; } else { ndx = 0; } } else if (extension->value->used != 0) switch(p->conf.balance) { case PROXY_BALANCE_HASH: /* hash balancing */ if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sd", "proxy - used hash balancing, hosts:", extension->value->used); } for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) { data_proxy *host = (data_proxy *)extension->value->data[k]; unsigned long cur_max; if (host->is_disabled) continue; cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) + generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */ generate_crc32c(CONST_BUF_LEN(con->uri.authority)); if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sbbbd", "proxy - election:", con->uri.path, host->host, con->uri.authority, cur_max); } if ((last_max == ULONG_MAX) || /* first round */ (cur_max > last_max)) { last_max = cur_max; ndx = k; } } break; case PROXY_BALANCE_FAIR: /* fair balancing */ if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "proxy - used fair balancing"); } for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) { data_proxy *host = (data_proxy *)extension->value->data[k]; if (host->is_disabled) continue; if (host->usage < max_usage) { max_usage = host->usage; ndx = k; } } break; case PROXY_BALANCE_RR: { data_proxy *host; /* round robin */ if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "proxy - used round-robin balancing"); } /* just to be sure */ assert(extension->value->used < INT_MAX); host = (data_proxy *)extension->value->data[0]; /* Use last_used_ndx from first host in list */ k = host->last_used_ndx; ndx = k + 1; /* use next host after the last one */ if (ndx < 0) ndx = 0; /* Search first active host after last_used_ndx */ while ( ndx < (int) extension->value->used && (host = (data_proxy *)extension->value->data[ndx])->is_disabled ) ndx++; if (ndx >= (int) extension->value->used) { /* didn't found a higher id, wrap to the start */ for (ndx = 0; ndx <= (int) k; ndx++) { host = (data_proxy *)extension->value->data[ndx]; if (!host->is_disabled) break; } /* No active host found */ if (host->is_disabled) ndx = -1; } /* Save new index for next round */ ((data_proxy *)extension->value->data[0])->last_used_ndx = ndx; break; } default: break; } /* found a server */ if (ndx != -1) { data_proxy *host = (data_proxy *)extension->value->data[ndx]; /* * if check-local is disabled, use the uri.path handler * */ /* init handler-context */ handler_ctx *hctx; hctx = handler_ctx_init(); hctx->path_info_offset = path_info_offset; hctx->remote_conn = con; hctx->plugin_data = p; hctx->host = host; con->plugin_ctx[p->id] = hctx; host->usage++; con->mode = p->id; if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sbd", "proxy - found a host", host->host, host->port); } return HANDLER_GO_ON; } else { /* no handler found */ con->http_status = 500; log_error_write(srv, __FILE__, __LINE__, "sb", "no proxy-handler found for:", fn); return HANDLER_FINISHED; } return HANDLER_GO_ON; }
static handler_t process_rewrite_rules(server *srv, connection *con, plugin_data *p, pcre_keyvalue_buffer *kvb, int repeat_idx) { handler_ctx *hctx; struct burl_parts_t burl; pcre_keyvalue_ctx ctx; handler_t rc; if (con->plugin_ctx[p->id]) { hctx = con->plugin_ctx[p->id]; if (hctx->loops++ > 100) { data_config *dc = p->conf.context; if (NULL == dc) { log_error_write(srv, __FILE__, __LINE__, "s", "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request"); return HANDLER_ERROR; } log_error_write(srv, __FILE__, __LINE__, "SbbSBS", "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat ($", dc->comp_key, dc->op, "\"", dc->string, "\")"); return HANDLER_ERROR; } if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON; } ctx.cache = p->conf.context ? &con->cond_cache[p->conf.context->context_ndx] : NULL; ctx.burl = &burl; burl.scheme = con->uri.scheme; burl.authority = con->uri.authority; burl.port = sock_addr_get_port(&con->srv_socket->addr); burl.path = con->uri.path_raw; burl.query = con->uri.query; if (buffer_string_is_empty(burl.authority)) burl.authority = con->server_name; rc = pcre_keyvalue_buffer_process(kvb, &ctx, con->request.uri, srv->tmp_buf); if (HANDLER_FINISHED == rc && !buffer_is_empty(srv->tmp_buf) && srv->tmp_buf->ptr[0] == '/') { buffer_copy_buffer(con->request.uri, srv->tmp_buf); if (con->plugin_ctx[p->id] == NULL) { hctx = handler_ctx_init(); con->plugin_ctx[p->id] = hctx; } else { hctx = con->plugin_ctx[p->id]; } if (ctx.m < repeat_idx) hctx->state = REWRITE_STATE_FINISHED; buffer_reset(con->physical.path); rc = HANDLER_COMEBACK; } else if (HANDLER_FINISHED == rc) { rc = HANDLER_ERROR; log_error_write(srv, __FILE__, __LINE__, "sb", "mod_rewrite invalid result (not beginning with '/') while processing uri:", con->request.uri); } else if (HANDLER_ERROR == rc) { log_error_write(srv, __FILE__, __LINE__, "sb", "pcre_exec() error while processing uri:", con->request.uri); } return rc; }