Skip to content

Commit

Permalink
Upgrade commmons IO & lang3 lib versions
Browse files Browse the repository at this point in the history
Request to destination: option to Header overwrite
  • Loading branch information
domivds committed Feb 7, 2025
1 parent 4750623 commit 227bc38
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 13 deletions.
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ cognizone:
- key: Access-Control-Allow-Headers
value: "*"
filter: "#{[request].getHeader('Origin') != null}"
request-set:
- key: X-Send-This-As-Header
value: "someValue"
```
That's it, you're all set.
Expand All @@ -37,15 +40,28 @@ If you return a non-null value, that value with be used to send the response and
At the moment following HTTP methods are supported: GET, POST, PUT, DELETE

### Headers
Follow headers will be passed from the original request:
#### Pass from original request
Follow headers will be passed from the original request to the destination:
- Accept
- Accept-Language
- Content-Type
- User-Agent

#### Add extra fixed headers

Using configuration `.headers.request-set` you can pass additional headers to the destination server.
This can for example be used to set basic authentication headers.

#### Send back to caller
After the proxied request, following response headers will be sent back to the client:
- Content-Type

Using configuration `.headers.response-set` you can also set extra headers to send back to the caller.
The setting of these extra headers can be ignored based on filter which is evaluated as a SpEL expression.

#### Example info
In the example above `Access-Control-Allow-Headers: *` will be added to the response of secondRoute in case the filter matches.
The filter should be a spel expression that returns a boolean.
In this example (`#{[request].getHeader('Origin') != null}`) the header will be set if the original request contains an `Origin` header.

The proxying will also send the header `X-Send-This-As-Header` with value `someValue` to the destination server.
5 changes: 2 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
buildscript {
ext {
commonsIoVersion = "2.11.0"
commonsLang3Version = "3.12.0"
commonsIoVersion = "2.18.0"
commonsLang3Version = "3.17.0"
httpclientVersion = "4.5.13"
jsr305Version = "3.0.2"
junitVersion = "5.9.2"
Expand Down Expand Up @@ -216,7 +216,6 @@ project("vinz-clortho") {
implementation("javax.inject:javax.inject:1") //if we don't have this dependency the publication build does not work???
implementation 'org.springframework.boot:spring-boot-starter-web'

implementation "com.google.code.findbugs:jsr305"
implementation "commons-io:commons-io"
implementation "org.apache.commons:commons-lang3"
implementation "org.apache.httpcomponents:httpclient"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public static class Route {
@Data
public static class Headers {
private List<Header> responseSet = new ArrayList<>();
private List<Header> requestSet = new ArrayList<>();
}

@Data
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package cogni.zone.vinzclortho;

import jakarta.annotation.Nullable;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
Expand All @@ -23,15 +32,6 @@
import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher;

import jakarta.annotation.Nullable;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -164,6 +164,11 @@ private HttpRequestBase createRequest(BiFunction<String, HttpServletRequest, Htt
request.addHeader(headersToPass, headerValue);
}
}

route.getHeaders()
.getRequestSet()
.forEach(headerToSet -> request.addHeader(headerToSet.getKey(), headerToSet.getValue()));

return request;
}

Expand Down
44 changes: 44 additions & 0 deletions vinz-clortho/src/test/java/cogni/zone/vinzclortho/HeaderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
Expand All @@ -14,9 +15,12 @@

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
Expand Down Expand Up @@ -72,8 +76,48 @@ public void headerTest2() throws Exception {
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.header().string("X-Bla1", "value1"))
.andExpect(MockMvcResultMatchers.header().string("X-Bla2", "value2"));
}

@Test
public void header_setOverwrites() throws Exception {
CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
CloseableHttpResponse httpResponse = mock(CloseableHttpResponse.class);
StatusLine statusLine = mock(StatusLine.class);
HttpEntity httpEntity = mock(HttpEntity.class);
when(httpClientFactory.create()).thenReturn(httpClient);
when(httpClient.execute(any(HttpPost.class))).thenReturn(httpResponse);
when(statusLine.getStatusCode()).thenReturn(200);
when(httpResponse.getStatusLine()).thenReturn(statusLine);
when(httpResponse.getHeaders(any())).thenReturn(new Header[0]);
when(httpResponse.getEntity()).thenReturn(httpEntity);
when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream("IT".getBytes(StandardCharsets.UTF_8)));


MockHttpServletRequestBuilder testPostRequest = post("/proxy/addHeader/test")
.servletPath("/proxy/addHeader/test")
.header("X-Bla-in", "bla") //config says, if we have in header X-Bla-in, then return X-Bla2
.header("X-Send-This-As-Header", "thisShouldBeOverwritten")
.header("User-Agent", "broumbroumserver");
mockMvc.perform(testPostRequest)
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.header().string("X-Bla1", "value1"))
.andExpect(MockMvcResultMatchers.header().string("X-Bla2", "value2"));

AtomicBoolean realRequestBodyChecked = new AtomicBoolean(false);
verify(httpClient).execute(argThat(thaRealRequest -> {
if (realRequestBodyChecked.getAndSet(true)) return true; //called twice for some reason, just check once
Assertions.assertThat(thaRealRequest).isExactlyInstanceOf(HttpPost.class);

Header firstHeader = thaRealRequest.getFirstHeader("X-Send-This-As-Header");
Assertions.assertThat(firstHeader).isNotNull();
Assertions.assertThat(firstHeader.getValue()).isEqualTo("someValue");

Header agentHeader = thaRealRequest.getFirstHeader("User-Agent");
Assertions.assertThat(agentHeader).isNotNull();
Assertions.assertThat(agentHeader.getValue()).isEqualTo("broumbroumserver");

return true;
}));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ cognizone:
- key: X-Bla2
value: value2
filter: "#{[request].getHeader('X-Bla-in') != null}"
request-set:
- key: X-Send-This-As-Header
value: someValue

0 comments on commit 227bc38

Please sign in to comment.