コード例 #1
0
ファイル: mod_proxy.c プロジェクト: angad/lighttpd-android
static handler_t proxy_write_request(server *srv, handler_ctx *hctx) {
	data_proxy *host= hctx->host;
	connection *con   = hctx->remote_conn;

	int ret;

	if (!host ||
	    (!host->host->used || !host->port)) return -1;

	switch(hctx->state) {
	case PROXY_STATE_CONNECT:
		/* wait for the connect() to finish */

		/* connect failed ? */
		if (-1 == hctx->fde_ndx) return HANDLER_ERROR;

		/* wait */
		return HANDLER_WAIT_FOR_EVENT;

		break;

	case PROXY_STATE_INIT:
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
		if (strstr(host->host->ptr,":")) {
		    if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
			return HANDLER_ERROR;
		    }
		} else
#endif
		{
		    if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
			return HANDLER_ERROR;
		    }
		}
		hctx->fde_ndx = -1;

		srv->cur_fds++;

		fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);

		if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));

			return HANDLER_ERROR;
		}

		switch (proxy_establish_connection(srv, hctx)) {
		case 1:
			proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);

			/* connection is in progress, wait for an event and call getsockopt() below */

			fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);

			return HANDLER_WAIT_FOR_EVENT;
		case -1:
			/* if ECONNREFUSED choose another connection -> FIXME */
			hctx->fde_ndx = -1;

			return HANDLER_ERROR;
		default:
			/* everything is ok, go on */
			proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
			break;
		}

		/* fall through */

	case PROXY_STATE_PREPARE_WRITE:
		proxy_create_env(srv, hctx);

		proxy_set_state(srv, hctx, PROXY_STATE_WRITE);

		/* fall through */
	case PROXY_STATE_WRITE:;
		ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb, MAX_WRITE_LIMIT);

		chunkqueue_remove_finished_chunks(hctx->wb);

		if (-1 == ret) { /* error on our side */
			log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);

			return HANDLER_ERROR;
		} else if (-2 == ret) { /* remote close */
			log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed, remote connection close:", strerror(errno), errno);

			return HANDLER_ERROR;
		}

		if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
			proxy_set_state(srv, hctx, PROXY_STATE_READ);

			fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
			fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
		} else {
			fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);

			return HANDLER_WAIT_FOR_EVENT;
		}

		return HANDLER_WAIT_FOR_EVENT;
	case PROXY_STATE_READ:
		/* waiting for a response */
		return HANDLER_WAIT_FOR_EVENT;
	default:
		log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
		return HANDLER_ERROR;
	}

	return HANDLER_GO_ON;
}
コード例 #2
0
ファイル: mod_proxy.c プロジェクト: angad/lighttpd-android
static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) {
	handler_ctx *hctx = ctx;
	connection  *con  = hctx->remote_conn;
	plugin_data *p    = hctx->plugin_data;


	if ((revents & FDEVENT_IN) &&
	    hctx->state == PROXY_STATE_READ) {

		if (p->conf.debug) {
			log_error_write(srv, __FILE__, __LINE__, "sd",
					"proxy: fdevent-in", hctx->state);
		}

		switch (proxy_demux_response(srv, hctx)) {
		case 0:
			break;
		case 1:
			/* we are done */
			proxy_connection_close(srv, hctx);

			joblist_append(srv, con);
			return HANDLER_FINISHED;
		case -1:
			if (con->file_started == 0) {
				/* nothing has been send out yet, send a 500 */
				connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
				con->http_status = 500;
				con->mode = DIRECT;
			} else {
				/* response might have been already started, kill the connection */
				connection_set_state(srv, con, CON_STATE_ERROR);
			}

			joblist_append(srv, con);
			return HANDLER_FINISHED;
		}
	}

	if (revents & FDEVENT_OUT) {
		if (p->conf.debug) {
			log_error_write(srv, __FILE__, __LINE__, "sd",
					"proxy: fdevent-out", hctx->state);
		}

		if (hctx->state == PROXY_STATE_CONNECT) {
			int socket_error;
			socklen_t socket_error_len = sizeof(socket_error);

			/* we don't need it anymore */
			fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
			hctx->fde_ndx = -1;

			/* try to finish the connect() */
			if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
				log_error_write(srv, __FILE__, __LINE__, "ss",
					"getsockopt failed:", strerror(errno));

				joblist_append(srv, con);
				return HANDLER_FINISHED;
			}
			if (socket_error != 0) {
				log_error_write(srv, __FILE__, __LINE__, "ss",
					"establishing connection failed:", strerror(socket_error),
					"port:", hctx->host->port);

				joblist_append(srv, con);
				return HANDLER_FINISHED;
			}
			if (p->conf.debug) {
				log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success");
			}

			proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
		}

		if (hctx->state == PROXY_STATE_PREPARE_WRITE ||
		    hctx->state == PROXY_STATE_WRITE) {
			/* we are allowed to send something out
			 *
			 * 1. after a just finished connect() call
			 * 2. in a unfinished write() call (long POST request)
			 */
			return mod_proxy_handle_subrequest(srv, con, p);
		} else {
			log_error_write(srv, __FILE__, __LINE__, "sd",
					"proxy: out", hctx->state);
		}
	}

	/* perhaps this issue is already handled */
	if (revents & FDEVENT_HUP) {
		if (p->conf.debug) {
			log_error_write(srv, __FILE__, __LINE__, "sd",
					"proxy: fdevent-hup", hctx->state);
		}

		if (hctx->state == PROXY_STATE_CONNECT) {
			/* connect() -> EINPROGRESS -> HUP */

			/**
			 * what is proxy is doing if it can't reach the next hop ?
			 *
			 */

			if (hctx->host) {
				hctx->host->is_disabled = 1;
				hctx->host->disable_ts = srv->cur_ts;
				log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:",
						hctx->host->host,
						hctx->host->port,
						hctx->fd);

				/* disable this server */
				hctx->host->is_disabled = 1;
				hctx->host->disable_ts = srv->cur_ts;

				proxy_connection_close(srv, hctx);

				/* reset the enviroment and restart the sub-request */
				buffer_reset(con->physical.path);
				con->mode = DIRECT;

				joblist_append(srv, con);
			} else {
				proxy_connection_close(srv, hctx);
				joblist_append(srv, con);

				con->mode = DIRECT;
				con->http_status = 503;
			}

			return HANDLER_FINISHED;
		}

		if (!con->file_finished) {
			http_chunk_append_mem(srv, con, NULL, 0);
		}

		con->file_finished = 1;
		proxy_connection_close(srv, hctx);
		joblist_append(srv, con);
	} else if (revents & FDEVENT_ERR) {
		/* kill all connections to the proxy process */

		log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);

		con->file_finished = 1;
		joblist_append(srv, con);
		proxy_connection_close(srv, hctx);
	}

	return HANDLER_FINISHED;
}
コード例 #3
0
ファイル: mod_proxy.c プロジェクト: chandantr/lighty2
static handler_t proxy_write_request(server *srv, handler_ctx *hctx) {
	data_proxy *host= hctx->host;
	plugin_data *p    = hctx->plugin_data;
	connection *con   = hctx->remote_conn;

	int ret;

	if (!host ||
	    (!host->host->used || !host->port)) return -1;

	switch(hctx->state) {
	case PROXY_STATE_INIT:
		if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
			return HANDLER_ERROR;
		}
		hctx->fde_ndx = -1;

		srv->cur_fds++;

		fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);

		if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
			log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));

			return HANDLER_ERROR;
		}

		/* fall through */

	case PROXY_STATE_CONNECT:
		/* try to finish the connect() */
		if (hctx->state == PROXY_STATE_INIT) {
			/* first round */
			switch (proxy_establish_connection(srv, hctx)) {
			case 1:
				proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);

				/* connection is in progress, wait for an event and call getsockopt() below */

				fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);

				return HANDLER_WAIT_FOR_EVENT;
			case -1:
				/* if ECONNREFUSED choose another connection -> FIXME */
				hctx->fde_ndx = -1;

				return HANDLER_ERROR;
			default:
				/* everything is ok, go on */
				break;
			}
		} else {
			int socket_error;
			socklen_t socket_error_len = sizeof(socket_error);

			/* we don't need it anymore */
			fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);

			/* try to finish the connect() */
			if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
				log_error_write(srv, __FILE__, __LINE__, "ss",
						"getsockopt failed:", strerror(errno));

				return HANDLER_ERROR;
			}
			if (socket_error != 0) {
				log_error_write(srv, __FILE__, __LINE__, "ss",
						"establishing connection failed:", strerror(socket_error),
						"port:", hctx->host->port);

				return HANDLER_ERROR;
			}
			if (p->conf.debug) {
				log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success");
			}
		}

		proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
		/* fall through */
	case PROXY_STATE_PREPARE_WRITE:
		proxy_create_env(srv, hctx);

		proxy_set_state(srv, hctx, PROXY_STATE_WRITE);

		/* fall through */
	case PROXY_STATE_WRITE:;
		ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);

		chunkqueue_remove_finished_chunks(hctx->wb);

		if (-1 == ret) {
			if (errno != EAGAIN &&
			    errno != EINTR) {
				log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);

				return HANDLER_ERROR;
			} else {
				fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);

				return HANDLER_WAIT_FOR_EVENT;
			}
		}

		if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
			proxy_set_state(srv, hctx, PROXY_STATE_READ);

			fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
			fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
		} else {
			fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);

			return HANDLER_WAIT_FOR_EVENT;
		}

		return HANDLER_WAIT_FOR_EVENT;
	case PROXY_STATE_READ:
		/* waiting for a response */
		return HANDLER_WAIT_FOR_EVENT;
	default:
		log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
		return HANDLER_ERROR;
	}

	return HANDLER_GO_ON;
}