Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
s#!/bin/bash
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,22 @@ static class ModifyResponseDecorator extends ServerHttpResponseDecorator {
@NonNull
public Mono<Void> writeWith(@NonNull final Publisher<? extends DataBuffer> body) {
modifyResponseHeadersAndStatus();
if (!hasBodyModifications() || !isJsonResponse()) {
if (!hasBodyModifications()) {
return super.writeWith(body);
}
final Mono<DataBuffer> dataBufferMono = DataBufferUtils.join(body);
return dataBufferMono.flatMap(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
return WebFluxResultUtils.result(this.exchange, modifyBody(bytes));
if (isJsonResponse()) {
return WebFluxResultUtils.result(this.exchange, modifyBody(bytes));
}
byte[] modifiedBody = tryModifyBody(bytes);
if (Objects.isNull(modifiedBody)) {
return super.writeWith(Mono.just(this.getDelegate().bufferFactory().wrap(bytes)));
}
return WebFluxResultUtils.result(this.exchange, modifiedBody);
});
}

Expand Down Expand Up @@ -193,5 +200,16 @@ private String modifyBody(final String jsonValue) {
}
return context.jsonString();
}

private byte[] tryModifyBody(final byte[] responseBody) {
try {
String bodyStr = modifyBody(new String(responseBody, StandardCharsets.UTF_8));
LOG.info("the body string {}", bodyStr);
return bodyStr.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
LOG.debug("skip modify response body because response content type is not json", e);
return null;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,21 @@
import org.apache.shenyu.common.dto.RuleData;
import org.apache.shenyu.common.dto.SelectorData;
import org.apache.shenyu.common.dto.convert.rule.impl.ModifyResponseRuleHandle;
import org.apache.shenyu.common.dto.convert.rule.impl.ParamMappingRuleHandle;
import org.apache.shenyu.common.enums.PluginEnum;
import org.apache.shenyu.plugin.api.ShenyuPluginChain;
import org.apache.shenyu.plugin.api.context.ShenyuContext;
import org.apache.shenyu.plugin.api.result.ShenyuResult;
import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
import org.apache.shenyu.plugin.modify.response.handler.ModifyResponsePluginDataHandler;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.reactivestreams.Publisher;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
Expand Down Expand Up @@ -87,6 +92,11 @@ public void setUp() {
exchange.getAttributes().put(Constants.CONTEXT, shenyuContext);
}

@AfterEach
public void tearDown() {
SpringBeanUtils.getInstance().setApplicationContext(null);
}

@Test
public void testDoExecute() {
when(chain.execute(any())).thenReturn(Mono.empty());
Expand Down Expand Up @@ -166,6 +176,28 @@ public void testWriteWithSkipsBodyRulesForNonJsonResponse() {
.verifyComplete();
}

@Test
public void testWriteWithModifiesJsonBodyForNonJsonContentType() {
mockShenyuResult();
final ModifyResponseRuleHandle responseRuleHandle = new ModifyResponseRuleHandle();
final ParamMappingRuleHandle.ParamMapInfo addBodyKey = new ParamMappingRuleHandle.ParamMapInfo();
addBodyKey.setPath("$");
addBodyKey.setKey("added");
addBodyKey.setValue("true");
responseRuleHandle.setAddBodyKeys(Collections.singletonList(addBodyKey));
final ModifyResponsePlugin.ModifyResponseDecorator decorator =
new ModifyResponsePlugin.ModifyResponseDecorator(exchange, responseRuleHandle);
final MockServerHttpResponse response = (MockServerHttpResponse) exchange.getResponse();
response.getHeaders().setContentType(MediaType.TEXT_PLAIN);
final DataBuffer dataBuffer = response.bufferFactory().wrap("{\"value\":true}".getBytes(StandardCharsets.UTF_8));

StepVerifier.create(decorator.writeWith(Mono.just(dataBuffer))).verifyComplete();

StepVerifier.create(response.getBodyAsString())
.expectNext("{\"value\":true,\"added\":\"true\"}")
.verifyComplete();
}

@Test
public void testGetOrder() {
assertEquals(modifyResponsePlugin.getOrder(), PluginEnum.MODIFY_RESPONSE.getCode());
Expand All @@ -180,4 +212,15 @@ public void testNamed() {
public void testSkip() {
assertFalse(modifyResponsePlugin.skip(exchange));
}

private void mockShenyuResult() {
ApplicationContext applicationContext = mock(ApplicationContext.class);
@SuppressWarnings("unchecked")
ShenyuResult<Object> shenyuResult = (ShenyuResult<Object>) mock(ShenyuResult.class);
when(shenyuResult.format(any(ServerWebExchange.class), any())).thenAnswer(invocation -> invocation.getArgument(1));
when(shenyuResult.contentType(any(ServerWebExchange.class), any())).thenReturn(MediaType.APPLICATION_JSON);
when(shenyuResult.result(any(ServerWebExchange.class), any())).thenAnswer(invocation -> invocation.getArgument(1));
when(applicationContext.getBean(ShenyuResult.class)).thenReturn(shenyuResult);
SpringBeanUtils.getInstance().setApplicationContext(applicationContext);
}
}
Loading