Skip to content

Commit e6aa55c

Browse files
authored
Merge pull request #122 from eclipse-vertx/simplify-creation-of-interceptors
Interceptor improvements
2 parents c41506d + e6f82b9 commit e6aa55c

33 files changed

+1769
-504
lines changed

src/main/asciidoc/index.adoc

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -134,26 +134,24 @@ You can filter body by simply replacing the original {@link io.vertx.httpproxy.B
134134
{@link io.vertx.httpproxy.ProxyContext#sendRequest} and {@link io.vertx.httpproxy.ProxyContext#sendResponse} continue the
135135
current interception chain and then send the result to the origin server or the user-agent.
136136

137-
You can change the control, e.g you can send a response immediately to the user-agent without even requesting the origin server
137+
You can change the control, e.g. you can send a response immediately to the user-agent without even requesting the origin server
138138

139139
[source,java]
140140
----
141141
{@link examples.HttpProxyExamples#immediateResponse}
142142
----
143143

144-
==== Head interceptor
144+
==== Customizable interceptor
145145

146-
You can use the {@link io.vertx.httpproxy.interceptors.HeadInterceptor} to change HTTP request/response heads:
146+
You can use {@link io.vertx.httpproxy.ProxyInterceptor#builder()} that facilitates the implementation of an interceptor
147+
that modifies the request/response heads and bodies:
147148

148149
- request path
149150
- query params
150151
- request and response headers
152+
- body transformation
151153

152-
A {@link io.vertx.httpproxy.interceptors.HeadInterceptor} is created and configured with a {@link io.vertx.httpproxy.interceptors.HeadInterceptorBuilder}.
153-
154-
The builder methods can be invoked several times.
155-
Operations on the path will be invoked in the order of configuration.
156-
That goes for operations on query parameters, request headers and response headers.
154+
Such interceptor is created and configured with a {@link io.vertx.httpproxy.ProxyInterceptorBuilder}.
157155

158156
===== Headers interception
159157

@@ -164,7 +162,9 @@ You can apply the interceptor to change headers from the request and response wi
164162
{@link examples.HttpProxyExamples#headerInterceptorFilter}
165163
----
166164

167-
Check out {@link io.vertx.httpproxy.interceptors.HeadInterceptorBuilder} for details about the available methods.
165+
Headers modifying methods can be invoked several times, operations are applied in the order of configuration.
166+
167+
Check out {@link io.vertx.httpproxy.ProxyInterceptorBuilder} for details about the available methods.
168168

169169
===== Query params interception
170170

@@ -175,18 +175,46 @@ You can apply the interceptor to update or remove query parameters:
175175
{@link examples.HttpProxyExamples#queryInterceptorAdd}
176176
----
177177

178-
You can also refer to {@link io.vertx.httpproxy.interceptors.HeadInterceptorBuilder} for more information.
178+
Query params modifying methods can be invoked several times, operations are applied in the order of configuration.
179+
180+
You can also refer to {@link io.vertx.httpproxy.ProxyInterceptorBuilder} for more information.
179181

180182
==== Body interceptor
181183

182-
You can use body interceptor to create body transformations for common data types, like {@link io.vertx.core.json.JsonObject}:
184+
You can use a {@link io.vertx.httpproxy.BodyTransformer} to create body transformations.
185+
186+
A set of predefined transformations facilitates the creation of a transformer.
187+
188+
[source,java]
189+
----
190+
{@link examples.HttpProxyExamples#bodyTransformer}
191+
----
192+
193+
A body transformer is then turned into a proxy interceptor with the builder:
194+
195+
[source,java]
196+
----
197+
{@link examples.HttpProxyExamples#bodyInterceptorTransformer}
198+
----
199+
200+
{@link io.vertx.httpproxy.BodyTransformers} provides transformation for common data types, like {@link io.vertx.core.json.JsonObject}:
183201

184202
[source,java]
185203
----
186204
{@link examples.HttpProxyExamples#bodyInterceptorJson}
187205
----
188206

189-
Please check the {@link io.vertx.httpproxy.interceptors.BodyTransformer} for other supported transformations.
207+
Most transformations provided in {@link io.vertx.httpproxy.BodyTransformers} are synchronous and buffer bytes. The default
208+
maximum amount of bytes is 256K bytes, you can provide a different amount:
209+
210+
[source,java]
211+
----
212+
{@link examples.HttpProxyExamples#bodyInterceptorJsonMaxBufferedSize}
213+
----
214+
215+
Please check the {@link io.vertx.httpproxy.BodyTransformers} for other supported transformations.
216+
217+
NOTE: you can also implement {@link io.vertx.httpproxy.BodyTransformer} contract to best adapt it to your needs.
190218

191219
==== Interception and WebSocket upgrades
192220

src/main/java/examples/HttpProxyExamples.java

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212
import io.vertx.core.net.SocketAddress;
1313
import io.vertx.httpproxy.*;
1414
import io.vertx.httpproxy.cache.CacheOptions;
15-
import io.vertx.httpproxy.interceptors.BodyInterceptor;
16-
import io.vertx.httpproxy.interceptors.BodyTransformer;
17-
import io.vertx.httpproxy.interceptors.HeadInterceptor;
1815

1916
import java.util.Set;
2017

@@ -111,25 +108,60 @@ public Future<Void> handleProxyResponse(ProxyContext context) {
111108
public void headerInterceptorFilter(HttpProxy proxy, Set<CharSequence> shouldRemove) {
112109
// remove a set of headers
113110
proxy.addInterceptor(
114-
HeadInterceptor.builder().filteringResponseHeaders(shouldRemove).build());
111+
ProxyInterceptor.builder().filteringResponseHeaders(shouldRemove).build());
115112
}
116113

117114
public void queryInterceptorAdd(HttpProxy proxy, String key, String value) {
118115
proxy.addInterceptor(
119-
HeadInterceptor.builder().settingQueryParam(key, value).build());
116+
ProxyInterceptor.builder().settingQueryParam(key, value).build());
117+
}
118+
119+
public void bodyTransformer() {
120+
BodyTransformer transformer = BodyTransformers.transform(
121+
MediaType.APPLICATION_JSON,
122+
MediaType.APPLICATION_OCTET_STREAM,
123+
buffer -> {
124+
// Apply some transformation
125+
return buffer;
126+
}
127+
);
128+
}
129+
130+
public void bodyInterceptorTransformer(HttpProxy proxy, BodyTransformer transformer) {
131+
proxy.addInterceptor(
132+
ProxyInterceptor
133+
.builder()
134+
.transformingResponseBody(transformer)
135+
.build()
136+
);
120137
}
121138

122139
public void bodyInterceptorJson(HttpProxy proxy) {
123140
proxy.addInterceptor(
124-
BodyInterceptor.modifyResponseBody(
125-
BodyTransformer.transformJsonObject(
126-
jsonObject -> removeSomeFields(jsonObject)
127-
)
128-
));
141+
ProxyInterceptor
142+
.builder()
143+
.transformingResponseBody(
144+
BodyTransformers.jsonObject(
145+
jsonObject -> removeSomeFields(jsonObject)
146+
)
147+
).build());
148+
}
149+
150+
public void bodyInterceptorJsonMaxBufferedSize(HttpProxy proxy) {
151+
proxy.addInterceptor(
152+
ProxyInterceptor
153+
.builder()
154+
.transformingResponseBody(
155+
BodyTransformers.jsonObject(
156+
// Maximum amount of buffered bytes
157+
128 * 1024,
158+
jsonObject -> removeSomeFields(jsonObject)
159+
)
160+
).build());
129161
}
130162

131163
public void webSocketInterceptorPath(HttpProxy proxy) {
132-
HeadInterceptor interceptor = HeadInterceptor.builder()
164+
ProxyInterceptor interceptor = ProxyInterceptor.builder()
133165
.addingPathPrefix("/api")
134166
.build();
135167
proxy.addInterceptor(interceptor, true);

src/main/java/io/vertx/httpproxy/Body.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,32 @@ public interface Body {
3131
* @return a reference to this, so the API can be used fluently
3232
*/
3333
static Body body(ReadStream<Buffer> stream, long len) {
34+
return body(stream, len, MediaType.APPLICATION_OCTET_STREAM);
35+
}
36+
37+
static Body body(ReadStream<Buffer> stream, long len, MediaType mediatype) {
38+
return new Body() {
39+
@Override
40+
public String mediaType() {
41+
return mediatype != null ? mediatype.toString() : null;
42+
}
43+
@Override
44+
public long length() {
45+
return len;
46+
}
47+
@Override
48+
public ReadStream<Buffer> stream() {
49+
return stream;
50+
}
51+
};
52+
}
53+
54+
static Body body(ReadStream<Buffer> stream, long len, String mediatype) {
3455
return new Body() {
56+
@Override
57+
public String mediaType() {
58+
return mediatype;
59+
}
3560
@Override
3661
public long length() {
3762
return len;
@@ -52,15 +77,24 @@ public ReadStream<Buffer> stream() {
5277
static Body body(ReadStream<Buffer> stream) {
5378
return body(stream, -1L);
5479
}
55-
80+
81+
static Body body(Buffer buffer) {
82+
return body(buffer, MediaType.APPLICATION_OCTET_STREAM);
83+
}
84+
5685
/**
5786
* Create a new {@code Body} instance.
5887
*
5988
* @param buffer the {@link Buffer} of the body
89+
* @param mediaType the body media type
6090
* @return a reference to this, so the API can be used fluently
6191
*/
62-
static Body body(Buffer buffer) {
92+
static Body body(Buffer buffer, MediaType mediaType) {
6393
return new Body() {
94+
@Override
95+
public String mediaType() {
96+
return mediaType == null ? null : mediaType.toString();
97+
}
6498
@Override
6599
public long length() {
66100
return buffer.length();
@@ -72,6 +106,11 @@ public ReadStream<Buffer> stream() {
72106
};
73107
}
74108

109+
/**
110+
* @return the media type of this body
111+
*/
112+
String mediaType();
113+
75114
/**
76115
*
77116
* Get length of the {@code Body}.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package io.vertx.httpproxy;
2+
3+
import io.vertx.codegen.annotations.GenIgnore;
4+
import io.vertx.codegen.annotations.Unstable;
5+
import io.vertx.codegen.annotations.VertxGen;
6+
import io.vertx.core.Future;
7+
8+
/**
9+
* A synchronous function that transforms an HTTP body entity.
10+
*/
11+
@VertxGen
12+
@Unstable
13+
public interface BodyTransformer {
14+
15+
/**
16+
* @return whether this transformer consumes the {@code mediaType}, {@code mediaType} can be {@code null}
17+
* when the HTTP head does not present a body, the default implementation returns {@code true}
18+
*/
19+
default boolean consumes(MediaType mediaType) {
20+
return true;
21+
}
22+
23+
/**
24+
* @return the media type produced by this transformer, the default implementation returns the same media type
25+
*/
26+
default MediaType produces(MediaType mediaType) {
27+
return mediaType;
28+
}
29+
30+
/**
31+
* Return the future body, transformed.
32+
*
33+
* The default implementation returns the same body.
34+
*
35+
* @param body the body to rewrite
36+
* @return a future of the transformed body
37+
*/
38+
@GenIgnore
39+
default Future<Body> transform(Body body) {
40+
return Future.succeededFuture(body);
41+
}
42+
}

0 commit comments

Comments
 (0)