private static Eventual<LiveHttpResponse> handleErrors(Throwable e, HttpInterceptor.Context context) { if (e instanceof PluginNotFoundException) { return Eventual.of(responseWith(NOT_FOUND, e.getMessage())); } if (e instanceof BadPluginToggleRequestException) { return Eventual.of(responseWith(BAD_REQUEST, e.getMessage())); } LOGGER.error("Plugin toggle error", e); return Eventual.of(responseWith(INTERNAL_SERVER_ERROR, "")); }
private static <T> Eventual<T> fromMono(Mono<T> mono) { return new Eventual<>(mono); }
@Override public Eventual<LiveHttpResponse> intercept(LiveHttpRequest request, Chain chain) { return chain.proceed(request) .flatMap(response -> response.aggregate(this.maxContentLength)) .flatMap(fullResponse -> Eventual.from(asyncEvent(this.delayMillis)) .map(x -> fullResponse)) .map(HttpResponse::stream); }
@Override public Eventual<LiveHttpResponse> intercept(LiveHttpRequest request, Chain chain) { String header = xHcomPluginsHeader(request); final String configPath = environment.pluginConfig(String.class); String pluginsList = environment.configuration().get("plugins.active").get(); LiveHttpRequest newRequest = request.newBuilder() .header(X_HCOM_PLUGINS_HEADER, header) .header(X_HCOM_PLUGINS_CONFIGURATION_PATH, configPath) .header(X_HCOM_PLUGINS_LIST, pluginsList) .header("X-Hcom-Styx-Started", styxStarted) .header("X-Hcom-Styx-Stopped", styxStopped) .build(); Function<ByteBuf, String> byteBufStringFunction = byteBuf -> byteBuf.toString(Charsets.UTF_8); return chain.proceed(newRequest) .flatMap(response -> response.aggregate(1 * 1024 * 1024)) .map(response -> response.newBuilder() .header(X_HCOM_PLUGINS_HEADER, header) .header(X_HCOM_PLUGINS_CONFIGURATION_PATH, configPath) .header(X_HCOM_PLUGINS_LIST, pluginsList) .header("X-Hcom-Styx-Started", styxStarted) .header("X-Hcom-Styx-Stopped", styxStopped) .build()) .map(HttpResponse::stream); }
/** * Aggregates content stream and converts this response to a {@link HttpResponse}. * <p> * Returns a {@link Eventual <HttpResponse>} that eventually produces a * {@link HttpResponse}. The resulting full response object has the same * response line, headers, and content as this response. * <p> * The content stream is aggregated asynchronously. The stream may be connected * to a network socket or some other content producer. Once aggregated, a * HttpResponse object is emitted on the returned {@link Eventual}. * <p> * A sole {@code maxContentBytes} argument is a backstop defence against excessively * long content streams. The {@code maxContentBytes} should be set to a sensible * value according to your application requirements and heap size. When the content * size stream exceeds the {@code maxContentBytes}, a @{link ContentOverflowException} * is emitted on the returned observable. * * @param maxContentBytes maximum expected content size * @return a {@link Eventual} */ public Eventual<HttpResponse> aggregate(int maxContentBytes) { return Eventual.from(body.aggregate(maxContentBytes)) .map(it -> new HttpResponse.Builder(this, decodeAndRelease(it)) .disableValidation() .build() ); }
@Override public Eventual<LiveHttpResponse> proceed(LiveHttpRequest request) { requestTracker.trackRequest(request); if (index < interceptors.size()) { HttpInterceptor.Chain chain = new HttpInterceptorChain(this, index + 1); HttpInterceptor interceptor = interceptors.get(index); try { return interceptor.intercept(request, chain); } catch (Throwable e) { return Eventual.error(e); } } requestTracker.markRequestAsSent(request); return new Eventual<>(toPublisher(toObservable(client.handle(request, this.context)) .compose(StandardHttpPipeline::sendErrorOnDoubleSubscription))); } }
public static HttpResponse waitForResponse(Eventual<LiveHttpResponse> responseObs) { return Mono.from(responseObs.flatMap(response -> response.aggregate(120*1024))).block(); }
/** * Aggregates content stream and converts this request to a {@link HttpRequest}. * <p> * Returns a {@link Eventual} that eventually produces a * {@link HttpRequest}. The resulting full request object has the same * request line, headers, and content as this request. * <p> * The content stream is aggregated asynchronously. The stream may be connected * to a network socket or some other content producer. Once aggregated, a * HttpRequest object is emitted on the returned {@link Eventual}. * <p> * A sole {@code maxContentBytes} argument is a backstop defence against excessively * long content streams. The {@code maxContentBytes} should be set to a sensible * value according to your application requirements and heap size. When the content * size stream exceeds the {@code maxContentBytes}, a @{link ContentOverflowException} * is emitted on the returned observable. * * @param maxContentBytes maximum expected content size * @return a {@link Eventual} */ public Eventual<HttpRequest> aggregate(int maxContentBytes) { return Eventual.from( body.aggregate(maxContentBytes) .thenApply(it -> new HttpRequest.Builder(this, decodeAndRelease(it)).build()) ); }
@Override public Eventual<LiveHttpResponse> handle(LiveHttpRequest request, HttpInterceptor.Context context) { return router.route(request, context) .map(pipeline -> pipeline.handle(request, context)) .orElseGet(() -> Eventual.error(new NoServiceConfiguredException(request.path()))); } }
@Override public Eventual<LiveHttpResponse> handle(LiveHttpRequest request, HttpInterceptor.Context context) { return getCurrentOrPutNewState(request, context) .onError(cause -> handleErrors(cause, context)); }
@Override public Eventual<LiveHttpResponse> intercept(LiveHttpRequest request, Chain chain) { return request.aggregate(config.maxContentLength()) .flatMap(fullHttpRequest -> Eventual.from(asyncOperation(config.delayMillis()))) .map(outcome -> request.newBuilder().header("X-Outcome", outcome.result())) .flatMap(x -> chain.proceed(request)); } }
@Override public Eventual<LiveHttpResponse> intercept(LiveHttpRequest request, Chain chain) { return chain.proceed(removeHopByHopHeaders(request)) .map(HopByHopHeadersRemovingInterceptor::removeHopByHopHeaders); }
@Override public Eventual<LiveHttpResponse> intercept(LiveHttpRequest request, Chain originalChain) { StatusRecordingChain chain = new StatusRecordingChain(originalChain); try { return new Eventual<>(toPublisher( toObservable(plugin.intercept(request, chain)) .doOnNext(response -> recordStatusCode(chain, response)) .onErrorResumeNext(error -> error(recordAndWrapError(chain, error))))); } catch (Throwable e) { recordException(e); return Eventual.error(new PluginException(e, plugin.name())); } }