예제 #1
0
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;
}
예제 #2
0
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;
}