Skip to content

Commit e57e2fb

Browse files
tsegismontwzy1935
andauthored
Out-of-the-box transformations for proxied requests (#78)
* Initial API proposal for interceptors See #65 Signed-off-by: Thomas Segismont <tsegismont@gmail.com> * Add basic header and path interceptors (#80) * Add basic header and path interceptors * fix batch 1 * fix batch 2 * fix batch 3 * add query interceptor * fix batch 4 * Add body interceptor (#81) * temp: test stucked * fix batch 1 * fix batch 2 * fix batch 3 * fix connection closed (#88) --------- Signed-off-by: Thomas Segismont <tsegismont@gmail.com> Co-authored-by: Zengyi Wang <wangzengyi1935@163.com>
1 parent 928d8d9 commit e57e2fb

19 files changed

+1131
-10
lines changed

src/main/asciidoc/index.adoc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,37 @@ You can change the control, e.g you can send a response immediately to the user-
140140
----
141141
{@link examples.HttpProxyExamples#immediateResponse}
142142
----
143+
144+
==== Header interceptor
145+
146+
You can apply header interceptors to change headers from the request and response with common operations:
147+
148+
[source,java]
149+
----
150+
{@link examples.HttpProxyExamples#headerInterceptorFilter}
151+
----
152+
153+
Check out the {@link io.vertx.httpproxy.interceptors.HeadersInterceptor} class for details about the available methods.
154+
155+
==== Query interceptor
156+
157+
You can use query interceptors to update or remove the query parameters:
158+
159+
[source,java]
160+
----
161+
{@link examples.HttpProxyExamples#queryInterceptorAdd}
162+
----
163+
164+
You can also refer to {@link io.vertx.httpproxy.interceptors.QueryInterceptor} for more information.
165+
166+
==== Body interceptor
167+
168+
You can use body interceptor to create body transformations for common data types, like {@link io.vertx.core.json.JsonObject}:
169+
170+
[source,java]
171+
----
172+
{@link examples.HttpProxyExamples#bodyInterceptorJson}
173+
----
174+
175+
Please check the {@link io.vertx.httpproxy.interceptors.BodyTransformer} for other supported transformations.
176+

src/main/java/examples/HttpProxyExamples.java

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@
88
import io.vertx.core.http.HttpServer;
99
import io.vertx.core.http.HttpServerRequest;
1010
import io.vertx.core.http.RequestOptions;
11+
import io.vertx.core.json.JsonObject;
1112
import io.vertx.core.net.HostAndPort;
1213
import io.vertx.core.net.SocketAddress;
13-
import io.vertx.httpproxy.Body;
14-
import io.vertx.httpproxy.HttpProxy;
15-
import io.vertx.httpproxy.ProxyContext;
16-
import io.vertx.httpproxy.ProxyInterceptor;
17-
import io.vertx.httpproxy.ProxyOptions;
18-
import io.vertx.httpproxy.ProxyRequest;
19-
import io.vertx.httpproxy.ProxyResponse;
14+
import io.vertx.httpproxy.*;
2015
import io.vertx.httpproxy.cache.CacheOptions;
16+
import io.vertx.httpproxy.interceptors.BodyInterceptor;
17+
import io.vertx.httpproxy.interceptors.BodyTransformer;
18+
import io.vertx.httpproxy.interceptors.HeadersInterceptor;
19+
import io.vertx.httpproxy.interceptors.QueryInterceptor;
20+
21+
import java.util.Set;
2122

2223
/**
2324
* @author <a href="mailto:emad.albloushi@gmail.com">Emad Alblueshi</a>
@@ -108,6 +109,26 @@ public Future<Void> handleProxyResponse(ProxyContext context) {
108109
});
109110
}
110111

112+
public void headerInterceptorFilter(HttpProxy proxy, Set<CharSequence> shouldRemove) {
113+
// remove a set of headers
114+
proxy.addInterceptor(
115+
HeadersInterceptor.filterResponseHeaders(shouldRemove));
116+
}
117+
118+
public void queryInterceptorAdd(HttpProxy proxy, String key, String value) {
119+
proxy.addInterceptor(
120+
QueryInterceptor.setQueryParam(key, value));
121+
}
122+
123+
public void bodyInterceptorJson(HttpProxy proxy) {
124+
proxy.addInterceptor(
125+
BodyInterceptor.modifyResponseBody(
126+
BodyTransformer.transformJsonObject(
127+
jsonObject -> removeSomeFields(jsonObject)
128+
)
129+
));
130+
}
131+
111132
public void immediateResponse(HttpProxy proxy) {
112133
proxy.addInterceptor(new ProxyInterceptor() {
113134
@Override
@@ -137,6 +158,12 @@ private Body filter(Body body) {
137158
return body;
138159
}
139160

161+
private JsonObject removeSomeFields(JsonObject o) {
162+
return o;
163+
}
164+
165+
;
166+
140167
public void more(Vertx vertx, HttpClient proxyClient) {
141168
HttpProxy proxy = HttpProxy.reverseProxy(proxyClient).originSelector(
142169
address -> Future.succeededFuture(SocketAddress.inetSocketAddress(7070, "origin"))

src/main/java/io/vertx/httpproxy/impl/BufferingWriteStream.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,12 @@
1111
package io.vertx.httpproxy.impl;
1212

1313
import io.vertx.codegen.annotations.Nullable;
14-
import io.vertx.core.AsyncResult;
1514
import io.vertx.core.Future;
1615
import io.vertx.core.Handler;
1716
import io.vertx.core.buffer.Buffer;
18-
import io.vertx.core.streams.ReadStream;
1917
import io.vertx.core.streams.WriteStream;
2018

21-
class BufferingWriteStream implements WriteStream<Buffer> {
19+
public class BufferingWriteStream implements WriteStream<Buffer> {
2220

2321
private final Buffer content;
2422

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2011-2024 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
12+
package io.vertx.httpproxy.interceptors;
13+
14+
import io.vertx.codegen.annotations.Unstable;
15+
import io.vertx.codegen.annotations.VertxGen;
16+
import io.vertx.httpproxy.ProxyInterceptor;
17+
import io.vertx.httpproxy.interceptors.impl.BodyInterceptorImpl;
18+
19+
/**
20+
* Used to create interceptors to modify request and response bodies.
21+
*/
22+
@VertxGen
23+
@Unstable
24+
public interface BodyInterceptor {
25+
26+
/**
27+
* Apply callbacks to change the request and response bodies when the proxy receives them.
28+
*
29+
* @param requestTransformer the operation to apply to the request body
30+
* @param responseTransformer the operation to apply to the response body
31+
* @return the created interceptor
32+
*/
33+
static ProxyInterceptor modifyBody(BodyTransformer requestTransformer, BodyTransformer responseTransformer) {
34+
return new BodyInterceptorImpl(requestTransformer, responseTransformer);
35+
}
36+
37+
/**
38+
* Apply callbacks to change the request body when the proxy receives it.
39+
*
40+
* @param requestTransformer the operation to apply to the request body
41+
* @return the created interceptor
42+
*/
43+
static ProxyInterceptor modifyRequestBody(BodyTransformer requestTransformer) {
44+
return new BodyInterceptorImpl(requestTransformer, null);
45+
}
46+
47+
/**
48+
* Apply callbacks to change the response body when the proxy receives it.
49+
*
50+
* @param responseTransformer the operation to apply to the response body
51+
* @return the created interceptor
52+
*/
53+
static ProxyInterceptor modifyResponseBody(BodyTransformer responseTransformer) {
54+
return new BodyInterceptorImpl(null, responseTransformer);
55+
}
56+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package io.vertx.httpproxy.interceptors;
2+
3+
import io.vertx.codegen.annotations.Unstable;
4+
import io.vertx.codegen.annotations.VertxGen;
5+
import io.vertx.core.buffer.Buffer;
6+
import io.vertx.core.json.JsonArray;
7+
import io.vertx.core.json.JsonObject;
8+
import io.vertx.httpproxy.interceptors.impl.BodyTransformerImpl;
9+
10+
import java.util.function.Function;
11+
12+
/**
13+
* The callback to transform the request or response body.
14+
*/
15+
@VertxGen
16+
@Unstable
17+
public interface BodyTransformer extends Function<Buffer, Buffer> {
18+
19+
/**
20+
* Create a callback for transform JsonObject.
21+
*
22+
* @param transformer the operation to transform data
23+
* @return the built callback
24+
*/
25+
static BodyTransformer transformJsonObject(Function<JsonObject, JsonObject> transformer) {
26+
return BodyTransformerImpl.transformJsonObject(transformer);
27+
}
28+
29+
/**
30+
* Create a callback for transform JsonArray.
31+
*
32+
* @param transformer the operation to transform data
33+
* @return the built callback
34+
*/
35+
static BodyTransformer transformJsonArray(Function<JsonArray, JsonArray> transformer) {
36+
return BodyTransformerImpl.transformJsonArray(transformer);
37+
}
38+
39+
/**
40+
* Create a callback for transform json with unknown shape.
41+
*
42+
* @param transformer the operation to transform data
43+
* @return the built callback
44+
*/
45+
static BodyTransformer transformJson(Function<Object, Object> transformer) {
46+
return BodyTransformerImpl.transformJson(transformer);
47+
}
48+
49+
/**
50+
* Create a callback for transform texts.
51+
*
52+
* @param transformer the operation to transform data
53+
* @return the built callback
54+
*/
55+
static BodyTransformer transformText(Function<String, String> transformer, String encoding) {
56+
return BodyTransformerImpl.transformText(transformer, encoding);
57+
}
58+
59+
/**
60+
* Create a callback to discard the body.
61+
*
62+
* @return the built callback
63+
*/
64+
static BodyTransformer discard() {
65+
return BodyTransformerImpl.discard();
66+
}
67+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2011-2024 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
12+
package io.vertx.httpproxy.interceptors;
13+
14+
import io.vertx.codegen.annotations.GenIgnore;
15+
import io.vertx.codegen.annotations.Unstable;
16+
import io.vertx.codegen.annotations.VertxGen;
17+
import io.vertx.core.Handler;
18+
import io.vertx.core.MultiMap;
19+
import io.vertx.httpproxy.ProxyInterceptor;
20+
import io.vertx.httpproxy.interceptors.impl.HeadersInterceptorImpl;
21+
22+
import java.util.Set;
23+
24+
import static io.vertx.codegen.annotations.GenIgnore.PERMITTED_TYPE;
25+
26+
/**
27+
* Used to create interceptors to modify request and response headers.
28+
*/
29+
@VertxGen
30+
@Unstable
31+
public interface HeadersInterceptor {
32+
33+
/**
34+
* Apply callbacks to change the request and response headers when the proxy receives them.
35+
*
36+
* @param changeRequestHeaders the operation to apply to the request headers
37+
* @param changeResponseHeaders the operation to apply to the response headers
38+
* @return the created interceptor
39+
*/
40+
static ProxyInterceptor changeHeaders(Handler<MultiMap> changeRequestHeaders, Handler<MultiMap> changeResponseHeaders) {
41+
return new HeadersInterceptorImpl(changeRequestHeaders, changeResponseHeaders);
42+
}
43+
44+
/**
45+
* Filter the request headers in the given set.
46+
*
47+
* @param requestHeaders a set of the headers that need to be filtered
48+
* @return the created interceptor
49+
*/
50+
@GenIgnore(PERMITTED_TYPE)
51+
static ProxyInterceptor filterRequestHeaders(Set<CharSequence> requestHeaders) {
52+
return HeadersInterceptorImpl.filter(requestHeaders, null);
53+
}
54+
55+
/**
56+
* Filter the response headers in the given set.
57+
*
58+
* @param responseHeaders a set of the headers that need to be filtered
59+
* @return the created interceptor
60+
*/
61+
@GenIgnore(PERMITTED_TYPE)
62+
static ProxyInterceptor filterResponseHeaders(Set<CharSequence> responseHeaders) {
63+
return HeadersInterceptorImpl.filter(null, responseHeaders);
64+
}
65+
66+
/**
67+
* Filter the request and response headers in the given sets.
68+
*
69+
* @param requestHeaders a set of the request headers that need to be filtered
70+
* @param responseHeaders a set of the response headers that need to be filtered
71+
* @return the created interceptor
72+
*/
73+
@GenIgnore(PERMITTED_TYPE)
74+
static ProxyInterceptor filterHeaders(Set<CharSequence> requestHeaders, Set<CharSequence> responseHeaders) {
75+
return HeadersInterceptorImpl.filter(requestHeaders, responseHeaders);
76+
}
77+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2011-2024 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
12+
package io.vertx.httpproxy.interceptors;
13+
14+
import io.vertx.codegen.annotations.Unstable;
15+
import io.vertx.codegen.annotations.VertxGen;
16+
import io.vertx.httpproxy.ProxyInterceptor;
17+
import io.vertx.httpproxy.interceptors.impl.PathInterceptorImpl;
18+
19+
import java.util.function.Function;
20+
21+
/**
22+
* Used to create interceptors to modify the request path.
23+
*/
24+
@VertxGen
25+
@Unstable
26+
public interface PathInterceptor {
27+
28+
/**
29+
* Apply a callback to change the request URI when the proxy receives it.
30+
*
31+
* @param pattern the operation that applied to the path
32+
* @return the created interceptor
33+
*/
34+
static ProxyInterceptor changePath(Function<String, String> pattern) {
35+
return new PathInterceptorImpl(pattern);
36+
}
37+
38+
/**
39+
* Add a prefix to the URI.
40+
*
41+
* @param prefix the prefix that need to be added
42+
* @return the created interceptor
43+
*/
44+
static ProxyInterceptor removePrefix(String prefix) {
45+
return PathInterceptorImpl.removePrefix(prefix);
46+
}
47+
48+
/**
49+
* Remove a prefix to the URI. Do nothing if it doesn't exist.
50+
*
51+
* @param prefix the prefix that need to be removed
52+
* @return the created interceptor
53+
*/
54+
static ProxyInterceptor addPrefix(String prefix) {
55+
return PathInterceptorImpl.addPrefix(prefix);
56+
}
57+
}

0 commit comments

Comments
 (0)