Skip to content

Commit

Permalink
Merge pull request #755 from olegz/GH-754
Browse files Browse the repository at this point in the history
GH-754 Fix request parameter parsing
  • Loading branch information
deki authored Jan 30, 2024
2 parents 58b296f + 88f6e4a commit 028b179
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.function.serverless.web.ServerlessHttpServletRequest;
import org.springframework.cloud.function.serverless.web.ServerlessMVC;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.MultiValueMapAdapter;
import org.springframework.util.StringUtils;
Expand Down Expand Up @@ -109,6 +113,9 @@ private static HttpServletRequest generateRequest1(String request, Context lambd
AwsProxyRequest v1Request = readValue(request, AwsProxyRequest.class, mapper);

ServerlessHttpServletRequest httpRequest = new ServerlessHttpServletRequest(servletContext, v1Request.getHttpMethod(), v1Request.getPath());

populateQueryStringparameters(v1Request.getQueryStringParameters(), httpRequest);

if (v1Request.getMultiValueHeaders() != null) {
MultiValueMapAdapter headers = new MultiValueMapAdapter(v1Request.getMultiValueHeaders());
httpRequest.setHeaders(headers);
Expand All @@ -128,16 +135,21 @@ private static HttpServletRequest generateRequest1(String request, Context lambd
securityWriter.writeSecurityContext(v1Request, lambdaContext));
return httpRequest;
}



@SuppressWarnings({ "rawtypes", "unchecked" })
private static HttpServletRequest generateRequest2(String request, Context lambdaContext,
SecurityContextWriter securityWriter, ObjectMapper mapper, ServletContext servletContext) {
HttpApiV2ProxyRequest v2Request = readValue(request, HttpApiV2ProxyRequest.class, mapper);


ServerlessHttpServletRequest httpRequest = new ServerlessHttpServletRequest(servletContext,
v2Request.getRequestContext().getHttp().getMethod(), v2Request.getRequestContext().getHttp().getPath());
populateQueryStringparameters(v2Request.getQueryStringParameters(), httpRequest);

v2Request.getHeaders().forEach(httpRequest::setHeader);

if (StringUtils.hasText(v2Request.getBody())) {
httpRequest.setContentType("application/json");
httpRequest.setContent(v2Request.getBody().getBytes(StandardCharsets.UTF_8));
Expand All @@ -151,6 +163,14 @@ private static HttpServletRequest generateRequest2(String request, Context lambd
return httpRequest;
}

private static void populateQueryStringparameters(Map<String, String> requestParameters, ServerlessHttpServletRequest httpRequest) {
if (!CollectionUtils.isEmpty(requestParameters)) {
for (Entry<String, String> entry : requestParameters.entrySet()) {
httpRequest.setParameter(entry.getKey(), entry.getValue());
}
}
}

private static <T> T readValue(String json, Class<T> clazz, ObjectMapper mapper) {
try {
return mapper.readValue(json, clazz);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.cloud.function.serverless.web.ServerlessServletContext;
import org.springframework.util.CollectionUtils;

import com.amazonaws.serverless.proxy.spring.servletapp.MessageData;
Expand Down Expand Up @@ -72,12 +73,16 @@ public class SpringDelegatingLambdaContainerHandlerTests {
+ " },\n"
+ " \"queryStringParameters\": {\n"
+ " \"abc\": \"xyz\",\n"
+ " \"name\": \"Ricky\",\n"
+ " \"foo\": \"baz\"\n"
+ " },\n"
+ " \"multiValueQueryStringParameters\": {\n"
+ " \"abc\": [\n"
+ " \"xyz\"\n"
+ " ],\n"
+ " \"name\": [\n"
+ " \"Ricky\"\n"
+ " ],\n"
+ " \"foo\": [\n"
+ " \"bar\",\n"
+ " \"baz\"\n"
Expand Down Expand Up @@ -124,7 +129,7 @@ public class SpringDelegatingLambdaContainerHandlerTests {
" \"version\": \"2.0\",\n" +
" \"routeKey\": \"$default\",\n" +
" \"rawPath\": \"/my/path\",\n" +
" \"rawQueryString\": \"parameter1=value1&parameter1=value2&parameter2=value\",\n" +
" \"rawQueryString\": \"parameter1=value1&parameter1=value2&name=Ricky&parameter2=value\",\n" +
" \"cookies\": [\n" +
" \"cookie1\",\n" +
" \"cookie2\"\n" +
Expand All @@ -135,6 +140,7 @@ public class SpringDelegatingLambdaContainerHandlerTests {
" },\n" +
" \"queryStringParameters\": {\n" +
" \"parameter1\": \"value1,value2\",\n" +
" \"name\": \"Ricky\",\n" +
" \"parameter2\": \"value\"\n" +
" },\n" +
" \"requestContext\": {\n" +
Expand Down Expand Up @@ -202,6 +208,22 @@ public static Collection<String> data() {
return Arrays.asList(new String[]{API_GATEWAY_EVENT, API_GATEWAY_EVENT_V2});
}

@MethodSource("data")
@ParameterizedTest
public void validateComplesrequest(String jsonEvent) throws Exception {
initServletAppTest();
InputStream targetStream = new ByteArrayInputStream(this.generateHttpRequest(jsonEvent, "POST",
"/foo/male/list/24", "{\"name\":\"bob\"}", null));
ByteArrayOutputStream output = new ByteArrayOutputStream();
handler.handleRequest(targetStream, output, null);
Map result = mapper.readValue(output.toString(StandardCharsets.UTF_8), Map.class);
assertEquals(200, result.get("statusCode"));
String[] respponseBody = ((String) result.get("body")).split("/");
assertEquals("male", respponseBody[0]);
assertEquals("24", respponseBody[1]);
assertEquals("Ricky", respponseBody[2]);
}

@MethodSource("data")
@ParameterizedTest
public void testAsyncPost(String jsonEvent) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.amazonaws.serverless.proxy.spring.servletapp;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication(exclude = {
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration.class,
Expand All @@ -14,5 +18,15 @@
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration.class
})
@Import(MessageController.class)
@RestController
public class ServletApplication {

@RequestMapping(path = "/foo/{gender}/list/{age}", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String complexRequest(
@PathVariable("gender") String gender,
@PathVariable("age") String age,
@RequestParam("name") String name
) {
return gender + "/" + age + "/" + name;
}
}
19 changes: 18 additions & 1 deletion samples/springboot3/alt-pet-store/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,21 @@ PetStoreApi - URL for application https://xxxxxxxxxx.execute-api.us-w
---------------------------------------------------------------------------------------------------------
$ curl https://xxxxxxxxxx.execute-api.us-west-2.amazonaws.com/pets
```
```

You can also try a complex request passing both path and request parameters to complex endpoint such as this:


```
@RequestMapping(path = "/foo/{gender}/bar/{age}", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String complexRequest(@RequestBody String body,
@PathVariable("gender") String gender,
@PathVariable("age") String age,
@RequestParam("name") String name
)
```
For example.

```
curl -d '{"key1":"value1", "key2":"value2"}' -H "Content-Type: application/json" -X POST https://zuhd709386.execute-api.us-east-2.amazonaws.com/foo/male/bar/25?name=Ricky
```
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import com.amazonaws.serverless.sample.springboot3.model.Pet;
import com.amazonaws.serverless.sample.springboot3.model.PetData;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
Expand All @@ -32,6 +34,7 @@
@RestController
@EnableWebMvc
public class PetsController {

@RequestMapping(path = "/pets", method = RequestMethod.POST)
public Pet createPet(@RequestBody Pet newPet) {
if (newPet.getName() == null || newPet.getBreed() == null) {
Expand Down Expand Up @@ -73,5 +76,15 @@ public Pet listPets() {
newPet.setName(PetData.getRandomName());
return newPet;
}

@RequestMapping(path = "/foo/{gender}/bar/{age}", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String complexRequest(@RequestBody String body,
@PathVariable("gender") String gender,
@PathVariable("age") String age,
@RequestParam("name") String name
) {
System.out.println("Body: " + body + " - " + gender + "/" + age + "/" + name);
return gender + "/" + age + "/" + name;
}

}

0 comments on commit 028b179

Please sign in to comment.