Exemplo n.º 1
0
static filter_lua_state* filter_lua_state_new(liVRequest *vr, filter_lua_config *config) {
	int object_ref = LUA_NOREF;
	liServer *srv = vr->wrk->srv;
	lua_State *L = config->LL->L;

	li_lua_lock(config->LL);

	lua_rawgeti(L, LUA_REGISTRYINDEX, config->class_ref); /* +1 */
	li_lua_push_vrequest(L, vr); /* +1 */

	if (li_lua_call_object(srv, vr, L, "new", 2, 1, FALSE)) { /* -2, +1 on success */
		if (!lua_isnil(L, -1)) {
			object_ref = luaL_ref(L, LUA_REGISTRYINDEX); /* -1 */
		} else { /* no error; nil is interpreted as "don't need this filter for this request" */
			lua_pop(L, 1); /* -1 */
		}
	} else {
		VR_ERROR(vr, "%s", "li_lua_call_object failed");
		li_vrequest_error(vr);
	}

	li_lua_unlock(config->LL);

	if (LUA_NOREF != object_ref) {
		filter_lua_state *state = g_slice_new0(filter_lua_state);
		state->LL = config->LL;
		state->object_ref = object_ref;

		return state;
	} else {
		return NULL;
	}
}
Exemplo n.º 2
0
static void stream_http_response_data(liStreamHttpResponse* shr) {
	if (NULL == shr->stream.source) return;

	if (!shr->response_headers_finished) {
		switch (li_http_response_parse(shr->vr, &shr->parse_response_ctx)) {
		case LI_HANDLER_GO_ON:
			check_response_header(shr);
			if (NULL == shr->stream.source) return;
			break;
		case LI_HANDLER_ERROR:
			VR_ERROR(shr->vr, "%s", "Parsing response header failed");
			li_vrequest_error(shr->vr);
			return;
		case LI_HANDLER_WAIT_FOR_EVENT:
			if (shr->stream.source->out->is_closed) {
				VR_ERROR(shr->vr, "%s", "Parsing response header failed (eos)");
				li_vrequest_error(shr->vr);
			}
			return;
		default:
			return;
		}
	}

	if (shr->transfer_encoding_chunked) {
		if (!li_filter_chunked_decode(shr->vr, shr->stream.out, shr->stream.source->out, &shr->chunked_decode_state)) {
			if (NULL != shr->vr) {
				VR_ERROR(shr->vr, "%s", "Decoding chunks failed");
				li_vrequest_error(shr->vr);
			} else {
				li_stream_reset(&shr->stream);
			}
		}
		if (shr->stream.source->out->is_closed) {
			li_stream_disconnect(&shr->stream);
		}
	} else {
		li_chunkqueue_steal_all(shr->stream.out, shr->stream.source->out);
		if (shr->stream.source->out->is_closed) {
			shr->stream.out->is_closed = TRUE;
			li_stream_disconnect(&shr->stream);
		}
	}
	li_stream_notify(&shr->stream);
}
Exemplo n.º 3
0
static gboolean fastcgi_parse_response(fastcgi_connection *fcon) {
	liVRequest *vr = fcon->vr;
	liPlugin *p = fcon->ctx->plugin;
	gint len;
	while (fastcgi_get_packet(fcon)) {
		if (fcon->fcgi_in_record.version != FCGI_VERSION_1) {
			VR_ERROR(vr, "(%s) Unknown fastcgi protocol version %i", fcon->ctx->socket_str->str, (gint) fcon->fcgi_in_record.version);
			close(fcon->fd);
			fcon->fd = -1;
			li_vrequest_error(vr);
			return FALSE;
		}
		switch (fcon->fcgi_in_record.type) {
		case FCGI_END_REQUEST:
			li_chunkqueue_skip(fcon->fcgi_in, fastcgi_available(fcon));
			fcon->stdout->is_closed = TRUE;
			break;
		case FCGI_STDOUT:
			if (0 == fcon->fcgi_in_record.contentLength) {
				fcon->stdout->is_closed = TRUE;
			} else {
				li_chunkqueue_steal_len(fcon->stdout, fcon->fcgi_in, fastcgi_available(fcon));
			}
			break;
		case FCGI_STDERR:
			len = fastcgi_available(fcon);
			li_chunkqueue_extract_to(vr, fcon->fcgi_in, len, vr->wrk->tmp_str);
			if (OPTION(FASTCGI_OPTION_LOG_PLAIN_ERRORS).boolean) {
				li_log_split_lines(vr->wrk->srv, vr, LI_LOG_LEVEL_BACKEND, 0, vr->wrk->tmp_str->str, "");
			} else {
				VR_BACKEND_LINES(vr, vr->wrk->tmp_str->str, "(fcgi-stderr %s) ", fcon->ctx->socket_str->str);
			}
			li_chunkqueue_skip(fcon->fcgi_in, len);
			break;
		default:
			if (fcon->fcgi_in_record.first) VR_WARNING(vr, "(%s) Unhandled fastcgi record type %i", fcon->ctx->socket_str->str, (gint) fcon->fcgi_in_record.type);
			li_chunkqueue_skip(fcon->fcgi_in, fastcgi_available(fcon));
			break;
		}
		fcon->fcgi_in_record.first = FALSE;
	}
	return TRUE;
}
Exemplo n.º 4
0
static void check_response_header(liStreamHttpResponse* shr) {
	liResponse *resp = &shr->vr->response;
	GList *l;

	shr->transfer_encoding_chunked = FALSE;

	/* Transfer-Encoding: chunked */
	l = li_http_header_find_first(resp->headers, CONST_STR_LEN("transfer-encoding"));
	if (l) {
		for ( ; l ; l = li_http_header_find_next(l, CONST_STR_LEN("transfer-encoding")) ) {
			liHttpHeader *hh = (liHttpHeader*) l->data;
			if (0 == g_ascii_strcasecmp( LI_HEADER_VALUE(hh), "identity" )) {
				/* ignore */
				continue;
			} if (0 == g_ascii_strcasecmp( LI_HEADER_VALUE(hh), "chunked" )) {
				if (shr->transfer_encoding_chunked) {
					VR_ERROR(shr->vr, "%s", "Response is chunked encoded twice");
					li_vrequest_error(shr->vr);
					return;
				}
				shr->transfer_encoding_chunked = TRUE;
			} else {
				VR_ERROR(shr->vr, "Response has unsupported Transfer-Encoding: %s", LI_HEADER_VALUE(hh));
				li_vrequest_error(shr->vr);
				return;
			}
		}
		li_http_header_remove(resp->headers, CONST_STR_LEN("transfer-encoding"));
		/* any non trivial transfer-encoding overwrites content-length */
		if (shr->transfer_encoding_chunked) {
			li_http_header_remove(resp->headers, CONST_STR_LEN("content-length"));
		}
	}

	/* Upgrade: */
	l = li_http_header_find_first(resp->headers, CONST_STR_LEN("upgrade"));
	if (l) {
		gboolean have_connection_upgrade = FALSE;
		liHttpHeaderTokenizer header_tokenizer;
		GString *token;
		if (101 != resp->http_status) {
			VR_ERROR(shr->vr, "Upgrade but status is %i instead of 101 'Switching Protocols'", resp->http_status);
			li_vrequest_error(shr->vr);
			return;
		}
		if (shr->transfer_encoding_chunked) {
			VR_ERROR(shr->vr, "%s", "Upgrade with Transfer-Encoding: chunked");
			li_vrequest_error(shr->vr);
			return;
		}
		/* requires Connection: Upgrade header */
		token = g_string_sized_new(15);
		li_http_header_tokenizer_start(&header_tokenizer, resp->headers, CONST_STR_LEN("Connection"));
		while (li_http_header_tokenizer_next(&header_tokenizer, token)) {
			VR_ERROR(shr->vr, "Parsing header '%s'", ((liHttpHeader*)header_tokenizer.cur->data)->data->str);
			VR_ERROR(shr->vr, "Connection token '%s'", token->str);
			if (0 == g_ascii_strcasecmp(token->str, "Upgrade")) {
				have_connection_upgrade = TRUE;
				break;
			}
		}
		g_string_free(token, TRUE); token = NULL;
		if (!have_connection_upgrade) {
			VR_ERROR(shr->vr, "%s", "Upgrade without Connection: Upgrade Transfer");
			li_vrequest_error(shr->vr);
			return;
		}
		shr->response_headers_finished = TRUE;
		shr->vr->backend_drain->out->is_closed = FALSE;
		{
			/* li_vrequest_connection_upgrade releases vr->backend_drain; keep our own reference */
			liStream *backend_drain = shr->vr->backend_drain;
			shr->vr->backend_drain = NULL;
			li_vrequest_connection_upgrade(shr->vr, backend_drain, &shr->stream);
			li_stream_release(backend_drain);
		}
		return;
	}

	shr->response_headers_finished = TRUE;
	li_vrequest_indirect_headers_ready(shr->vr);

	return;
}
Exemplo n.º 5
0
static void proxy_fd_cb(struct ev_loop *loop, ev_io *w, int revents) {
	proxy_connection *pcon = (proxy_connection*) w->data;

	if (pcon->state == SS_CONNECTING) {
		if (LI_HANDLER_GO_ON != proxy_statemachine(pcon->vr, pcon)) {
			li_vrequest_error(pcon->vr);
		}
		return;
	}

	if (revents & EV_READ) {
		if (pcon->proxy_in->is_closed) {
			li_ev_io_rem_events(loop, w, EV_READ);
		} else {
			switch (li_network_read(pcon->vr, w->fd, pcon->proxy_in, &pcon->proxy_in_buffer)) {
			case LI_NETWORK_STATUS_SUCCESS:
				break;
			case LI_NETWORK_STATUS_FATAL_ERROR:
				VR_ERROR(pcon->vr, "(%s) network read fatal error", pcon->ctx->socket_str->str);
				li_vrequest_error(pcon->vr);
				return;
			case LI_NETWORK_STATUS_CONNECTION_CLOSE:
				pcon->proxy_in->is_closed = TRUE;
				ev_io_stop(loop, w);
				close(pcon->fd);
				pcon->fd = -1;
				li_vrequest_backend_finished(pcon->vr);
				break;
			case LI_NETWORK_STATUS_WAIT_FOR_EVENT:
				break;
			}
		}
	}

	if (pcon->fd != -1 && (revents & EV_WRITE)) {
		if (pcon->proxy_out->length > 0) {
			switch (li_network_write(pcon->vr, w->fd, pcon->proxy_out, 256*1024)) {
			case LI_NETWORK_STATUS_SUCCESS:
				break;
			case LI_NETWORK_STATUS_FATAL_ERROR:
				VR_ERROR(pcon->vr, "(%s) network write fatal error", pcon->ctx->socket_str->str);
				li_vrequest_error(pcon->vr);
				return;
			case LI_NETWORK_STATUS_CONNECTION_CLOSE:
				pcon->proxy_in->is_closed = TRUE;
				ev_io_stop(loop, w);
				close(pcon->fd);
				pcon->fd = -1;
				li_vrequest_backend_finished(pcon->vr);
				break;
			case LI_NETWORK_STATUS_WAIT_FOR_EVENT:
				break;
			}
		}
		if (pcon->proxy_out->length == 0) {
			li_ev_io_rem_events(loop, w, EV_WRITE);
		}
	}

	if (!pcon->response_headers_finished && LI_HANDLER_GO_ON == li_http_response_parse(pcon->vr, &pcon->parse_response_ctx)) {
		/* "ignore" 1xx response headers */
		if (!(pcon->vr->response.http_status >= 100 && pcon->vr->response.http_status < 200)) {
			pcon->response_headers_finished = TRUE;
			li_vrequest_handle_response_headers(pcon->vr);
		}
	}

	if (pcon->response_headers_finished) {
		li_chunkqueue_steal_all(pcon->vr->out, pcon->proxy_in);
		pcon->vr->out->is_closed = pcon->proxy_in->is_closed;
		li_vrequest_handle_response_body(pcon->vr);
	}

	/* only possible if we didn't found a header */
	if (pcon->proxy_in->is_closed && !pcon->vr->out->is_closed) {
		VR_ERROR(pcon->vr, "(%s) unexpected end-of-file (perhaps the proxy process died)", pcon->ctx->socket_str->str);
		li_vrequest_error(pcon->vr);
	}
}
Exemplo n.º 6
0
static void fastcgi_fd_cb(struct ev_loop *loop, ev_io *w, int revents) {
	fastcgi_connection *fcon = (fastcgi_connection*) w->data;

	if (fcon->state == FS_CONNECTING) {
		if (LI_HANDLER_GO_ON != fastcgi_statemachine(fcon->vr, fcon)) {
			li_vrequest_error(fcon->vr);
		}
		return;
	}

	if (revents & EV_READ) {
		if (fcon->fcgi_in->is_closed) {
			li_ev_io_rem_events(loop, w, EV_READ);
		} else {
			switch (li_network_read(fcon->vr, w->fd, fcon->fcgi_in, &fcon->fcgi_in_buffer)) {
			case LI_NETWORK_STATUS_SUCCESS:
				break;
			case LI_NETWORK_STATUS_FATAL_ERROR:
				VR_ERROR(fcon->vr, "(%s) network read fatal error", fcon->ctx->socket_str->str);
				li_vrequest_error(fcon->vr);
				return;
			case LI_NETWORK_STATUS_CONNECTION_CLOSE:
				fcon->fcgi_in->is_closed = TRUE;
				ev_io_stop(loop, w);
				close(fcon->fd);
				fcon->fd = -1;
				li_vrequest_backend_finished(fcon->vr);
				break;
			case LI_NETWORK_STATUS_WAIT_FOR_EVENT:
				break;
			}
		}
	}

	if (fcon->fd != -1 && (revents & EV_WRITE)) {
		if (fcon->fcgi_out->length > 0) {
			switch (li_network_write(fcon->vr, w->fd, fcon->fcgi_out, 256*1024)) {
			case LI_NETWORK_STATUS_SUCCESS:
				break;
			case LI_NETWORK_STATUS_FATAL_ERROR:
				VR_ERROR(fcon->vr, "(%s) network write fatal error", fcon->ctx->socket_str->str);
				li_vrequest_error(fcon->vr);
				return;
			case LI_NETWORK_STATUS_CONNECTION_CLOSE:
				fcon->fcgi_in->is_closed = TRUE;
				ev_io_stop(loop, w);
				close(fcon->fd);
				fcon->fd = -1;
				li_vrequest_backend_finished(fcon->vr);
				break;
			case LI_NETWORK_STATUS_WAIT_FOR_EVENT:
				break;
			}
		}
		if (fcon->fcgi_out->length == 0) {
			li_ev_io_rem_events(loop, w, EV_WRITE);
		}
	}

	if (!fastcgi_parse_response(fcon)) return;

	if (!fcon->response_headers_finished) {
		switch (li_http_response_parse(fcon->vr, &fcon->parse_response_ctx)) {
		case LI_HANDLER_GO_ON:
			fcon->response_headers_finished = TRUE;
			li_vrequest_handle_response_headers(fcon->vr);
			break;
		case LI_HANDLER_ERROR:
			VR_ERROR(fcon->vr, "Parsing response header failed for: %s", fcon->ctx->socket_str->str);
			li_vrequest_error(fcon->vr);
			break;
		default:
			break;
		}
	}

	if (fcon->response_headers_finished) {
		li_chunkqueue_steal_all(fcon->vr->out, fcon->stdout);
		fcon->vr->out->is_closed = fcon->stdout->is_closed;
		li_vrequest_handle_response_body(fcon->vr);
	}

	if (fcon->fcgi_in->is_closed && !fcon->vr->out->is_closed) {
		VR_ERROR(fcon->vr, "(%s) unexpected end-of-file (perhaps the fastcgi process died)", fcon->ctx->socket_str->str);
		li_vrequest_error(fcon->vr);
	}
}