diff --git a/README.md b/README.md
index babff70..c156138 100644
--- a/README.md
+++ b/README.md
@@ -564,6 +564,58 @@ TODO
TODO
+## Use in your application server
+
+If you don't like the embedded server, you can use any application server which support servlet filter.
+
+First exclude jetty in your pom.xml
+
+```xml
+
+ net.code-story
+ http
+ 1.31
+
+
+ org.eclipse.jetty
+ jetty-server
+
+
+ org.eclipse.jetty
+ jetty-servlet
+
+
+
+```
+
+Then declare the filter in your web.xml with your class for configuration :
+```xml
+
+ codestoryfilter
+ net.codestory.http.WebServer
+
+ configClass
+ com.mycompany.ConfigClass
+
+
+
+
+ codestoryfilter
+ *
+
+```
+
+The class pass throw the parameter configClass must implement WebServerConfig, here is an exemple :
+```java
+public class ConfigClass implements WebServerConfig {
+ @Override
+ public void configure(WebServer webServer) {
+ webServer.configure(routes ->
+ routes.get("/hello", "Hello World"));
+ }
+}
+```
+
# Deploy on Maven Central
Build the release:
@@ -596,7 +648,6 @@ Synchro to Maven Central is done hourly.
+ Cleanup Payload class. Make Payload immutable?
+ Auto reload meme sans les lambda avec capture de variables locales
+ Singletons qui utilise les annotations standards
- + Remplacer Simple par un Servlet Filter qui fonctionne par defaut sur un Jetty Http
+ Help use local storage
+ Add your own/reuse Servlet filters
+ Supporter les coffee et less pré-générés
diff --git a/pom.xml b/pom.xml
index fdbf129..57cafaf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -197,9 +197,14 @@
- org.simpleframework
- simple
- 5.1.6
+ org.eclipse.jetty
+ jetty-server
+ 9.1.3.v20140225
+
+
+ org.eclipse.jetty
+ jetty-servlet
+ 9.1.3.v20140225
com.github.sommeri
@@ -305,5 +310,11 @@
3.1.1
test
+
+ org.eclipse.jetty
+ jetty-webapp
+ 9.1.3.v20140225
+ test
+
diff --git a/src/main/java/net/codestory/http/WebServer.java b/src/main/java/net/codestory/http/WebServer.java
index 6a02407..6dad983 100644
--- a/src/main/java/net/codestory/http/WebServer.java
+++ b/src/main/java/net/codestory/http/WebServer.java
@@ -16,6 +16,8 @@
package net.codestory.http;
import java.io.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
import java.net.*;
import java.nio.file.Path;
import java.util.*;
@@ -27,21 +29,34 @@
import net.codestory.http.payload.*;
import net.codestory.http.reload.*;
import net.codestory.http.routes.*;
+import net.codestory.http.servlet.WebServerConfig;
import net.codestory.http.ssl.*;
-import org.simpleframework.http.*;
-import org.simpleframework.http.core.*;
-import org.simpleframework.transport.*;
-import org.simpleframework.transport.connect.*;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.slf4j.*;
-import javax.net.ssl.*;
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
-public class WebServer {
+public class WebServer implements Filter {
private final static Logger LOG = LoggerFactory.getLogger(WebServer.class);
- private final Server server;
- private final SocketConnection connection;
+ private Server server;
private RoutesProvider routesProvider;
private int port;
@@ -51,12 +66,6 @@ public WebServer() {
}
public WebServer(Configuration configuration) {
- try {
- server = new ContainerServer(this::handle);
- connection = new SocketConnection(server);
- } catch (IOException e) {
- throw new IllegalStateException("Unable to create http server", e);
- }
configure(configuration);
}
@@ -96,7 +105,7 @@ public WebServer start(int port) {
}
public WebServer startSSL(int port, Path pathCertificate, Path pathPrivateKey) {
- SSLContext context;
+ SslContextFactory context;
try {
context = new SSLContextFactory().create(pathCertificate, pathPrivateKey);
} catch (Exception e) {
@@ -105,11 +114,33 @@ public WebServer startSSL(int port, Path pathCertificate, Path pathPrivateKey) {
return startWithContext(port, context);
}
- private WebServer startWithContext(int port, SSLContext context) {
+ private WebServer startWithContext(int port, SslContextFactory context) {
try {
this.port = Env.INSTANCE.overriddenPort(port);
+ embedded = true;
+
+ if (context == null) {
+ server = new Server(this.port);
+ } else {
+ server = new Server();
+
+ HttpConfiguration https = new HttpConfiguration();
+ https.addCustomizer(new SecureRequestCustomizer());
+
+ ServerConnector sslConnector = new ServerConnector(server,
+ new SslConnectionFactory(context, "http/1.1"),
+ new HttpConnectionFactory(https));
+ sslConnector.setPort(this.port);
+
+ server.addConnector(sslConnector);
+ }
+
+ ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
+ servletHandler.addFilter(new FilterHolder(this), "/*", EnumSet.of(DispatcherType.REQUEST));
- connection.connect(new InetSocketAddress(this.port), context);
+ server.setHandler(servletHandler);
+
+ server.start();
LOG.info("Server started on port {}", this.port);
} catch (RuntimeException e) {
@@ -135,33 +166,8 @@ public void reset() {
public void stop() {
try {
server.stop();
- } catch (IOException e) {
- throw new IllegalStateException("Unable to stop the web server", e);
- }
- }
-
- void handle(Request request, Response response) {
- Context context = null;
-
- try {
- RouteCollection routes = routesProvider.get();
- context = new Context(request, response, routes.getIocAdapter());
-
- applyRoutes(routes, context);
} catch (Exception e) {
- if (context == null) {
- // Didn't manage to initialize a full context
- // because the routes failed to load
- //
- context = new Context(request, response, null);
- }
- handleServerError(context, e);
- } finally {
- try {
- response.close();
- } catch (IOException e) {
- // Ignore
- }
+ throw new IllegalStateException("Unable to stop the web server", e);
}
}
@@ -198,4 +204,64 @@ protected Payload errorPage(Payload payload, Exception e) {
Exception shownError = Env.INSTANCE.prodMode() ? null : e;
return new ErrorPage(payload, shownError).payload();
}
+
+ private boolean embedded = false;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ if (embedded) {
+ return;
+ }
+ String configClassName = filterConfig.getInitParameter("configClass");
+ if (configClassName == null) {
+ throw new IllegalArgumentException("Parameter configClass must be specified for the filter.");
+ }
+
+ try {
+ Class> configClass = Class.forName(configClassName);
+ Constructor> constructor = configClass.getConstructor();
+ Object configObject = constructor.newInstance();
+ if (!(configObject instanceof WebServerConfig)) {
+ throw new IllegalArgumentException(configClassName + " must implement WebServerConfig");
+ }
+ WebServerConfig webServerConfig = (WebServerConfig) configObject;
+ webServerConfig.configure(this);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Parameter configClass must be set with a class", e);
+ } catch (NoSuchMethodException|InvocationTargetException|InstantiationException|IllegalAccessException e) {
+ throw new IllegalArgumentException(configClassName + " must have a public constructor with no args", e);
+ }
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+
+ Context context = null;
+
+ try {
+ RouteCollection routes = routesProvider.get();
+ context = new Context((HttpServletRequest)request, (HttpServletResponse)response, routes.getIocAdapter());
+
+ applyRoutes(routes, context);
+ } catch (Exception e) {
+ if (context == null) {
+ // Didn't manage to initialize a full context
+ // because the routes failed to load
+ //
+ context = new Context((HttpServletRequest)request, (HttpServletResponse)response, null);
+ }
+ handleServerError(context, e);
+ } finally {
+ try {
+ response.getOutputStream().close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+
+ @Override
+ public void destroy() {
+
+ }
}
diff --git a/src/main/java/net/codestory/http/convert/TypeConvert.java b/src/main/java/net/codestory/http/convert/TypeConvert.java
index 2fe425a..7588acf 100644
--- a/src/main/java/net/codestory/http/convert/TypeConvert.java
+++ b/src/main/java/net/codestory/http/convert/TypeConvert.java
@@ -16,6 +16,7 @@
package net.codestory.http.convert;
import java.io.*;
+import java.nio.charset.Charset;
import java.util.*;
import net.codestory.http.internal.*;
@@ -23,6 +24,7 @@
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
+import net.codestory.http.io.InputStreams;
public class TypeConvert {
private static ObjectMapper OBJECT_MAPPER = new ObjectMapper()
@@ -71,7 +73,7 @@ public static T convert(Context context, Class type) {
String json;
try {
- json = context.request().getContent();
+ json = InputStreams.readString(context.request().getInputStream(), Charset.forName("UTF-8"));
} catch (IOException e) {
throw new IllegalArgumentException("Unable read request content", e);
}
diff --git a/src/main/java/net/codestory/http/filters/twitter/TwitterAuthFilter.java b/src/main/java/net/codestory/http/filters/twitter/TwitterAuthFilter.java
index a7e0721..5d61cc8 100644
--- a/src/main/java/net/codestory/http/filters/twitter/TwitterAuthFilter.java
+++ b/src/main/java/net/codestory/http/filters/twitter/TwitterAuthFilter.java
@@ -22,7 +22,6 @@
import net.codestory.http.internal.*;
import net.codestory.http.payload.*;
-import org.simpleframework.http.*;
import twitter4j.*;
import twitter4j.conf.*;
@@ -70,16 +69,16 @@ public Payload apply(String uri, Context context, PayloadSupplier nextFilter) th
}
return Payload.seeOther("/")
- .withCookie(new Cookie("userId", user.id.toString(), "/", true))
- .withCookie(new Cookie("screenName", user.screenName, "/", true))
- .withCookie(new Cookie("userPhoto", user.imageUrl, "/", true));
+ .withCookie("userId", user.id.toString())
+ .withCookie("screenName", user.screenName)
+ .withCookie("userPhoto", user.imageUrl);
}
if (uri.equals(uriPrefix + "logout")) {
return Payload.seeOther("/")
- .withCookie(new Cookie("userId", "", "/", false))
- .withCookie(new Cookie("screenName", "", "/", false))
- .withCookie(new Cookie("userPhoto", "", "/", false));
+ .withCookie("userId", "")
+ .withCookie("screenName", "")
+ .withCookie("userPhoto", "");
}
String userId = context.cookieValue("userId");
diff --git a/src/main/java/net/codestory/http/internal/Context.java b/src/main/java/net/codestory/http/internal/Context.java
index 30dc97b..1515e22 100644
--- a/src/main/java/net/codestory/http/internal/Context.java
+++ b/src/main/java/net/codestory/http/internal/Context.java
@@ -18,34 +18,38 @@
import static net.codestory.http.constants.Headers.*;
import java.io.*;
+import java.net.URLDecoder;
import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import net.codestory.http.convert.*;
import net.codestory.http.injection.*;
import net.codestory.http.io.*;
-import org.simpleframework.http.*;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
public class Context {
- private final Request request;
- private final Response response;
+ private final HttpServletRequest request;
+ private final HttpServletResponse response;
private final IocAdapter iocAdapter;
- private final Query query;
private String currentUser;
- public Context(Request request, Response response, IocAdapter iocAdapter) {
+ public Context(HttpServletRequest request, HttpServletResponse response, IocAdapter iocAdapter) {
this.request = request;
this.response = response;
this.iocAdapter = iocAdapter;
- this.query = request.getQuery();
}
public String uri() {
- return request.getPath().getPath();
+ return uriDecode(request.getRequestURI());
}
public Cookie cookie(String name) {
- return request.getCookie(name);
+ return cookies().stream().filter(cookie -> name.equals(cookie.getName())).findFirst().orElse(null);
}
public String cookieValue(String name) {
@@ -86,55 +90,70 @@ public boolean cookieValue(String name, boolean defaultValue) {
}
public List cookies() {
- return request.getCookies();
+ if (request.getCookies() == null || request.getCookies().length == 0) {
+ return new ArrayList<>();
+ }
+ return Arrays.asList(request.getCookies());
}
public String get(String name) {
- return query.get(name);
+ return uriDecode(request.getParameter(name));
}
public List getAll(String name) {
- return query.getAll(name);
+ return Arrays.asList(request.getParameterValues(name)).stream().map(this::uriDecode).collect(Collectors.toList());
}
public int getInteger(String name) {
- return query.getInteger(name);
+ return Integer.parseInt(request.getParameter(name));
}
public float getFloat(String name) {
- return query.getFloat(name);
+ return Float.parseFloat(request.getParameter(name));
}
public boolean getBoolean(String name) {
- return query.getBoolean(name);
+ return Boolean.parseBoolean(request.getParameter(name));
}
public String getHeader(String name) {
- return request.getValue(name);
+ return request.getHeader(name);
}
public List getHeaders(String name) {
- return request.getValues(name);
+ return Collections.list(request.getHeaders(name));
}
public String method() {
return request.getMethod();
}
+ private String uriDecode(String uri) {
+ try {
+ return URLDecoder.decode(uri, "UTF-8");
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new IllegalStateException("UTF-8 not supported on your system", e);
+ }
+ }
+
public Map keyValues() {
- return query;
+ return Collections.list(request.getParameterNames()).stream().collect(Collectors.toMap(
+ Function.identity(),
+ name -> uriDecode(request.getParameter(name))
+ ));
}
public String getClientAddress() {
String forwarded = getHeader(X_FORWARDED_FOR);
- return (forwarded != null) ? forwarded : request.getClientAddress().toString();
+ return (forwarded != null) ? forwarded : request.getRemoteAddr();
}
- public Request request() {
+ public HttpServletRequest request() {
return request;
}
- public Response response() {
+ public HttpServletResponse response() {
return response;
}
diff --git a/src/main/java/net/codestory/http/payload/Payload.java b/src/main/java/net/codestory/http/payload/Payload.java
index 5b3b503..1fbeaa9 100644
--- a/src/main/java/net/codestory/http/payload/Payload.java
+++ b/src/main/java/net/codestory/http/payload/Payload.java
@@ -19,9 +19,9 @@
import static net.codestory.http.constants.Encodings.*;
import static net.codestory.http.constants.Headers.*;
import static net.codestory.http.constants.HttpStatus.NOT_FOUND;
+import static net.codestory.http.constants.HttpStatus.NOT_MODIFIED;
import static net.codestory.http.constants.Methods.*;
import static net.codestory.http.io.Strings.*;
-import static org.simpleframework.http.Status.NOT_MODIFIED;
import java.io.*;
import java.net.*;
@@ -37,8 +37,11 @@
import net.codestory.http.misc.*;
import net.codestory.http.templating.*;
import net.codestory.http.types.*;
+import org.eclipse.jetty.server.Response;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
-import org.simpleframework.http.*;
public class Payload {
private final String contentType;
@@ -112,7 +115,9 @@ public Payload withCookie(String name, boolean value) {
}
public Payload withCookie(String name, String value) {
- return withCookie(new Cookie(name, value, "/", true));
+ Cookie cookie = new Cookie(name, value);
+ cookie.setDomain("/");
+ return withCookie(cookie);
}
public Payload withCookie(String name, Object value) {
@@ -195,7 +200,7 @@ public static Payload temporaryRedirect(URI uri) {
}
public static Payload notModified() {
- return new Payload(HttpStatus.NOT_MODIFIED);
+ return new Payload(NOT_MODIFIED);
}
public static Payload unauthorized(String realm) {
@@ -229,10 +234,11 @@ public boolean isBetter(Payload other) {
}
public void writeTo(Context context) throws IOException {
- Response response = context.response();
+ HttpServletResponse response = context.response();
- headers.entrySet().forEach(entry -> response.setValue(entry.getKey(), entry.getValue()));
- cookies.forEach(cookie -> response.setCookie(cookie));
+ headers.entrySet().forEach(entry ->
+ response.setHeader(entry.getKey(), entry.getValue()));
+ cookies.forEach(cookie -> response.addCookie(cookie));
long lastModified = getLastModified();
if (lastModified >= 0) {
@@ -241,20 +247,20 @@ public void writeTo(Context context) throws IOException {
response.setStatus(NOT_MODIFIED);
return;
}
- response.setValue(LAST_MODIFIED, Dates.to_rfc_1123(lastModified));
+ response.setHeader(LAST_MODIFIED, Dates.to_rfc_1123(lastModified));
}
String uri = context.uri();
byte[] data = getData(uri, context);
if (data == null) {
- response.setStatus(Status.getStatus(code));
+ response.setStatus(code);
response.setContentLength(0);
return;
}
String type = getContentType(uri);
- response.setValue(CONTENT_TYPE, type);
- response.setStatus(Status.getStatus(code));
+ response.setHeader(CONTENT_TYPE, type);
+ response.setStatus(code);
if (HEAD.equals(context.method()) || (code == 204) || (code == 304) || ((code >= 100) && (code < 200))) {
return;
@@ -266,11 +272,11 @@ public void writeTo(Context context) throws IOException {
response.setStatus(NOT_MODIFIED);
return;
}
- response.setValue(ETAG, etag);
+ response.setHeader(ETAG, etag);
String acceptEncoding = context.getHeader(ACCEPT_ENCODING);
if ((acceptEncoding != null) && acceptEncoding.contains(GZIP)) {
- response.setValue(CONTENT_ENCODING, GZIP);
+ response.setHeader(CONTENT_ENCODING, GZIP);
GZIPOutputStream gzip = new GZIPOutputStream(response.getOutputStream());
gzip.write(data);
diff --git a/src/main/java/net/codestory/http/routes/RouteWrapper.java b/src/main/java/net/codestory/http/routes/RouteWrapper.java
index fcd4691..67425d9 100644
--- a/src/main/java/net/codestory/http/routes/RouteWrapper.java
+++ b/src/main/java/net/codestory/http/routes/RouteWrapper.java
@@ -42,7 +42,7 @@ public boolean matchMethod(String method) {
@Override
public Object body(Context context) {
- String[] parameters = uriParser.params(context.uri(), context.request().getQuery());
+ String[] parameters = uriParser.params(context.uri(), context.keyValues());
return route.body(context, parameters);
}
}
diff --git a/src/main/java/net/codestory/http/servlet/WebServerConfig.java b/src/main/java/net/codestory/http/servlet/WebServerConfig.java
new file mode 100644
index 0000000..3d32016
--- /dev/null
+++ b/src/main/java/net/codestory/http/servlet/WebServerConfig.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (C) 2013 all@code-story.net
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package net.codestory.http.servlet;
+
+import net.codestory.http.WebServer;
+
+public interface WebServerConfig {
+
+ public void configure(WebServer webServer);
+
+}
diff --git a/src/main/java/net/codestory/http/ssl/SSLContextFactory.java b/src/main/java/net/codestory/http/ssl/SSLContextFactory.java
index cb02655..6762b29 100644
--- a/src/main/java/net/codestory/http/ssl/SSLContextFactory.java
+++ b/src/main/java/net/codestory/http/ssl/SSLContextFactory.java
@@ -15,6 +15,8 @@
*/
package net.codestory.http.ssl;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
import java.io.*;
import java.nio.file.*;
import java.security.*;
@@ -25,7 +27,8 @@
import javax.net.ssl.*;
public class SSLContextFactory {
- public SSLContext create(Path pathCertificate, Path pathPrivateKey) throws Exception {
+
+ public SslContextFactory create(Path pathCertificate, Path pathPrivateKey) throws Exception {
X509Certificate cert = generateCertificateFromDER(Files.readAllBytes(pathCertificate));
RSAPrivateKey key = generatePrivateKeyFromDER(Files.readAllBytes(pathPrivateKey));
@@ -37,7 +40,9 @@ public SSLContext create(Path pathCertificate, Path pathPrivateKey) throws Excep
SSLContext context = SSLContext.getInstance("TLS");
context.init(getKeyManagers(keystore), null, null);
- return context;
+ SslContextFactory sslContextFactory = new SslContextFactory();
+ sslContextFactory.setSslContext(context);
+ return sslContextFactory;
}
private static KeyManager[] getKeyManagers(KeyStore keyStore) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException {
diff --git a/src/test/java/net/codestory/http/StaticPagesTest.java b/src/test/java/net/codestory/http/StaticPagesTest.java
index f529afe..89bbfc4 100644
--- a/src/test/java/net/codestory/http/StaticPagesTest.java
+++ b/src/test/java/net/codestory/http/StaticPagesTest.java
@@ -63,7 +63,9 @@ public void markdown() {
@Test
public void private_files() {
- get("/../private.txt").produces(404);
+ // Status 400 is handle by jetty himself
+ get("/../private.txt").produces(400);
+
get("/_config.yaml").produces(404);
get("/_layouts/layout.html").produces(404);
get("/unknown").produces(404);
diff --git a/src/test/java/net/codestory/http/internal/ContextTest.java b/src/test/java/net/codestory/http/internal/ContextTest.java
index c009a0a..74653f7 100644
--- a/src/test/java/net/codestory/http/internal/ContextTest.java
+++ b/src/test/java/net/codestory/http/internal/ContextTest.java
@@ -20,12 +20,16 @@
import net.codestory.http.injection.*;
+import org.assertj.core.util.Arrays;
import org.junit.*;
-import org.simpleframework.http.*;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
public class ContextTest {
- Request request = mock(Request.class);
- Response response = mock(Response.class);
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ HttpServletResponse response = mock(HttpServletResponse.class);
IocAdapter iocAdapter = mock(IocAdapter.class);
Context context = new Context(request, response, iocAdapter);
@@ -46,7 +50,7 @@ public void default_value() {
@Test
public void cookie_value() {
- when(request.getCookie("name")).thenReturn(new Cookie("name", "value"));
+ when(request.getCookies()).thenReturn(Arrays.array(new Cookie("name", "value")));
String value = context.cookieValue("name", "default");
@@ -55,7 +59,7 @@ public void cookie_value() {
@Test
public void json_cookie_json_by_type() {
- when(request.getCookie("name")).thenReturn(new Cookie("name", "{\"name\": \"Bob\", \"quantity\": 42}"));
+ when(request.getCookies()).thenReturn(Arrays.array(new Cookie("name", "{\"name\": \"Bob\", \"quantity\": 42}")));
Order order = context.cookieValue("name", Order.class);
@@ -73,7 +77,7 @@ public void json_cookie_default_value() {
@Test
public void json_cookie() {
- when(request.getCookie("name")).thenReturn(new Cookie("name", "{\"name\": \"Joe\", \"quantity\": 12}"));
+ when(request.getCookies()).thenReturn(Arrays.array(new Cookie("name", "{\"name\": \"Joe\", \"quantity\": 12}")));
Order order = context.cookieValue("name", new Order());
diff --git a/src/test/java/net/codestory/http/payload/PayloadTest.java b/src/test/java/net/codestory/http/payload/PayloadTest.java
index 85b38cb..c757742 100644
--- a/src/test/java/net/codestory/http/payload/PayloadTest.java
+++ b/src/test/java/net/codestory/http/payload/PayloadTest.java
@@ -23,19 +23,24 @@
import java.nio.file.*;
import java.util.*;
+import net.codestory.http.constants.HttpStatus;
import net.codestory.http.internal.*;
import org.junit.*;
-import org.simpleframework.http.*;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.WriteListener;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
public class PayloadTest {
Context context = mock(Context.class);
- Response response = mock(Response.class);
+ HttpServletResponse response = mock(HttpServletResponse.class);
@Before
public void setupContext() throws IOException {
when(context.response()).thenReturn(response);
- when(response.getOutputStream()).thenReturn(new ByteArrayOutputStream());
+ when(response.getOutputStream()).thenReturn(mock(ServletOutputStream.class));
}
@Test
@@ -94,7 +99,7 @@ public void support_absent_optional() throws IOException {
Payload payload = new Payload("text/plain", Optional.empty());
payload.writeTo(context);
- verify(response).setStatus(Status.NOT_FOUND);
+ verify(response).setStatus(HttpStatus.NOT_FOUND);
verify(response).setContentLength(0);
verifyNoMoreInteractions(response);
}
@@ -104,8 +109,8 @@ public void redirect() throws IOException {
Payload payload = Payload.seeOther("/url");
payload.writeTo(context);
- verify(response).setValue("Location", "/url");
- verify(response).setStatus(Status.SEE_OTHER);
+ verify(response).setHeader("Location", "/url");
+ verify(response).setStatus(HttpStatus.SEE_OTHER);
verify(response).setContentLength(0);
verifyNoMoreInteractions(response);
}
@@ -115,7 +120,7 @@ public void forbidden() throws IOException {
Payload payload = Payload.forbidden();
payload.writeTo(context);
- verify(response).setStatus(Status.FORBIDDEN);
+ verify(response).setStatus(HttpStatus.FORBIDDEN);
verify(response).setContentLength(0);
verifyNoMoreInteractions(response);
}
@@ -125,8 +130,8 @@ public void permanent_move() throws IOException {
Payload payload = Payload.movedPermanently("/url");
payload.writeTo(context);
- verify(response).setValue("Location", "/url");
- verify(response).setStatus(Status.MOVED_PERMANENTLY);
+ verify(response).setHeader("Location", "/url");
+ verify(response).setStatus(HttpStatus.MOVED_PERMANENTLY);
verify(response).setContentLength(0);
verifyNoMoreInteractions(response);
}
@@ -136,7 +141,7 @@ public void last_modified() throws IOException {
Payload payload = new Payload(Paths.get("hello.md"));
payload.writeTo(context);
- verify(response).setValue(eq("Last-Modified"), anyString());
+ verify(response).setHeader(eq("Last-Modified"), anyString());
}
@Test
@@ -183,8 +188,8 @@ public void etag() throws IOException {
Payload payload = new Payload("Hello");
payload.writeTo(context);
- verify(response).setStatus(Status.OK);
- verify(response).setValue("ETag", "8b1a9953c4611296a827abf8c47804d7");
+ verify(response).setStatus(HttpStatus.OK);
+ verify(response).setHeader("ETag", "8b1a9953c4611296a827abf8c47804d7");
}
@Test
@@ -194,7 +199,7 @@ public void not_modified() throws IOException {
Payload payload = new Payload("Hello");
payload.writeTo(context);
- verify(response).setStatus(Status.NOT_MODIFIED);
+ verify(response).setStatus(HttpStatus.NOT_MODIFIED);
}
@Test
@@ -204,7 +209,7 @@ public void head() throws IOException {
Payload payload = new Payload("Hello");
payload.writeTo(context);
- verify(response).setStatus(Status.OK);
+ verify(response).setStatus(HttpStatus.OK);
verify(response, never()).setContentLength(anyInt());
verify(response, never()).getOutputStream();
}
diff --git a/src/test/java/net/codestory/http/servlet/WebXmlConfig.java b/src/test/java/net/codestory/http/servlet/WebXmlConfig.java
new file mode 100644
index 0000000..11e87b0
--- /dev/null
+++ b/src/test/java/net/codestory/http/servlet/WebXmlConfig.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2013 all@code-story.net
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package net.codestory.http.servlet;
+
+import net.codestory.http.WebServer;
+
+public class WebXmlConfig implements WebServerConfig {
+ @Override
+ public void configure(WebServer webServer) {
+ webServer.configure(routes ->
+ routes.get("/hellowebxml", "Hello World"));
+ }
+}
diff --git a/src/test/java/net/codestory/http/servlet/WebXmlTest.java b/src/test/java/net/codestory/http/servlet/WebXmlTest.java
new file mode 100644
index 0000000..47fd480
--- /dev/null
+++ b/src/test/java/net/codestory/http/servlet/WebXmlTest.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2013 all@code-story.net
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package net.codestory.http.servlet;
+
+import com.jayway.restassured.RestAssured;
+import com.jayway.restassured.assertion.BodyMatcher;
+import com.jayway.restassured.matcher.RestAssuredMatchers;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Random;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.core.IsEqual.equalTo;
+
+public class WebXmlTest {
+
+ private Server server;
+
+ private int port;
+
+ @Before
+ public void startServer() throws Exception {
+ port = 8080 + new Random().nextInt(1000);
+ server = new Server(port);
+
+ WebAppContext context = new WebAppContext(WebXmlTest.class.getResource("/net/codestory/http/servlet").toExternalForm(), "/");
+ context.setParentLoaderPriority(true);
+
+ server.setHandler(context);
+
+ server.start();
+ }
+
+ @Test
+ public void should_answer_with_webxml() throws Exception {
+
+ RestAssured.port = this.port;
+ assertThat(RestAssured.get("/hellowebxml").then()
+ .statusCode(200)
+ .body(equalTo("Hello World")));
+
+ }
+
+ @After
+ public void stopServer() throws Exception {
+ server.stop();
+ }
+
+}
diff --git a/src/test/java/net/codestory/http/ssl/SSLTest.java b/src/test/java/net/codestory/http/ssl/SSLTest.java
index 062cccb..41a2988 100644
--- a/src/test/java/net/codestory/http/ssl/SSLTest.java
+++ b/src/test/java/net/codestory/http/ssl/SSLTest.java
@@ -19,18 +19,23 @@
import java.nio.file.*;
import java.util.*;
+import com.jayway.restassured.RestAssured;
import net.codestory.http.*;
import org.junit.*;
public class SSLTest {
@Test
- public void start_server() throws URISyntaxException {
+ public void start_server() throws URISyntaxException, InterruptedException {
Path pathCertificate = resource("certificates/server.crt");
Path pathPrivateKey = resource("certificates/server.der");
WebServer webServer = new WebServer();
webServer.startSSL(8183 + new Random().nextInt(1000), pathCertificate, pathPrivateKey);
+
+ RestAssured.useRelaxedHTTPSValidation();
+ RestAssured.get("https://localhost:" + webServer.port() + "/").then().statusCode(200);
+
}
private static Path resource(String name) throws URISyntaxException {
diff --git a/src/test/resources/net/codestory/http/servlet/WEB-INF/web.xml b/src/test/resources/net/codestory/http/servlet/WEB-INF/web.xml
new file mode 100644
index 0000000..a067f1c
--- /dev/null
+++ b/src/test/resources/net/codestory/http/servlet/WEB-INF/web.xml
@@ -0,0 +1,15 @@
+
+
+ codestoryfilter
+ net.codestory.http.WebServer
+
+ configClass
+ net.codestory.http.servlet.WebXmlConfig
+
+
+
+
+ codestoryfilter
+ *
+
+
\ No newline at end of file