Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d5421c2

Browse files
authored
feat: support for getting upstream response body (#200)
1 parent d2fe045 commit d5421c2

File tree

11 files changed

+302
-65
lines changed

11 files changed

+302
-65
lines changed

ci/apisix/config.yaml

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,22 @@
1515
# limitations under the License.
1616
#
1717

18-
19-
apisix:
20-
allow_admin:
21-
- 0.0.0.0/0
22-
enable_control: true
23-
control:
24-
ip: "0.0.0.0"
25-
port: 9092
26-
admin_key:
27-
- name: admin
28-
key: edd1c9f034335f136f87ad84b625c8f1
29-
role: admin
30-
etcd:
31-
host:
32-
- http://etcd:2379
33-
prefix: "/apisix"
34-
timeout: 30
18+
deployment:
19+
role: traditional
20+
role_traditional:
21+
config_provider: etcd
22+
admin:
23+
admin_key:
24+
- name: admin
25+
key: edd1c9f034335f136f87ad84b625c8f1 # using fixed API token has security risk, please update it when you deploy to production environment
26+
role: admin
27+
allow_admin:
28+
- 0.0.0.0/0
29+
etcd:
30+
host:
31+
- "http://etcd:2379"
32+
prefix: "/apisix"
33+
timeout: 30
3534
ext-plugin:
3635
path_for_test: /tmp/runner.sock
3736
nginx_config:

ci/docker-compose.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ services:
3131
- "9180:9180/tcp"
3232
- "9091:9091/tcp"
3333
- "9443:9443/tcp"
34-
- "9092:9092/tcp"
3534
networks:
3635
apisix:
3736

docs/en/latest/development.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ and you can also set the `PostResponse` to override the origin upstream response
159159
* request.getConfig()
160160
* request.getUpstreamHeaders()
161161
* request.getUpstreamStatusCode()
162+
* request.getBody()
162163

163164
##### PostResponse
164165

docs/en/latest/installation-guide.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Prerequisites
3434
-------------
3535

3636
* JDK 11
37-
* APISIX 2.15.0
37+
* APISIX master branch
3838
* Refer to [Debug](how-it-works.md#debug) to build the debug environment.
3939

4040
Install

runner-core/src/main/java/org/apache/apisix/plugin/runner/handler/RpcCallHandler.java

Lines changed: 86 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public class RpcCallHandler extends SimpleChannelInboundHandler<A6Request> {
5757
private final Logger logger = LoggerFactory.getLogger(RpcCallHandler.class);
5858

5959
private final static String EXTRA_INFO_REQ_BODY_KEY = "request_body";
60+
private final static String EXTRA_INFO_RESP_BODY_KEY = "response_body";
6061

6162
private final Cache<Long, A6Conf> cache;
6263

@@ -106,6 +107,62 @@ protected void channelRead0(ChannelHandlerContext ctx, A6Request request) {
106107
}
107108
}
108109

110+
private Boolean[] fetchExtraInfo(ChannelHandlerContext ctx, PluginFilterChain chain) {
111+
// fetch the nginx variables
112+
Set<String> varKeys = new HashSet<>();
113+
boolean requiredReqBody = false;
114+
boolean requiredVars = false;
115+
boolean requiredRespBody = false;
116+
117+
for (PluginFilter filter : chain.getFilters()) {
118+
Collection<String> vars = filter.requiredVars();
119+
if (!CollectionUtils.isEmpty(vars)) {
120+
varKeys.addAll(vars);
121+
requiredVars = true;
122+
}
123+
124+
if (filter.requiredBody() != null && filter.requiredBody()) {
125+
requiredReqBody = true;
126+
}
127+
128+
if (filter.requiredRespBody() != null && filter.requiredRespBody()) {
129+
requiredRespBody = true;
130+
}
131+
}
132+
133+
// fetch the nginx vars
134+
if (requiredVars) {
135+
for (String varKey : varKeys) {
136+
boolean offer = queue.offer(varKey);
137+
if (!offer) {
138+
logger.error("queue is full");
139+
errorHandle(ctx, Code.SERVICE_UNAVAILABLE);
140+
}
141+
ExtraInfoRequest extraInfoRequest = new ExtraInfoRequest(varKey, null, null);
142+
ChannelFuture future = ctx.writeAndFlush(extraInfoRequest);
143+
future.addListeners(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
144+
}
145+
}
146+
147+
// fetch the request body
148+
if (requiredReqBody) {
149+
queue.offer(EXTRA_INFO_REQ_BODY_KEY);
150+
ExtraInfoRequest extraInfoRequest = new ExtraInfoRequest(null, true, null);
151+
ChannelFuture future = ctx.writeAndFlush(extraInfoRequest);
152+
future.addListeners(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
153+
}
154+
155+
// fetch the response body
156+
if (requiredRespBody) {
157+
queue.offer(EXTRA_INFO_RESP_BODY_KEY);
158+
ExtraInfoRequest extraInfoRequest = new ExtraInfoRequest(null, null, true);
159+
ChannelFuture future = ctx.writeAndFlush(extraInfoRequest);
160+
future.addListeners(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
161+
}
162+
163+
return new Boolean[]{requiredVars, requiredReqBody, requiredRespBody};
164+
}
165+
109166
private void handleHttpRespCall(ChannelHandlerContext ctx, PostRequest request) {
110167
cleanCtx();
111168

@@ -129,7 +186,14 @@ private void handleHttpRespCall(ChannelHandlerContext ctx, PostRequest request)
129186
return;
130187
}
131188

132-
doPostFilter(ctx);
189+
Boolean[] result = fetchExtraInfo(ctx, chain);
190+
if (Objects.isNull(result)) {
191+
return;
192+
}
193+
if (!result[0] && !result[2]) {
194+
// no need to fetch extra info
195+
doPostFilter(ctx);
196+
}
133197
}
134198

135199
private void doPostFilter(ChannelHandlerContext ctx) {
@@ -141,6 +205,7 @@ private void doPostFilter(ChannelHandlerContext ctx) {
141205
}
142206

143207
postReq.initCtx(conf.getConfig());
208+
postReq.setVars(nginxVars);
144209

145210
PluginFilterChain chain = conf.getChain();
146211
chain.postFilter(postReq, postResp);
@@ -159,12 +224,24 @@ private void handleExtraInfo(ChannelHandlerContext ctx, ExtraInfoResponse reques
159224
}
160225

161226
if (EXTRA_INFO_REQ_BODY_KEY.equals(varsKey)) {
162-
currReq.setBody(result);
163-
} else {
227+
if (!Objects.isNull(currReq)) {
228+
currReq.setBody(result);
229+
}
230+
} else if (EXTRA_INFO_RESP_BODY_KEY.equals(varsKey)) {
231+
if (!Objects.isNull(postReq)) {
232+
postReq.setBody(result);
233+
}
234+
}
235+
else {
164236
nginxVars.put(varsKey, result);
165237
}
238+
166239
if (queue.isEmpty()) {
167-
doFilter(ctx);
240+
if (currReq != null) {
241+
doFilter(ctx);
242+
} else if (postReq != null) {
243+
doPostFilter(ctx);
244+
}
168245
}
169246
}
170247

@@ -215,47 +292,12 @@ private void handleHttpReqCall(ChannelHandlerContext ctx, HttpRequest request) {
215292
return;
216293
}
217294

218-
// fetch the nginx variables
219-
Set<String> varKeys = new HashSet<>();
220-
boolean requiredBody = false;
221-
boolean requiredVars = false;
222-
223-
for (PluginFilter filter : chain.getFilters()) {
224-
Collection<String> vars = filter.requiredVars();
225-
if (!CollectionUtils.isEmpty(vars)) {
226-
varKeys.addAll(vars);
227-
requiredVars = true;
228-
}
229-
230-
if (filter.requiredBody() != null && filter.requiredBody()) {
231-
requiredBody = true;
232-
}
233-
}
234-
235-
if (varKeys.size() > 0) {
236-
for (String varKey : varKeys) {
237-
boolean offer = queue.offer(varKey);
238-
if (!offer) {
239-
logger.error("queue is full");
240-
errorHandle(ctx, Code.SERVICE_UNAVAILABLE);
241-
return;
242-
}
243-
ExtraInfoRequest extraInfoRequest = new ExtraInfoRequest(varKey, null);
244-
ChannelFuture future = ctx.writeAndFlush(extraInfoRequest);
245-
future.addListeners(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
246-
}
247-
}
248-
249-
// fetch the request body
250-
if (requiredBody) {
251-
queue.offer(EXTRA_INFO_REQ_BODY_KEY);
252-
ExtraInfoRequest extraInfoRequest = new ExtraInfoRequest(null, true);
253-
ChannelFuture future = ctx.writeAndFlush(extraInfoRequest);
254-
future.addListeners(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
295+
Boolean[] result = fetchExtraInfo(ctx, chain);
296+
if (Objects.isNull(result)) {
297+
return;
255298
}
256-
257-
// no need to fetch the nginx variables or request body, just do filter
258-
if (!requiredBody && !requiredVars) {
299+
if (!result[0] && !result[1]) {
300+
// no need to fetch extra info
259301
doFilter(ctx);
260302
}
261303
}

runner-plugin-sdk/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
<dependency>
3737
<groupId>io.github.api7</groupId>
3838
<artifactId>A6</artifactId>
39-
<version>0.5.0-RELEASE</version>
39+
<version>0.6.0-RELEASE</version>
4040
</dependency>
4141

4242
<dependency>

runner-plugin-sdk/src/main/java/org/apache/apisix/plugin/runner/ExtraInfoRequest.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.flatbuffers.FlatBufferBuilder;
2121
import io.github.api7.A6.ExtraInfo.Info;
2222
import io.github.api7.A6.ExtraInfo.ReqBody;
23+
import io.github.api7.A6.ExtraInfo.RespBody;
2324
import io.github.api7.A6.PrepareConf.Req;
2425

2526
import java.nio.ByteBuffer;
@@ -30,9 +31,12 @@ public class ExtraInfoRequest implements A6Response {
3031

3132
private final Boolean reqBody;
3233

33-
public ExtraInfoRequest(String var, Boolean reqBody) {
34+
private final Boolean reqRespBody;
35+
36+
public ExtraInfoRequest(String var, Boolean reqBody, Boolean reqRespBody) {
3437
this.var = var;
3538
this.reqBody = reqBody;
39+
this.reqRespBody = reqRespBody;
3640
}
3741

3842
@Override
@@ -53,6 +57,12 @@ public ByteBuffer encode() {
5357
buildExtraInfo(reqBodyReq, Info.ReqBody, builder);
5458
}
5559

60+
if (this.reqRespBody != null && this.reqRespBody) {
61+
io.github.api7.A6.ExtraInfo.RespBody.startRespBody(builder);
62+
int reqBodyResp = RespBody.endRespBody(builder);
63+
buildExtraInfo(reqBodyResp, Info.RespBody, builder);
64+
}
65+
5666
builder.finish(Req.endReq(builder));
5767
return builder.dataBuffer();
5868
}

runner-plugin-sdk/src/main/java/org/apache/apisix/plugin/runner/PostRequest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io.github.api7.A6.HTTPRespCall.Req;
2121
import io.github.api7.A6.TextEntry;
2222
import org.apache.apisix.plugin.runner.filter.PluginFilter;
23+
import org.springframework.util.CollectionUtils;
2324

2425
import java.nio.ByteBuffer;
2526
import java.util.HashMap;
@@ -37,6 +38,10 @@ public class PostRequest implements A6Request {
3738

3839
private Integer status;
3940

41+
private String body;
42+
43+
private Map<String, String> vars;
44+
4045
public PostRequest(Req req) {
4146
this.req = req;
4247
}
@@ -87,4 +92,23 @@ public Integer getUpstreamStatusCode() {
8792
}
8893
return status;
8994
}
95+
96+
public void setBody(String body) {
97+
this.body = body;
98+
}
99+
100+
public String getBody() {
101+
return body;
102+
}
103+
104+
public String getVars(String key) {
105+
if (CollectionUtils.isEmpty(vars)) {
106+
return null;
107+
}
108+
return vars.get(key);
109+
}
110+
111+
public void setVars(Map<String, String> vars) {
112+
this.vars = vars;
113+
}
90114
}

runner-plugin-sdk/src/main/java/org/apache/apisix/plugin/runner/filter/PluginFilter.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,14 @@ default List<String> requiredVars() {
6767
default Boolean requiredBody() {
6868
return false;
6969
}
70+
71+
/**
72+
* need response body of upstream server in plugins or not
73+
*
74+
* @return true if need response body
75+
*/
76+
default Boolean requiredRespBody() {
77+
return false;
78+
}
7079
}
7180

0 commit comments

Comments
 (0)