All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vertx.httpproxy.impl.ReverseProxy Maven / Gradle / Ivy

The newest version!
/**
 * XXX 复制4.5.7版本的io.vertx.httpproxy.impl.ReverseProxy类的代码,让websocket也支持代理拦截器
 * Copyright (c) 2011-2020 Contributors to the Eclipse Foundation
 * 

* This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 * which is available at https://www.apache.org/licenses/LICENSE-2.0. *

* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 */ package io.vertx.httpproxy.impl; import java.util.*; import java.util.function.BiFunction; import io.vertx.core.Future; import io.vertx.core.Promise; import io.vertx.core.http.*; import io.vertx.core.net.NetSocket; import io.vertx.httpproxy.*; import io.vertx.httpproxy.cache.CacheOptions; import io.vertx.httpproxy.spi.cache.Cache; public class ReverseProxy implements HttpProxy { private final HttpClient client; private final boolean supportWebSocket; private BiFunction> selector = (req, client) -> Future .failedFuture("No origin available"); private final List interceptors = new ArrayList<>(); public ReverseProxy(ProxyOptions options, HttpClient client) { CacheOptions cacheOptions = options.getCacheOptions(); if (cacheOptions != null) { Cache cache = cacheOptions.newCache(); addInterceptor(new CachingFilter(cache)); } this.client = client; this.supportWebSocket = options.getSupportWebSocket(); } @Override public HttpProxy originRequestProvider( BiFunction> provider) { selector = provider; return this; } @Override public HttpProxy addInterceptor(ProxyInterceptor interceptor) { interceptors.add(interceptor); return this; } @Override public void handle(HttpServerRequest request) { ProxyRequest proxyRequest = ProxyRequest.reverseProxy(request); // Encoding sanity check Boolean chunked = HttpUtils.isChunked(request.headers()); if (chunked == null) { end(proxyRequest, 400); return; } // WebSocket upgrade tunneling if (supportWebSocket && io.vertx.core.http.impl.HttpUtils.canUpgradeToWebSocket(request)) { handleWebSocketUpgrade(proxyRequest); return; } Proxy proxy = new Proxy(proxyRequest); proxy.filters = interceptors.listIterator(); proxy.sendRequest().compose(proxy::sendProxyResponse); } private void handleWebSocketUpgrade(ProxyRequest proxyRequest) { // XXX 添加调用拦截器修改代理请求 interceptors.forEach(proxyInterceptor -> proxyInterceptor.modifyProxyRequest(proxyRequest)); HttpServerRequest proxiedRequest = proxyRequest.proxiedRequest(); resolveOrigin(proxiedRequest).onComplete(ar -> { if (ar.succeeded()) { HttpClientRequest request = ar.result(); request.setMethod(HttpMethod.GET); // XXX 过滤器可能要改变目标请求的uri,所以这里用代理请求的URI,而不是用被代理请求的URI // request.setURI(proxiedRequest.uri()); request.setURI(proxyRequest.getURI()); request.headers().addAll(proxiedRequest.headers()); Future fut2 = request.connect(); proxiedRequest.handler(request::write); proxiedRequest.endHandler(v -> request.end()); proxiedRequest.resume(); fut2.onComplete(ar2 -> { if (ar2.succeeded()) { HttpClientResponse proxiedResponse = ar2.result(); if (proxiedResponse.statusCode() == 101) { HttpServerResponse response = proxiedRequest.response(); response.setStatusCode(101); response.headers().addAll(proxiedResponse.headers()); Future otherso = proxiedRequest.toNetSocket(); otherso.onComplete(ar3 -> { if (ar3.succeeded()) { NetSocket responseSocket = ar3.result(); NetSocket proxyResponseSocket = proxiedResponse.netSocket(); responseSocket.handler(proxyResponseSocket::write); proxyResponseSocket.handler(responseSocket::write); responseSocket.closeHandler(v -> proxyResponseSocket.close()); proxyResponseSocket.closeHandler(v -> responseSocket.close()); } else { // Find reproducer System.err.println("Handle this case"); ar3.cause().printStackTrace(); } }); } else { // Rejection proxiedRequest.resume(); end(proxyRequest, proxiedResponse.statusCode()); } } else { proxiedRequest.resume(); end(proxyRequest, 502); } }); } else { proxiedRequest.resume(); end(proxyRequest, 502); } }); } private void end(ProxyRequest proxyRequest, int sc) { proxyRequest .response() .release() .setStatusCode(sc) .putHeader(HttpHeaders.CONTENT_LENGTH, "0") .setBody(null) .send(); } private Future resolveOrigin(HttpServerRequest proxiedRequest) { return selector.apply(proxiedRequest, client); } private class Proxy implements ProxyContext { private final ProxyRequest request; private ProxyResponse response; private final Map attachments = new HashMap<>(); private ListIterator filters; private Proxy(ProxyRequest request) { this.request = request; } @Override public void set(String name, Object value) { attachments.put(name, value); } @Override public T get(String name, Class type) { Object o = attachments.get(name); return type.isInstance(o) ? type.cast(o) : null; } @Override public ProxyRequest request() { return request; } @Override public Future sendRequest() { if (filters.hasNext()) { ProxyInterceptor next = filters.next(); return next.handleProxyRequest(this); } else { return sendProxyRequest(request); } } @Override public ProxyResponse response() { return response; } @Override public Future sendResponse() { if (filters.hasPrevious()) { ProxyInterceptor filter = filters.previous(); return filter.handleProxyResponse(this); } else { return response.send(); } } private Future sendProxyRequest(ProxyRequest proxyRequest) { Future f = resolveOrigin(proxyRequest.proxiedRequest()); f.onFailure(err -> { // Should this be done here ? I don't think so HttpServerRequest proxiedRequest = proxyRequest.proxiedRequest(); proxiedRequest.resume(); Promise promise = Promise.promise(); proxiedRequest.exceptionHandler(promise::tryFail); proxiedRequest.endHandler(promise::tryComplete); promise.future().onComplete(ar2 -> { end(proxyRequest, 502); }); }); return f.compose(a -> sendProxyRequest(proxyRequest, a)); } private Future sendProxyRequest(ProxyRequest proxyRequest, HttpClientRequest request) { Future fut = proxyRequest.send(request); fut.onFailure(err -> { proxyRequest.proxiedRequest().response().setStatusCode(502).end(); }); return fut; } private Future sendProxyResponse(ProxyResponse response) { this.response = response; // Check validity Boolean chunked = HttpUtils.isChunked(response.headers()); if (chunked == null) { // response.request().release(); // Is it needed ??? end(response.request(), 501); return Future.succeededFuture(); // should use END future here ??? } return sendResponse(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy