Skip to content

Commit d7bec0a

Browse files
committed
First implementation of Filter support in Spring
Still open 1. Support filter annotations 2. Add support for filters in spark
1 parent 06ebfae commit d7bec0a

File tree

22 files changed

+1523
-266
lines changed

22 files changed

+1523
-266
lines changed

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandler.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030
*/
3131
public abstract class LambdaContainerHandler<RequestType, ResponseType, ContainerRequestType, ContainerResponseType> {
3232

33+
//-------------------------------------------------------------
34+
// Constants
35+
//-------------------------------------------------------------
36+
37+
public static final String SERVER_INFO = "aws-serverless-java-container";
38+
3339
//-------------------------------------------------------------
3440
// Variables - Private
3541
//-------------------------------------------------------------
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
5+
* with the License. A copy of the License is located at
6+
*
7+
* http://aws.amazon.com/apache2.0/
8+
*
9+
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
10+
* OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*/
13+
package com.amazonaws.serverless.proxy.internal.servlet;
14+
15+
import java.util.Map;
16+
17+
/**
18+
* This implementation of the <code>FilterChainManager</code> object uses the <code>AwsServletContext</code> object
19+
* to extract a list of <code>FilterHolder</code>s
20+
*/
21+
public class AwsFilterChainManager extends FilterChainManager<AwsServletContext> {
22+
23+
//-------------------------------------------------------------
24+
// Constructors
25+
//-------------------------------------------------------------
26+
27+
/**
28+
* Creates a new FilterChainManager for the given servlet context
29+
* @param context An initialized AwsServletContext object
30+
*/
31+
AwsFilterChainManager(AwsServletContext context) {
32+
super(context);
33+
}
34+
35+
//-------------------------------------------------------------
36+
// Implementation - FilterChainManager
37+
//-------------------------------------------------------------
38+
39+
/**
40+
* Returns the filter holders stored in the <code>AwsServletContext</code> object
41+
* @return The map of filter holders
42+
*/
43+
protected Map<String, FilterHolder> getFilterHolders() {
44+
return servletContext.getFilterHolders();
45+
}
46+
}
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/*
2+
* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
5+
* with the License. A copy of the License is located at
6+
*
7+
* http://aws.amazon.com/apache2.0/
8+
*
9+
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
10+
* OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*/
13+
package com.amazonaws.serverless.proxy.internal.servlet;
14+
15+
import com.amazonaws.services.lambda.runtime.Context;
16+
17+
import javax.servlet.AsyncContext;
18+
import javax.servlet.DispatcherType;
19+
import javax.servlet.ServletContext;
20+
import javax.servlet.http.Cookie;
21+
import javax.servlet.http.HttpServletRequest;
22+
import javax.servlet.http.HttpSession;
23+
import java.io.UnsupportedEncodingException;
24+
import java.net.URLEncoder;
25+
import java.nio.charset.StandardCharsets;
26+
import java.util.*;
27+
28+
/**
29+
* Base HttpServletRequest object. This object exposes some utility methods to work with request values such as headers
30+
* and query string parameters. New implementations of <code>HttpServletRequest</code> can extend this class to reuse
31+
* the utility methods
32+
*/
33+
public abstract class AwsHttpServletRequest implements HttpServletRequest {
34+
//-------------------------------------------------------------
35+
// Constants
36+
//-------------------------------------------------------------
37+
38+
static final String HEADER_KEY_VALUE_SEPARATOR = "=";
39+
static final String HEADER_VALUE_SEPARATOR = ";";
40+
static final String FORM_DATA_SEPARATOR = "&";
41+
static final String DEFAULT_CHARACTER_ENCODING = "UTF-8";
42+
static final String HEADER_DATE_FORMAT = "EEE, d MMM yyyy HH:mm:ss z";
43+
static final String ENCODING_VALUE_KEY = "charset";
44+
45+
// We need this to pickup the protocol from the CloudFront header since Lambda doesn't receive this
46+
// information from anywhere else
47+
static final String CF_PROTOCOL_HEADER_NAME = "CloudFront-Forwarded-Proto";
48+
49+
//-------------------------------------------------------------
50+
// Variables - Private
51+
//-------------------------------------------------------------
52+
53+
private Context lamdaContext;
54+
private DispatcherType dispatcherType;
55+
private Map<String, Object> attributes;
56+
57+
//-------------------------------------------------------------
58+
// Constructors
59+
//-------------------------------------------------------------
60+
61+
/**
62+
* Protected constructors for implemnenting classes. This should be called first with the context received from
63+
* AWS Lambda
64+
* @param lambdaContext The Lambda function context. This object is used for utility methods such as log
65+
*/
66+
AwsHttpServletRequest(Context lambdaContext) {
67+
lamdaContext = lambdaContext;
68+
attributes = new HashMap<>();
69+
70+
// TODO: We are setting this to request by default
71+
dispatcherType = DispatcherType.REQUEST;
72+
}
73+
74+
//-------------------------------------------------------------
75+
// Methods - Protected
76+
//-------------------------------------------------------------
77+
78+
/**
79+
* Given the Cookie header value, parses it and creates a Cookie object
80+
* @param headerValue The string value of the HTTP Cookie header
81+
* @return An array of Cookie objects from the header
82+
*/
83+
protected Cookie[] parseCookies(String headerValue) {
84+
List<Cookie> output = new ArrayList<>();
85+
86+
for (AbstractMap.SimpleEntry<String, String> entry : this.parseHeaderValue(headerValue)) {
87+
if (entry.getKey() != null) {
88+
output.add(new Cookie(entry.getKey(), entry.getValue()));
89+
}
90+
}
91+
Cookie[] returnValue = new Cookie[output.size()];
92+
return output.toArray(returnValue);
93+
}
94+
95+
protected String readPathInfo(String path, String resource) {
96+
// TODO: Implement
97+
return "/";
98+
}
99+
100+
protected String readPathTranslated(String path) {
101+
// TODO: Implement
102+
return path;
103+
}
104+
105+
/**
106+
* Given a map of key/values query string parameters from API Gateway, creates a query string as it would have
107+
* been in the original url.
108+
* @param parameters A Map<String, String> of query string parameters
109+
* @return The generated query string for the URI
110+
*/
111+
protected String generateQueryString(Map<String, String> parameters) {
112+
String params = null;
113+
if (parameters != null && parameters.size() > 0) {
114+
params = "";
115+
for (String key : parameters.keySet()) {
116+
String separator = params.equals("") ? "?" : "&";
117+
String queryStringKey = key;
118+
String queryStringValue = parameters.get(key);
119+
try {
120+
// if they were URLDecoded along the way we should re-encode them for the URI
121+
if (!URLEncoder.encode(queryStringKey, StandardCharsets.UTF_8.name()).equals(key)) {
122+
queryStringKey = URLEncoder.encode(queryStringKey, StandardCharsets.UTF_8.name());
123+
}
124+
if (!URLEncoder.encode(queryStringValue, StandardCharsets.UTF_8.name()).equals(queryStringValue)) {
125+
queryStringValue = URLEncoder.encode(queryStringValue, StandardCharsets.UTF_8.name());
126+
}
127+
} catch (UnsupportedEncodingException e) {
128+
// TODO: Should we stop for the exception?
129+
lamdaContext.getLogger().log("Could not URLEncode: " + queryStringKey);
130+
e.printStackTrace();
131+
}
132+
params += separator + queryStringKey + "=" + queryStringValue;
133+
}
134+
}
135+
136+
return params;
137+
}
138+
139+
/**
140+
* Generic method to parse an HTTP header value and split it into a list of key/values for all its components.
141+
* When the property in the header does not specify a key the key field in the output pair is null and only the value
142+
* is populated. For example, The header <code>Accept: application/json; application/xml</code> will contain two
143+
* key value pairs with key null and the value set to application/json and application/xml respectively.
144+
*
145+
* @param headerContent The string value for the HTTP header
146+
* @return A list of SimpleMapEntry objects with all of the possible values for the header.
147+
*/
148+
protected List<AbstractMap.SimpleEntry<String, String>> parseHeaderValue(String headerContent) {
149+
List<AbstractMap.SimpleEntry<String, String>> values = new ArrayList<>();
150+
if (headerContent != null) {
151+
for (String kv : headerContent.split(HEADER_VALUE_SEPARATOR)) {
152+
String[] kvSplit = kv.split(HEADER_KEY_VALUE_SEPARATOR);
153+
154+
if (kvSplit.length != 2) {
155+
values.add(new AbstractMap.SimpleEntry<>(null, kv.trim()));
156+
} else {
157+
values.add(new AbstractMap.SimpleEntry<>(kvSplit[0].trim(), kvSplit[1].trim()));
158+
}
159+
}
160+
}
161+
return values;
162+
}
163+
164+
//-------------------------------------------------------------
165+
// Implementation - HttpServletRequest
166+
//-------------------------------------------------------------
167+
168+
@Override
169+
public String getRequestedSessionId() {
170+
// TODO: Throw not implemented
171+
return null;
172+
}
173+
174+
@Override
175+
public HttpSession getSession(boolean b) {
176+
return null;
177+
}
178+
179+
180+
@Override
181+
public HttpSession getSession() {
182+
return null;
183+
}
184+
185+
186+
@Override
187+
public String changeSessionId() {
188+
return null;
189+
}
190+
191+
192+
@Override
193+
public boolean isRequestedSessionIdValid() {
194+
return false;
195+
}
196+
197+
198+
@Override
199+
public boolean isRequestedSessionIdFromCookie() {
200+
return false;
201+
}
202+
203+
204+
@Override
205+
public boolean isRequestedSessionIdFromURL() {
206+
return false;
207+
}
208+
209+
210+
@Override
211+
public boolean isRequestedSessionIdFromUrl() {
212+
return false;
213+
}
214+
215+
@Override
216+
public Object getAttribute(String s) {
217+
return attributes.get(s);
218+
}
219+
220+
@Override
221+
public Enumeration<String> getAttributeNames() {
222+
return Collections.enumeration(attributes.keySet());
223+
}
224+
225+
@Override
226+
public void setAttribute(String s, Object o) {
227+
attributes.put(s, o);
228+
}
229+
230+
231+
@Override
232+
public void removeAttribute(String s) {
233+
attributes.remove(s);
234+
}
235+
236+
@Override
237+
public String getServerName() {
238+
return "lambda.amazonaws.com";
239+
}
240+
241+
242+
@Override
243+
public int getServerPort() {
244+
return 0;
245+
}
246+
247+
@Override
248+
public String getLocalName() {
249+
return "lambda.amazonaws.com";
250+
}
251+
252+
253+
@Override
254+
public String getLocalAddr() {
255+
return null;
256+
}
257+
258+
259+
@Override
260+
public int getLocalPort() {
261+
return 0;
262+
}
263+
264+
@Override
265+
public boolean isAsyncStarted() {
266+
return false;
267+
}
268+
269+
270+
@Override
271+
public boolean isAsyncSupported() {
272+
return false;
273+
}
274+
275+
276+
@Override
277+
public AsyncContext getAsyncContext() {
278+
return null;
279+
}
280+
281+
@Override
282+
public ServletContext getServletContext() {
283+
return AwsServletContext.getInstance(lamdaContext);
284+
}
285+
286+
@Override
287+
public DispatcherType getDispatcherType() {
288+
return dispatcherType;
289+
}
290+
}

0 commit comments

Comments
 (0)