summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
authorAndrei Belov <defan@nginx.com>2019-03-01 18:30:09 +0300
committerAndrei Belov <defan@nginx.com>2019-03-01 18:30:09 +0300
commit3c3720cba7154bc168cbd00c74817626bb53e140 (patch)
treeda1500f7c6bd5e90ecf45299b6f4b19a29d521cd /test
parent315a864c27aa27a48c013c4a1ef67a099ffea894 (diff)
parentdf02b03824065389c73213b19736140442cf63bc (diff)
downloadunit-3c3720cba7154bc168cbd00c74817626bb53e140.tar.gz
unit-3c3720cba7154bc168cbd00c74817626bb53e140.tar.bz2
Merged with the default branch.
Diffstat (limited to '')
-rw-r--r--test/java/content_type/app.java89
-rw-r--r--test/java/cookies/app.java30
-rw-r--r--test/java/empty/app.java18
-rw-r--r--test/java/filter/app.java54
-rw-r--r--test/java/forward/app.java138
-rw-r--r--test/java/forward/index.html1
-rw-r--r--test/java/forward/web.xml38
-rw-r--r--test/java/get_header/app.java21
-rw-r--r--test/java/get_header_names/app.java27
-rw-r--r--test/java/get_headers/app.java27
-rw-r--r--test/java/get_params/app.java50
-rw-r--r--test/java/header/app.java34
-rw-r--r--test/java/header_date/app.java22
-rw-r--r--test/java/header_int/app.java22
-rw-r--r--test/java/include/app.java136
-rw-r--r--test/java/include/index.html1
-rw-r--r--test/java/include/web.xml37
-rw-r--r--test/java/jsp/index.jsp2
-rw-r--r--test/java/mirror/app.java37
-rw-r--r--test/java/path_translation/app.java56
-rw-r--r--test/java/path_translation/index.html1
-rw-r--r--test/java/post_params/app.java22
-rw-r--r--test/java/query_string/app.java20
-rw-r--r--test/java/request_listeners/app.java79
-rw-r--r--test/java/session/app.java30
-rw-r--r--test/java/session_inactive/app.java27
-rw-r--r--test/java/session_invalidate/app.java23
-rw-r--r--test/java/session_listeners/app.java80
-rw-r--r--test/java/session_listeners/web.xml14
-rw-r--r--test/java/url_pattern/app.java39
-rw-r--r--test/java/url_pattern/web.xml75
-rw-r--r--test/java/welcome_files/app.java67
-rw-r--r--test/java/welcome_files/dir1/index.txt1
-rw-r--r--test/java/welcome_files/dir2/default.jsp3
-rw-r--r--test/java/welcome_files/dir2/index.html1
-rw-r--r--test/java/welcome_files/dir3/index.txt1
-rw-r--r--test/java/welcome_files/dir4/index.html1
-rw-r--r--test/java/welcome_files/index.htm1
-rw-r--r--test/java/welcome_files/web.xml27
-rwxr-xr-xtest/node/write_before_write_head/app.js1
-rw-r--r--test/perl/body_io_fake/IOFake.pm33
-rw-r--r--test/perl/body_io_fake/psgi.pl11
-rw-r--r--test/perl/delayed_response/psgi.pl10
-rw-r--r--test/perl/streaming_body/psgi.pl13
-rw-r--r--test/php/date_time/index.php3
-rw-r--r--test/php/highlight_file_exec/index.php4
-rw-r--r--test/php/query_string/index.php4
-rw-r--r--test/php/time_exec/index.php4
-rw-r--r--test/python/host/wsgi.py7
-rw-r--r--test/test_access_log.py8
-rw-r--r--test/test_configuration.py49
-rw-r--r--test/test_go_application.py25
-rw-r--r--test/test_http_header.py241
-rw-r--r--test/test_java_application.py753
-rw-r--r--test/test_node_application.py54
-rw-r--r--test/test_perl_application.py62
-rw-r--r--test/test_php_application.py157
-rw-r--r--test/test_python_application.py65
-rw-r--r--test/test_python_procman.py2
-rw-r--r--test/test_routing.py458
-rw-r--r--test/test_ruby_application.py32
-rw-r--r--test/test_settings.py31
-rw-r--r--test/test_tls.py44
-rw-r--r--test/unit.py113
64 files changed, 3308 insertions, 228 deletions
diff --git a/test/java/content_type/app.java b/test/java/content_type/app.java
new file mode 100644
index 00000000..7d8a7418
--- /dev/null
+++ b/test/java/content_type/app.java
@@ -0,0 +1,89 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet("/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ if (request.getServletPath().equals("/1")) {
+ response.setContentType("text/plain;charset=utf-8");
+ response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
+ response.setHeader("X-Content-Type", response.getContentType());
+ return;
+ }
+
+ if (request.getServletPath().equals("/2")) {
+ response.setContentType("text/plain");
+ response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
+ response.setHeader("X-Content-Type", response.getContentType());
+ return;
+ }
+
+ if (request.getServletPath().equals("/3")) {
+ response.setContentType("text/plain;charset=utf-8");
+ response.setCharacterEncoding("windows-1251");
+ response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
+ response.setHeader("X-Content-Type", response.getContentType());
+ return;
+ }
+
+ if (request.getServletPath().equals("/4")) {
+ response.setCharacterEncoding("windows-1251");
+ response.setContentType("text/plain");
+ response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
+ response.setHeader("X-Content-Type", response.getContentType());
+ return;
+ }
+
+ if (request.getServletPath().equals("/5")) {
+ response.setContentType("text/plain;charset=utf-8");
+ response.setCharacterEncoding(null);
+ response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
+ response.setHeader("X-Content-Type", response.getContentType());
+ return;
+ }
+
+ if (request.getServletPath().equals("/6")) {
+ response.setContentType("text/plain;charset=utf-8");
+ response.setContentType(null);
+ response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
+ response.setHeader("X-Content-Type", response.getContentType());
+ return;
+ }
+
+ if (request.getServletPath().equals("/7")) {
+ response.setContentType("text/plain;charset=utf-8");
+
+ PrintWriter out = response.getWriter();
+
+ response.setCharacterEncoding("windows-1251");
+ response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
+ response.setHeader("X-Content-Type", response.getContentType());
+ return;
+ }
+
+ if (request.getServletPath().equals("/8")) {
+ response.setContentType("text/plain;charset=utf-8");
+
+ PrintWriter out = response.getWriter();
+
+ response.setContentType("text/html;charset=windows-1251");
+ response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
+ response.setHeader("X-Content-Type", response.getContentType());
+ return;
+ }
+
+ response.sendError(404);
+ }
+}
diff --git a/test/java/cookies/app.java b/test/java/cookies/app.java
new file mode 100644
index 00000000..13cea6d1
--- /dev/null
+++ b/test/java/cookies/app.java
@@ -0,0 +1,30 @@
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet(urlPatterns = "/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ Cookie[] cookies = request.getCookies();
+ if (cookies != null) {
+ for (Cookie c : cookies) {
+ if (c.getName().equals("var1")) {
+ response.addHeader("X-Cookie-1", c.getValue());
+ }
+ if (c.getName().equals("var2")) {
+ response.addHeader("X-Cookie-2", c.getValue());
+ }
+ }
+ }
+ }
+}
diff --git a/test/java/empty/app.java b/test/java/empty/app.java
new file mode 100644
index 00000000..b0fca631
--- /dev/null
+++ b/test/java/empty/app.java
@@ -0,0 +1,18 @@
+
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet("/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ { }
+}
diff --git a/test/java/filter/app.java b/test/java/filter/app.java
new file mode 100644
index 00000000..a5da3997
--- /dev/null
+++ b/test/java/filter/app.java
@@ -0,0 +1,54 @@
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+@WebServlet(urlPatterns = "/")
+public class app extends HttpServlet
+{
+ @WebFilter(urlPatterns = "")
+ public static class filter implements Filter
+ {
+ @Override
+ public void init(FilterConfig filterConfig)
+ {
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException
+ {
+ response.getOutputStream().println("Extra Info");
+ response.setCharacterEncoding("utf-8");
+
+ ((HttpServletResponse) response).addHeader("X-Filter-Before", "1");
+
+ chain.doFilter(request, response);
+
+ ((HttpServletResponse) response).setHeader("X-Filter-After", "1");
+ }
+
+ @Override
+ public void destroy()
+ {
+ }
+ }
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.getOutputStream().println("This is servlet response");
+ response.setHeader("X-Filter-After", "0");
+ }
+}
diff --git a/test/java/forward/app.java b/test/java/forward/app.java
new file mode 100644
index 00000000..0dea17d6
--- /dev/null
+++ b/test/java/forward/app.java
@@ -0,0 +1,138 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import java.util.Map;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+public class app extends HttpServlet
+{
+ private String id;
+
+ private class RequestWrapper extends HttpServletRequestWrapper
+ {
+ public RequestWrapper(HttpServletRequest r)
+ {
+ super(r);
+ }
+ }
+
+ private class ResponseWrapper extends HttpServletResponseWrapper
+ {
+ public ResponseWrapper(HttpServletResponse r)
+ {
+ super(r);
+ }
+ }
+
+ @Override
+ public void init(ServletConfig sc)
+ throws ServletException
+ {
+ id = sc.getInitParameter("id");
+ }
+
+ private RequestDispatcher getRequestDispatcher(HttpServletRequest request, String str)
+ {
+ String disp = request.getParameter("disp");
+
+ if (disp != null && disp.equals("ctx")) {
+ return request.getServletContext().getRequestDispatcher(str);
+ }
+
+ if (disp != null && disp.equals("name")) {
+ return request.getServletContext().getNamedDispatcher(str);
+ }
+
+ if (disp == null || disp.equals("req")) {
+ return request.getRequestDispatcher(str);
+ }
+
+ return null;
+ }
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ String dtype = "" + request.getDispatcherType();
+
+ response.addHeader("X-" + dtype + "-Id", id);
+ response.addHeader("X-" + dtype + "-Request-URI", "" + request.getRequestURI());
+ response.addHeader("X-" + dtype + "-Servlet-Path", "" + request.getServletPath());
+ response.addHeader("X-" + dtype + "-Path-Info", "" + request.getPathInfo());
+ response.addHeader("X-" + dtype + "-Query-String", "" + request.getQueryString());
+ response.addHeader("X-" + dtype + "-Dispatcher-Type", "" + request.getDispatcherType());
+
+ response.setContentType("text/plain; charset=utf-8");
+
+ Map<String, String[]> pmap = request.getParameterMap();
+
+ for (Map.Entry<String,String[]> p : pmap.entrySet()) {
+ response.addHeader("X-" + dtype + "-Param-" + p.getKey(), "" + String.join(",", p.getValue()));
+ }
+
+ PrintWriter out = response.getWriter();
+
+ if (id.equals("fwd")) {
+ String uri = request.getParameter("uri");
+
+ if (uri != null && request.getDispatcherType() != DispatcherType.FORWARD) {
+ response.addHeader("X-Forward-To", "" + uri);
+
+ out.println("Before forwarding.");
+
+ RequestDispatcher d = getRequestDispatcher(request, uri);
+
+ if (d == null) {
+ out.println("Dispatcher is null");
+ return;
+ }
+
+ try {
+ d.forward(new RequestWrapper(request), new ResponseWrapper(response));
+ } catch(Exception e) {
+ response.addHeader("X-Exception", "" + e);
+ }
+
+ response.addHeader("X-After-Forwarding", "you-should-not-see-this");
+
+ out.println("After forwarding.");
+
+ return;
+ }
+ }
+
+ if (id.equals("data")) {
+ response.addHeader("X-" + RequestDispatcher.FORWARD_REQUEST_URI, "" + request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI));
+ response.addHeader("X-" + RequestDispatcher.FORWARD_CONTEXT_PATH, "" + request.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH));
+ response.addHeader("X-" + RequestDispatcher.FORWARD_SERVLET_PATH, "" + request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
+ response.addHeader("X-" + RequestDispatcher.FORWARD_PATH_INFO, "" + request.getAttribute(RequestDispatcher.FORWARD_PATH_INFO));
+ response.addHeader("X-" + RequestDispatcher.FORWARD_QUERY_STRING, "" + request.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING));
+
+ out.println("app.doGet(): #" + this + ", " + id);
+ out.println("RequestURI: " + request.getRequestURI());
+ out.println("ServletPath: " + request.getServletPath());
+ out.println("PathInfo: " + request.getPathInfo());
+ out.println("DispType: " + request.getDispatcherType());
+ out.println("QueryString: " + request.getQueryString());
+
+ for (Map.Entry<String,String[]> p : pmap.entrySet()) {
+ out.println("- " + p.getKey() + "=" + String.join(",", p.getValue()));
+ }
+
+ return;
+ }
+
+ response.sendError(404);
+ }
+}
diff --git a/test/java/forward/index.html b/test/java/forward/index.html
new file mode 100644
index 00000000..4f5a6379
--- /dev/null
+++ b/test/java/forward/index.html
@@ -0,0 +1 @@
+<html><body>This is index.html.</body></html>
diff --git a/test/java/forward/web.xml b/test/java/forward/web.xml
new file mode 100644
index 00000000..994adb37
--- /dev/null
+++ b/test/java/forward/web.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+ version="3.0">
+
+ <servlet>
+ <servlet-name>fwd</servlet-name>
+ <servlet-class>app</servlet-class>
+ <init-param><param-name>id</param-name><param-value>fwd</param-value></init-param>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>fwd</servlet-name>
+ <url-pattern>/fwd/*</url-pattern>
+ </servlet-mapping>
+
+
+ <servlet>
+ <servlet-name>data</servlet-name>
+ <servlet-class>app</servlet-class>
+ <init-param><param-name>id</param-name><param-value>data</param-value></init-param>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>data</servlet-name>
+ <url-pattern>/data/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>data</servlet-name>
+ <url-pattern>/WEB-INF/index.html</url-pattern>
+ <url-pattern>/index.html</url-pattern>
+ </servlet-mapping>
+
+</web-app>
+
diff --git a/test/java/get_header/app.java b/test/java/get_header/app.java
new file mode 100644
index 00000000..c981835d
--- /dev/null
+++ b/test/java/get_header/app.java
@@ -0,0 +1,21 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet("/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.addHeader("X-Reply", request.getHeader("X-Header"));
+ }
+}
diff --git a/test/java/get_header_names/app.java b/test/java/get_header_names/app.java
new file mode 100644
index 00000000..cd2f3097
--- /dev/null
+++ b/test/java/get_header_names/app.java
@@ -0,0 +1,27 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet("/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ Enumeration<String> header_names = request.getHeaderNames();
+
+ for (int i = 0; header_names.hasMoreElements(); i++) {
+ response.addHeader("X-Reply-" + Integer.toString(i),
+ header_names.nextElement());
+ }
+ }
+}
diff --git a/test/java/get_headers/app.java b/test/java/get_headers/app.java
new file mode 100644
index 00000000..f2930a61
--- /dev/null
+++ b/test/java/get_headers/app.java
@@ -0,0 +1,27 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet("/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ Enumeration<String> headers = request.getHeaders("X-Header");
+
+ for (int i = 0; headers.hasMoreElements(); i++) {
+ response.addHeader("X-Reply-" + Integer.toString(i),
+ headers.nextElement());
+ }
+ }
+}
diff --git a/test/java/get_params/app.java b/test/java/get_params/app.java
new file mode 100644
index 00000000..1965ae2a
--- /dev/null
+++ b/test/java/get_params/app.java
@@ -0,0 +1,50 @@
+
+import java.io.IOException;
+
+import java.util.Enumeration;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet(urlPatterns = "/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.addHeader("X-Var-1", request.getParameter("var1"));
+ response.addHeader("X-Var-2", "" + (request.getParameter("var2") != null));
+ response.addHeader("X-Var-3", "" + (request.getParameter("var3") != null));
+ response.addHeader("X-Var-4", request.getParameter("var4"));
+
+ Enumeration<String> parameter_names = request.getParameterNames();
+
+ String names = "";
+ for (int i = 0; parameter_names.hasMoreElements(); i++) {
+ names = names.concat(parameter_names.nextElement() + " ");
+ }
+ response.addHeader("X-Param-Names", names);
+
+ String[] parameter_values = request.getParameterValues("var4");
+
+ String values = "";
+ for (int i = 0; i < parameter_values.length; i++) {
+ values = values.concat(parameter_values[i] + " ");
+ }
+ response.addHeader("X-Param-Values", values);
+
+ Map <String, String[]> parameter_map = request.getParameterMap();
+
+ String map = "";
+ for (Map.Entry <String, String[]> p : parameter_map.entrySet()) {
+ map = map.concat(p.getKey() + "=" + String.join(",", p.getValue()) + " ");
+ }
+ response.addHeader("X-Param-Map", map);
+ }
+}
diff --git a/test/java/header/app.java b/test/java/header/app.java
new file mode 100644
index 00000000..02d56f4d
--- /dev/null
+++ b/test/java/header/app.java
@@ -0,0 +1,34 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet("/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.setHeader("X-Set-Utf8-Value", "тест");
+ response.setHeader("X-Set-Utf8-Name-Имя", "x");
+
+ response.addHeader("X-Add-Utf8-Value", "тест");
+ response.addHeader("X-Add-Utf8-Name-Имя", "y");
+
+ response.addHeader("X-Add-Test", "v1");
+ response.addHeader("X-Add-Test", null);
+
+ response.setHeader("X-Set-Test1", "v1");
+ response.setHeader("X-Set-Test1", null);
+
+ response.setHeader("X-Set-Test2", "v1");
+ response.setHeader("X-Set-Test2", "");
+ }
+}
diff --git a/test/java/header_date/app.java b/test/java/header_date/app.java
new file mode 100644
index 00000000..cedd569c
--- /dev/null
+++ b/test/java/header_date/app.java
@@ -0,0 +1,22 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet("/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.setDateHeader("X-Set-Date", 1000);
+ response.addDateHeader("X-Get-Date", request.getDateHeader("X-Header"));
+ }
+}
diff --git a/test/java/header_int/app.java b/test/java/header_int/app.java
new file mode 100644
index 00000000..3ac5478e
--- /dev/null
+++ b/test/java/header_int/app.java
@@ -0,0 +1,22 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet("/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.setIntHeader("X-Set-Int", 1);
+ response.addHeader("X-Get-Int", Integer.toString(request.getIntHeader("X-Header")));
+ }
+}
diff --git a/test/java/include/app.java b/test/java/include/app.java
new file mode 100644
index 00000000..d7e36fc6
--- /dev/null
+++ b/test/java/include/app.java
@@ -0,0 +1,136 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import java.util.Map;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+public class app extends HttpServlet
+{
+ private String id;
+
+ private class RequestWrapper extends HttpServletRequestWrapper
+ {
+ public RequestWrapper(HttpServletRequest r)
+ {
+ super(r);
+ }
+ }
+
+ private class ResponseWrapper extends HttpServletResponseWrapper
+ {
+ public ResponseWrapper(HttpServletResponse r)
+ {
+ super(r);
+ }
+ }
+
+ @Override
+ public void init(ServletConfig sc)
+ throws ServletException
+ {
+ id = sc.getInitParameter("id");
+ }
+
+ private RequestDispatcher getRequestDispatcher(HttpServletRequest request, String str)
+ {
+ String disp = request.getParameter("disp");
+
+ if (disp != null && disp.equals("ctx")) {
+ return request.getServletContext().getRequestDispatcher(str);
+ }
+
+ if (disp != null && disp.equals("name")) {
+ return request.getServletContext().getNamedDispatcher(str);
+ }
+
+ if (disp == null || disp.equals("req")) {
+ return request.getRequestDispatcher(str);
+ }
+
+ return null;
+ }
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ String dtype = "" + request.getDispatcherType();
+
+ response.addHeader("X-" + dtype + "-Id", id);
+ response.addHeader("X-" + dtype + "-Request-URI", "" + request.getRequestURI());
+ response.addHeader("X-" + dtype + "-Servlet-Path", "" + request.getServletPath());
+ response.addHeader("X-" + dtype + "-Path-Info", "" + request.getPathInfo());
+ response.addHeader("X-" + dtype + "-Query-String", "" + request.getQueryString());
+ response.addHeader("X-" + dtype + "-Dispatcher-Type", "" + request.getDispatcherType());
+
+ response.setContentType("text/plain; charset=utf-8");
+
+ PrintWriter out = response.getWriter();
+
+ if (id.equals("inc")) {
+ String uri = request.getParameter("uri");
+
+ if (uri != null && request.getDispatcherType() != DispatcherType.INCLUDE) {
+ response.addHeader("X-Include", "" + uri);
+
+ out.println("Before include.");
+
+ RequestDispatcher d = getRequestDispatcher(request, uri);
+
+ if (d == null) {
+ out.println("Dispatcher is null");
+ return;
+ }
+
+ try {
+ d.include(new RequestWrapper(request), new ResponseWrapper(response));
+ } catch(Exception e) {
+ response.addHeader("X-Exception", "" + e);
+ out.println("Exception: " + e);
+ }
+
+ response.addHeader("X-After-Include", "you-should-see-this");
+
+ out.println("After include.");
+
+ return;
+ }
+ }
+
+ if (id.equals("data")) {
+ out.println("app.doGet(): #" + this + ", " + id);
+ out.println("RequestURI: " + request.getRequestURI());
+ out.println("ServletPath: " + request.getServletPath());
+ out.println("PathInfo: " + request.getPathInfo());
+ out.println("DispType: " + request.getDispatcherType());
+ out.println("QueryString: " + request.getQueryString());
+
+ Map<String, String[]> pmap = request.getParameterMap();
+
+ for (Map.Entry<String,String[]> p : pmap.entrySet()) {
+ out.println("- " + p.getKey() + "=" + String.join(",", p.getValue()));
+ }
+
+ out.println(RequestDispatcher.INCLUDE_REQUEST_URI + ": " + request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI));
+ out.println(RequestDispatcher.INCLUDE_CONTEXT_PATH + ": " + request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH));
+ out.println(RequestDispatcher.INCLUDE_SERVLET_PATH + ": " + request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH));
+ out.println(RequestDispatcher.INCLUDE_PATH_INFO + ": " + request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO));
+ out.println(RequestDispatcher.INCLUDE_QUERY_STRING + ": " + request.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING));
+
+ return;
+ }
+
+ response.sendError(404);
+ }
+}
diff --git a/test/java/include/index.html b/test/java/include/index.html
new file mode 100644
index 00000000..4f5a6379
--- /dev/null
+++ b/test/java/include/index.html
@@ -0,0 +1 @@
+<html><body>This is index.html.</body></html>
diff --git a/test/java/include/web.xml b/test/java/include/web.xml
new file mode 100644
index 00000000..2ed86f1d
--- /dev/null
+++ b/test/java/include/web.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+ version="3.0">
+
+ <servlet>
+ <servlet-name>inc</servlet-name>
+ <servlet-class>app</servlet-class>
+ <init-param><param-name>id</param-name><param-value>inc</param-value></init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name>data</servlet-name>
+ <servlet-class>app</servlet-class>
+ <init-param><param-name>id</param-name><param-value>data</param-value></init-param>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>inc</servlet-name>
+ <url-pattern>/inc/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>data</servlet-name>
+ <url-pattern>/data/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>data</servlet-name>
+ <url-pattern>/WEB-INF/index.html</url-pattern>
+ <url-pattern>/index.html</url-pattern>
+ </servlet-mapping>
+
+</web-app>
+
diff --git a/test/java/jsp/index.jsp b/test/java/jsp/index.jsp
new file mode 100644
index 00000000..0af00a46
--- /dev/null
+++ b/test/java/jsp/index.jsp
@@ -0,0 +1,2 @@
+<%@ page contentType="text/plain"%>This is plain text response for "<%= request.getMethod() %> <%= request.getRequestURI() %>".
+<% response.addHeader("X-Unit-JSP", "ok"); %>
diff --git a/test/java/mirror/app.java b/test/java/mirror/app.java
new file mode 100644
index 00000000..45bc1d0d
--- /dev/null
+++ b/test/java/mirror/app.java
@@ -0,0 +1,37 @@
+
+import java.io.*;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet("/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ StringBuilder buffer = new StringBuilder();
+ BufferedReader reader = request.getReader();
+ String line;
+
+ while ((line = reader.readLine()) != null) {
+ buffer.append(line);
+ }
+
+ String data = buffer.toString();
+
+ String dataLength = Integer.toString(data.length());
+ response.setHeader("Content-Length", dataLength);
+
+ response.setContentType("text/html");
+
+ PrintWriter out = response.getWriter();
+ out.print(data);
+ out.flush();
+ }
+}
diff --git a/test/java/path_translation/app.java b/test/java/path_translation/app.java
new file mode 100644
index 00000000..ce0b9368
--- /dev/null
+++ b/test/java/path_translation/app.java
@@ -0,0 +1,56 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.InputStream;
+
+import java.util.Set;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet( urlPatterns = { "/", "/pt/*" } )
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.addHeader("X-Request-URI", "" + request.getRequestURI());
+ response.addHeader("X-Servlet-Path", "" + request.getServletPath());
+ response.addHeader("X-Path-Info", "" + request.getPathInfo());
+ response.addHeader("X-Query-String", "" + request.getQueryString());
+ response.addHeader("X-Path-Translated", "" + request.getPathTranslated());
+
+ response.setContentType("text/plain; charset=utf-8");
+
+ PrintWriter out = response.getWriter();
+ ServletContext ctx = request.getServletContext();
+
+ String path = request.getParameter("path");
+
+ if (path != null) {
+ response.addHeader("X-Real-Path", "" + ctx.getRealPath(path));
+ response.addHeader("X-Resource", "" + ctx.getResource(path));
+
+ Set<String> paths = ctx.getResourcePaths(path);
+
+ response.addHeader("X-Resource-Paths", "" + paths);
+
+ InputStream is = ctx.getResourceAsStream(path);
+
+ response.addHeader("X-Resource-As-Stream", "" + is);
+
+ if (is != null) {
+ final byte[] buf = new byte[1024];
+ int r = is.read(buf);
+
+ out.println(new String(buf, 0, r, "utf-8"));
+ }
+ }
+ }
+}
diff --git a/test/java/path_translation/index.html b/test/java/path_translation/index.html
new file mode 100644
index 00000000..4f5a6379
--- /dev/null
+++ b/test/java/path_translation/index.html
@@ -0,0 +1 @@
+<html><body>This is index.html.</body></html>
diff --git a/test/java/post_params/app.java b/test/java/post_params/app.java
new file mode 100644
index 00000000..0ed73d42
--- /dev/null
+++ b/test/java/post_params/app.java
@@ -0,0 +1,22 @@
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet(urlPatterns = "/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.addHeader("X-Var-1", request.getParameter("var1"));
+ response.addHeader("X-Var-2", "" + (request.getParameter("var2") != null));
+ response.addHeader("X-Var-3", "" + (request.getParameter("var3") != null));
+ }
+}
diff --git a/test/java/query_string/app.java b/test/java/query_string/app.java
new file mode 100644
index 00000000..7962336b
--- /dev/null
+++ b/test/java/query_string/app.java
@@ -0,0 +1,20 @@
+
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet( urlPatterns = { "/" } )
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.addHeader("X-Query-String", "" + request.getQueryString());
+ }
+}
diff --git a/test/java/request_listeners/app.java b/test/java/request_listeners/app.java
new file mode 100644
index 00000000..6cbf7860
--- /dev/null
+++ b/test/java/request_listeners/app.java
@@ -0,0 +1,79 @@
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.annotation.WebListener;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebListener
+@WebServlet(urlPatterns = "/")
+public class app extends HttpServlet implements
+ ServletRequestListener,
+ ServletRequestAttributeListener
+{
+ private static String request_initialized = "";
+ private static String request_destroyed = "";
+ private static String attribute_added = "";
+ private static String attribute_removed = "";
+ private static String attribute_replaced = "";
+
+ @Override
+ public void requestInitialized(ServletRequestEvent sre)
+ {
+ HttpServletRequest r = (HttpServletRequest) sre.getServletRequest();
+
+ request_initialized = r.getRequestURI();
+ }
+
+ @Override
+ public void requestDestroyed(ServletRequestEvent sre)
+ {
+ HttpServletRequest r = (HttpServletRequest) sre.getServletRequest();
+
+ request_destroyed = r.getRequestURI();
+
+ attribute_added = "";
+ attribute_removed = "";
+ attribute_replaced = "";
+ }
+
+ @Override
+ public void attributeAdded(ServletRequestAttributeEvent event)
+ {
+ attribute_added += event.getName() + "=" + event.getValue() + ";";
+ }
+
+ @Override
+ public void attributeRemoved(ServletRequestAttributeEvent event)
+ {
+ attribute_removed += event.getName() + "=" + event.getValue() + ";";
+ }
+
+ @Override
+ public void attributeReplaced(ServletRequestAttributeEvent event)
+ {
+ attribute_replaced += event.getName() + "=" + event.getValue() + ";";
+ }
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ request.setAttribute("var", request.getParameter("var1"));
+ request.setAttribute("var", request.getParameter("var2"));
+ request.setAttribute("var", request.getParameter("var3"));
+
+ response.addHeader("X-Request-Initialized", request_initialized);
+ response.addHeader("X-Request-Destroyed", request_destroyed);
+ response.addHeader("X-Attr-Added", attribute_added);
+ response.addHeader("X-Attr-Removed", attribute_removed);
+ response.addHeader("X-Attr-Replaced", attribute_replaced);
+ }
+}
diff --git a/test/java/session/app.java b/test/java/session/app.java
new file mode 100644
index 00000000..84d3fa55
--- /dev/null
+++ b/test/java/session/app.java
@@ -0,0 +1,30 @@
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+@WebServlet(urlPatterns = "/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ HttpSession s = request.getSession();
+ String old_var1 = (String) s.getAttribute("var1");
+ s.setAttribute("var1", request.getParameter("var1"));
+
+ if (old_var1 == null) {
+ response.addHeader("X-Var-1", "null");
+ } else {
+ response.addHeader("X-Var-1", old_var1);
+ }
+
+ response.addHeader("X-Session-Id", s.getId());
+ response.addHeader("X-Session-New", "" + s.isNew());
+ }
+}
diff --git a/test/java/session_inactive/app.java b/test/java/session_inactive/app.java
new file mode 100644
index 00000000..f338fc89
--- /dev/null
+++ b/test/java/session_inactive/app.java
@@ -0,0 +1,27 @@
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+@WebServlet(urlPatterns = "/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ HttpSession s = request.getSession();
+
+ if (s.isNew()) {
+ s.setMaxInactiveInterval(2);
+ }
+
+ response.addHeader("X-Session-Id", s.getId());
+ response.addDateHeader("X-Session-Last-Access-Time", s.getLastAccessedTime());
+ response.addIntHeader("X-Session-Interval", s.getMaxInactiveInterval());
+ }
+}
diff --git a/test/java/session_invalidate/app.java b/test/java/session_invalidate/app.java
new file mode 100644
index 00000000..3f66290f
--- /dev/null
+++ b/test/java/session_invalidate/app.java
@@ -0,0 +1,23 @@
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+@WebServlet(urlPatterns = "/")
+public class app extends HttpServlet
+{
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ HttpSession s = request.getSession();
+
+ s.invalidate();
+
+ response.addHeader("X-Session-Id", s.getId());
+ }
+}
diff --git a/test/java/session_listeners/app.java b/test/java/session_listeners/app.java
new file mode 100644
index 00000000..603cc932
--- /dev/null
+++ b/test/java/session_listeners/app.java
@@ -0,0 +1,80 @@
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionIdListener;
+import javax.servlet.http.HttpSessionListener;
+
+@WebServlet(urlPatterns = "/")
+public class app extends HttpServlet implements
+ HttpSessionListener,
+ HttpSessionIdListener,
+ HttpSessionAttributeListener
+{
+ private static String session_created = "";
+ private static String session_destroyed = "";
+ private static String session_id_changed = "";
+ private static String attribute_added = "";
+ private static String attribute_removed = "";
+ private static String attribute_replaced = "";
+
+ @Override
+ public void sessionCreated(HttpSessionEvent se)
+ {
+ session_created += se.getSession().getId();
+ }
+
+ @Override
+ public void sessionDestroyed(HttpSessionEvent se)
+ {
+ session_destroyed += se.getSession().getId();
+ }
+
+ @Override
+ public void sessionIdChanged(HttpSessionEvent event, String oldId)
+ {
+ session_id_changed += " " + oldId + "->" + event.getSession().getId();
+ }
+
+ @Override
+ public void attributeAdded(HttpSessionBindingEvent event)
+ {
+ attribute_added += event.getName() + "=" + event.getValue();
+ }
+
+ @Override
+ public void attributeRemoved(HttpSessionBindingEvent event)
+ {
+ attribute_removed += event.getName() + "=" + event.getValue();
+ }
+
+ @Override
+ public void attributeReplaced(HttpSessionBindingEvent event)
+ {
+ attribute_replaced += event.getName() + "=" + event.getValue();
+ }
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ HttpSession s = request.getSession();
+ s.setAttribute("var1", request.getParameter("var1"));
+
+ response.addHeader("X-Session-Id", s.getId());
+ response.addHeader("X-Session-Created", session_created);
+ response.addHeader("X-Session-Destroyed", session_destroyed);
+ response.addHeader("X-Attr-Added", attribute_added);
+ response.addHeader("X-Attr-Removed", attribute_removed);
+ response.addHeader("X-Attr-Replaced", attribute_replaced);
+ }
+}
diff --git a/test/java/session_listeners/web.xml b/test/java/session_listeners/web.xml
new file mode 100644
index 00000000..aedfe175
--- /dev/null
+++ b/test/java/session_listeners/web.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+ version="3.0">
+ <listener>
+ <listener-class>app</listener-class>
+ </listener>
+ <listener>
+ <listener-class>app</listener-class>
+ </listener>
+</web-app>
+
diff --git a/test/java/url_pattern/app.java b/test/java/url_pattern/app.java
new file mode 100644
index 00000000..88b071a2
--- /dev/null
+++ b/test/java/url_pattern/app.java
@@ -0,0 +1,39 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class app extends HttpServlet
+{
+ private String id;
+
+ @Override
+ public void init(ServletConfig sc)
+ throws ServletException
+ {
+ id = sc.getInitParameter("id");
+ }
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.addHeader("X-Id", id);
+ response.addHeader("X-Request-URI", "" + request.getRequestURI());
+ response.addHeader("X-Servlet-Path", "" + request.getServletPath());
+ response.setHeader("X-Path-Info", "" + request.getPathInfo());
+
+ response.setContentType("text/plain; charset=utf-8");
+
+ PrintWriter out = response.getWriter();
+ out.println("app.doGet(): #" + this + ", " + id);
+ out.println("RequestURI: " + request.getRequestURI());
+ out.println("ServletPath: " + request.getServletPath());
+ out.println("PathInfo: " + request.getPathInfo());
+ }
+}
diff --git a/test/java/url_pattern/web.xml b/test/java/url_pattern/web.xml
new file mode 100644
index 00000000..048400a6
--- /dev/null
+++ b/test/java/url_pattern/web.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+ version="3.0">
+
+ <servlet>
+ <servlet-name>servlet0</servlet-name>
+ <servlet-class>app</servlet-class>
+ <init-param><param-name>id</param-name><param-value>servlet0</param-value></init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name>servlet1</servlet-name>
+ <servlet-class>app</servlet-class>
+ <init-param><param-name>id</param-name><param-value>servlet1</param-value></init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name>servlet2</servlet-name>
+ <servlet-class>app</servlet-class>
+ <init-param><param-name>id</param-name><param-value>servlet2</param-value></init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name>servlet3</servlet-name>
+ <servlet-class>app</servlet-class>
+ <init-param><param-name>id</param-name><param-value>servlet3</param-value></init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name>servlet4</servlet-name>
+ <servlet-class>app</servlet-class>
+ <init-param><param-name>id</param-name><param-value>servlet4</param-value></init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name>default</servlet-name>
+ <servlet-class>app</servlet-class>
+ <init-param><param-name>id</param-name><param-value>default</param-value></init-param>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>servlet0</servlet-name>
+ <url-pattern>/foo/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>servlet1</servlet-name>
+ <url-pattern>/foo/bar/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>servlet2</servlet-name>
+ <url-pattern>/baz/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>servlet3</servlet-name>
+ <url-pattern>/catalog</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>servlet4</servlet-name>
+ <url-pattern>*.bop</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>default</servlet-name>
+ <url-pattern>/</url-pattern>
+ </servlet-mapping>
+
+</web-app>
+
diff --git a/test/java/welcome_files/app.java b/test/java/welcome_files/app.java
new file mode 100644
index 00000000..ce922531
--- /dev/null
+++ b/test/java/welcome_files/app.java
@@ -0,0 +1,67 @@
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+public class app extends HttpServlet
+{
+ @WebFilter(urlPatterns = "*.jsp")
+ public static class jsp_filter implements Filter
+ {
+ @Override
+ public void init(FilterConfig filterConfig) { }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException
+ {
+ ((HttpServletResponse) response).addHeader("X-JSP-Filter", "1");
+
+ chain.doFilter(request, response);
+ }
+
+ @Override
+ public void destroy() { }
+ }
+
+ @WebFilter(urlPatterns = "*.txt")
+ public static class txt_filter implements Filter
+ {
+ @Override
+ public void init(FilterConfig filterConfig) { }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException
+ {
+ ((HttpServletResponse) response).addHeader("X-TXT-Filter", "1");
+
+ chain.doFilter(request, response);
+ }
+
+ @Override
+ public void destroy() { }
+ }
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.addHeader("X-App-Servlet", "1");
+ response.setContentType("text/plain; charset=utf-8");
+
+ PrintWriter out = response.getWriter();
+ out.println("App Servlet");
+ }
+}
diff --git a/test/java/welcome_files/dir1/index.txt b/test/java/welcome_files/dir1/index.txt
new file mode 100644
index 00000000..e7784d20
--- /dev/null
+++ b/test/java/welcome_files/dir1/index.txt
@@ -0,0 +1 @@
+This is index.txt.
diff --git a/test/java/welcome_files/dir2/default.jsp b/test/java/welcome_files/dir2/default.jsp
new file mode 100644
index 00000000..48627641
--- /dev/null
+++ b/test/java/welcome_files/dir2/default.jsp
@@ -0,0 +1,3 @@
+<%@ page contentType="text/html"%>
+<html><body><p>You should see this on <a href="/dir2/">/dir2/</a> URL.</p></body></html>
+<% response.addHeader("X-Unit-JSP", "ok"); %>
diff --git a/test/java/welcome_files/dir2/index.html b/test/java/welcome_files/dir2/index.html
new file mode 100644
index 00000000..5b111825
--- /dev/null
+++ b/test/java/welcome_files/dir2/index.html
@@ -0,0 +1 @@
+<html><body><p>You should see this on <a href="/dir2/">/dir2/</a> URL.</p></body></html>
diff --git a/test/java/welcome_files/dir3/index.txt b/test/java/welcome_files/dir3/index.txt
new file mode 100644
index 00000000..8a2b7dea
--- /dev/null
+++ b/test/java/welcome_files/dir3/index.txt
@@ -0,0 +1 @@
+You should never see this.
diff --git a/test/java/welcome_files/dir4/index.html b/test/java/welcome_files/dir4/index.html
new file mode 100644
index 00000000..2cef75e2
--- /dev/null
+++ b/test/java/welcome_files/dir4/index.html
@@ -0,0 +1 @@
+<html><body><p>You should see this for <a href="/dir4/index.html">/dir4/index.html</a> or <a href="/dir4/">/dir4/</a> url.</body></html>
diff --git a/test/java/welcome_files/index.htm b/test/java/welcome_files/index.htm
new file mode 100644
index 00000000..97e34cf5
--- /dev/null
+++ b/test/java/welcome_files/index.htm
@@ -0,0 +1 @@
+<html><body><p>You should see this ONLY for <a href="/index.htm">/index.htm</a> url.</body></html>
diff --git a/test/java/welcome_files/web.xml b/test/java/welcome_files/web.xml
new file mode 100644
index 00000000..6bbc7c8e
--- /dev/null
+++ b/test/java/welcome_files/web.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+ version="3.0">
+
+ <welcome-file-list>
+ <welcome-file>index.txt</welcome-file>
+ <welcome-file>default.jsp</welcome-file>
+ <welcome-file>index.html</welcome-file>
+ </welcome-file-list>
+
+ <servlet>
+ <servlet-name>app</servlet-name>
+ <servlet-class>app</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>app</servlet-name>
+ <url-pattern>/dir3/index.txt</url-pattern>
+ <url-pattern>/dir4/index.txt</url-pattern>
+ <url-pattern>/dir5/index.html</url-pattern>
+ </servlet-mapping>
+
+</web-app>
+
diff --git a/test/node/write_before_write_head/app.js b/test/node/write_before_write_head/app.js
index 9fe3a58d..6e3fb9a9 100755
--- a/test/node/write_before_write_head/app.js
+++ b/test/node/write_before_write_head/app.js
@@ -3,4 +3,5 @@
require('unit-http').createServer(function (req, res) {
res.write('blah');
res.writeHead(200, {'Content-Type': 'text/plain'});
+ res.end();
}).listen(7080);
diff --git a/test/perl/body_io_fake/IOFake.pm b/test/perl/body_io_fake/IOFake.pm
new file mode 100644
index 00000000..d2542aa5
--- /dev/null
+++ b/test/perl/body_io_fake/IOFake.pm
@@ -0,0 +1,33 @@
+package IOFake;
+
+sub new {
+ my $class = shift;
+ my $errors = shift;
+ my $self = {};
+
+ $self->{_count} = 2;
+ $self->{_errors} = $errors;
+
+ bless $self, $class;
+ return $self;
+}
+
+sub getline() {
+ my $self = shift;
+
+ if ($self->{_count} > 0) {
+ return $self->{_count}--;
+ }
+
+ $self->{_errors}->print('IOFake getline() $/ is ' . ${ $/ });
+
+ return;
+}
+
+sub close() {
+ my $self = shift;
+
+ $self->{_errors}->print('IOFake close() called');
+};
+
+1;
diff --git a/test/perl/body_io_fake/psgi.pl b/test/perl/body_io_fake/psgi.pl
new file mode 100644
index 00000000..6990bfaf
--- /dev/null
+++ b/test/perl/body_io_fake/psgi.pl
@@ -0,0 +1,11 @@
+use File::Basename;
+use lib dirname (__FILE__);
+use IOFake;
+
+my $app = sub {
+ my ($environ) = @_;
+
+ my $io = IOFake->new($environ->{'psgi.errors'});
+
+ return ['200', [ 'Content-Length' => '2' ], $io];
+};
diff --git a/test/perl/delayed_response/psgi.pl b/test/perl/delayed_response/psgi.pl
new file mode 100644
index 00000000..f934c3a7
--- /dev/null
+++ b/test/perl/delayed_response/psgi.pl
@@ -0,0 +1,10 @@
+my $app = sub {
+ my ($environ) = @_;
+
+ return sub {
+ (my $responder = shift)->([200, [
+ 'Content-Type' => 'text/plain',
+ 'Content-Length' => '12'
+ ], ["Hello World!"]]);
+ }
+};
diff --git a/test/perl/streaming_body/psgi.pl b/test/perl/streaming_body/psgi.pl
new file mode 100644
index 00000000..a3e54ee0
--- /dev/null
+++ b/test/perl/streaming_body/psgi.pl
@@ -0,0 +1,13 @@
+my $app = sub {
+ my ($environ) = @_;
+
+ return sub {
+ my $writer = (my $responder = shift)->([200, [
+ 'Content-Type' => 'text/plain',
+ 'Content-Length' => '12'
+ ]]);
+
+ $writer->write("Hello World!");
+ $writer->close;
+ };
+};
diff --git a/test/php/date_time/index.php b/test/php/date_time/index.php
index 4e06fdf9..42992c3f 100644
--- a/test/php/date_time/index.php
+++ b/test/php/date_time/index.php
@@ -1,4 +1,5 @@
<?php
-$d = new DateTime('2011-01-01T15:03:01.012345Z');
+date_default_timezone_set('Europe/Moscow');
+$d = new DateTime('2011-01-01T15:03:01.012345');
echo $d->format('u');
?>
diff --git a/test/php/highlight_file_exec/index.php b/test/php/highlight_file_exec/index.php
deleted file mode 100644
index adcd5ed8..00000000
--- a/test/php/highlight_file_exec/index.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-highlight_file('index.php');
-exec('pwd');
-?>
diff --git a/test/php/query_string/index.php b/test/php/query_string/index.php
new file mode 100644
index 00000000..5691324d
--- /dev/null
+++ b/test/php/query_string/index.php
@@ -0,0 +1,4 @@
+<?php
+header('Content-Length: 0');
+header('Query-String: ' . $_SERVER['QUERY_STRING']);
+?>
diff --git a/test/php/time_exec/index.php b/test/php/time_exec/index.php
new file mode 100644
index 00000000..05d59d28
--- /dev/null
+++ b/test/php/time_exec/index.php
@@ -0,0 +1,4 @@
+<?php
+echo 'time: ' . time();
+echo 'exec: ' . exec('pwd');
+?>
diff --git a/test/python/host/wsgi.py b/test/python/host/wsgi.py
new file mode 100644
index 00000000..db7de306
--- /dev/null
+++ b/test/python/host/wsgi.py
@@ -0,0 +1,7 @@
+def application(env, start_response):
+ start_response('200', [
+ ('Content-Length', '0'),
+ ('X-Server-Name', env.get('SERVER_NAME')),
+ ('X-Http-Host', str(env.get('HTTP_HOST')))
+ ])
+ return []
diff --git a/test/test_access_log.py b/test/test_access_log.py
index c8464796..d6741c28 100644
--- a/test/test_access_log.py
+++ b/test/test_access_log.py
@@ -23,9 +23,9 @@ class TestUnitAccessLog(unit.TestUnitApplicationPython):
self.load('mirror')
(resp, sock) = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, body='01234')
time.sleep(0.2)
@@ -34,9 +34,9 @@ class TestUnitAccessLog(unit.TestUnitApplicationPython):
self.search_in_log(r'"POST / HTTP/1.1" 200 5'), 'keepalive 1')
resp = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'close',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, sock=sock, body='0123456789')
time.sleep(0.2)
diff --git a/test/test_configuration.py b/test/test_configuration.py
index 02705afe..52a67d38 100644
--- a/test/test_configuration.py
+++ b/test/test_configuration.py
@@ -132,7 +132,6 @@ class TestUnitConfiguration(unit.TestUnitControl):
self.skip_sanitizer = True
self.skip_alerts.extend([
r'failed to apply previous configuration',
- r'sendmsg.+failed',
r'process \d+ exited on signal'
])
@@ -217,5 +216,53 @@ class TestUnitConfiguration(unit.TestUnitControl):
}
}), 'no port')
+ @unittest.expectedFailure
+ def test_json_application_name_large(self):
+ self.skip_alerts.append(r'epoll_ctl.+failed')
+ name = "X" * 1024 * 1024
+
+ self.assertIn('success', self.conf({
+ "listeners": {
+ "*:7080": {
+ "application": name
+ }
+ },
+ "applications": {
+ name: {
+ "type": "python",
+ "processes": { "spare": 0 },
+ "path": "/app",
+ "module": "wsgi"
+ }
+ }
+ }))
+
+ @unittest.expectedFailure
+ def test_json_application_many(self):
+ self.skip_alerts.extend([
+ r'eventfd.+failed',
+ r'epoll_create.+failed',
+ r'failed to apply new conf'
+ ])
+ apps = 999
+
+ conf = {
+ "applications":
+ {"app-" + str(a): {
+ "type": "python",
+ "processes": { "spare": 0 },
+ "path": "/app",
+ "module": "wsgi"
+ } for a in range(apps)
+ },
+ "listeners": {
+ "*:" + str(7000 + a): {
+ "application": "app-" + str(a)
+ } for a in range(apps)
+ }
+ }
+
+ self.assertIn('success', self.conf(conf))
+
if __name__ == '__main__':
TestUnitConfiguration.main()
diff --git a/test/test_go_application.py b/test/test_go_application.py
index fd80bf5b..1ecc2536 100644
--- a/test/test_go_application.py
+++ b/test/test_go_application.py
@@ -4,12 +4,7 @@ import unit
class TestUnitGoApplication(unit.TestUnitApplicationGo):
def setUpClass():
- u = unit.TestUnit()
-
- if u.architecture == '32bit':
- raise unittest.SkipTest('Skip Go tests for x86')
-
- u.check_modules('go')
+ unit.TestUnit().check_modules('go')
def test_go_application_variables(self):
self.load('variables')
@@ -19,7 +14,8 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
resp = self.post(headers={
'Host': 'localhost',
'Content-Type': 'text/html',
- 'Custom-Header': 'blah'
+ 'Custom-Header': 'blah',
+ 'Connection': 'close'
}, body=body)
self.assertEqual(resp['status'], 200, 'status')
@@ -41,7 +37,8 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
'Server-Protocol': 'HTTP/1.1',
'Server-Protocol-Major': '1',
'Server-Protocol-Minor': '1',
- 'Custom-Header': 'blah'
+ 'Custom-Header': 'blah',
+ 'Connection': 'close'
}, 'headers')
self.assertEqual(resp['body'], body, 'body')
@@ -57,8 +54,8 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
self.load('post_variables')
resp = self.post(headers={
- 'Content-Type': 'application/x-www-form-urlencoded',
'Host': 'localhost',
+ 'Content-Type': 'application/x-www-form-urlencoded',
'Connection': 'close'
}, body='var1=val1&var2=&var3')
@@ -79,17 +76,17 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
self.load('mirror')
(resp, sock) = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, body='0123456789' * 500)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={
- 'Connection': 'close',
+ 'Host': 'localhost',
'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Connection': 'close'
}, sock=sock, body='0123456789')
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
@@ -98,8 +95,8 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
self.load('cookies')
resp = self.get(headers={
- 'Cookie': 'var1=val1; var2=val2',
'Host': 'localhost',
+ 'Cookie': 'var1=val1; var2=val2',
'Connection': 'close'
})
diff --git a/test/test_http_header.py b/test/test_http_header.py
index b850831d..f2294371 100644
--- a/test/test_http_header.py
+++ b/test/test_http_header.py
@@ -10,7 +10,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython):
self.load('custom_header')
resp = self.get(headers={
- 'Custom-Header': ' ,'
+ 'Host': 'localhost',
+ 'Custom-Header': ' ,',
+ 'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'value leading sp status')
@@ -21,7 +23,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython):
self.load('custom_header')
resp = self.get(headers={
- 'Custom-Header': '\t,'
+ 'Host': 'localhost',
+ 'Custom-Header': '\t,',
+ 'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'value leading htab status')
@@ -32,7 +36,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython):
self.load('custom_header')
resp = self.get(headers={
- 'Custom-Header': ', '
+ 'Host': 'localhost',
+ 'Custom-Header': ', ',
+ 'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'value trailing sp status')
@@ -43,7 +49,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython):
self.load('custom_header')
resp = self.get(headers={
- 'Custom-Header': ',\t'
+ 'Host': 'localhost',
+ 'Custom-Header': ',\t',
+ 'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'value trailing htab status')
@@ -54,7 +62,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython):
self.load('custom_header')
resp = self.get(headers={
- 'Custom-Header': ' , '
+ 'Host': 'localhost',
+ 'Custom-Header': ' , ',
+ 'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'value both sp status')
@@ -65,7 +75,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython):
self.load('custom_header')
resp = self.get(headers={
- 'Custom-Header': '\t,\t'
+ 'Host': 'localhost',
+ 'Custom-Header': '\t,\t',
+ 'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'value both htab status')
@@ -76,7 +88,9 @@ class TestUnitHTTPHeader(unit.TestUnitApplicationPython):
self.load('custom_header')
resp = self.get(headers={
- 'Custom-Header': '(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~'
+ 'Host': 'localhost',
+ 'Custom-Header': '(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~',
+ 'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'value chars status')
@@ -113,7 +127,9 @@ Connection: close
self.load('empty')
resp = self.get(headers={
- ' Custom-Header': 'blah'
+ 'Host': 'localhost',
+ ' Custom-Header': 'blah',
+ 'Connection': 'close'
})
self.assertEqual(resp['status'], 400, 'field leading sp')
@@ -122,7 +138,9 @@ Connection: close
self.load('empty')
resp = self.get(headers={
- '\tCustom-Header': 'blah'
+ 'Host': 'localhost',
+ '\tCustom-Header': 'blah',
+ 'Connection': 'close'
})
self.assertEqual(resp['status'], 400, 'field leading htab')
@@ -131,7 +149,9 @@ Connection: close
self.load('empty')
resp = self.get(headers={
- 'Custom-Header ': 'blah'
+ 'Host': 'localhost',
+ 'Custom-Header ': 'blah',
+ 'Connection': 'close'
})
self.assertEqual(resp['status'], 400, 'field trailing sp')
@@ -140,27 +160,204 @@ Connection: close
self.load('empty')
resp = self.get(headers={
- 'Custom-Header\t': 'blah'
+ 'Host': 'localhost',
+ 'Custom-Header\t': 'blah',
+ 'Connection': 'close'
})
self.assertEqual(resp['status'], 400, 'field trailing htab')
- @unittest.expectedFailure
- def test_http_header_transfer_encoding_chunked(self):
+ def test_http_header_content_length_big(self):
self.load('empty')
- resp = self.http(b"""GET / HTTP/1.1
-Host: localhost
-Transfer-Encoding: chunked
-Connection: close
+ self.assertEqual(self.post(headers={
+ 'Host': 'localhost',
+ 'Content-Length': str(2 ** 64),
+ 'Connection': 'close'
+ }, body='X' * 1000)['status'], 400, 'Content-Length big')
-a
-0123456789
-0
+ def test_http_header_content_length_negative(self):
+ self.load('empty')
-""", raw=True)
+ self.assertEqual(self.post(headers={
+ 'Host': 'localhost',
+ 'Content-Length': '-100',
+ 'Connection': 'close'
+ }, body='X' * 1000)['status'], 400, 'Content-Length negative')
+
+ def test_http_header_content_length_text(self):
+ self.load('empty')
+
+ self.assertEqual(self.post(headers={
+ 'Host': 'localhost',
+ 'Content-Length': 'blah',
+ 'Connection': 'close'
+ }, body='X' * 1000)['status'], 400, 'Content-Length text')
+
+ def test_http_header_content_length_multiple_values(self):
+ self.load('empty')
+
+ self.assertEqual(self.post(headers={
+ 'Host': 'localhost',
+ 'Content-Length': '41, 42',
+ 'Connection': 'close'
+ }, body='X' * 1000)['status'], 400, 'Content-Length multiple value')
+
+ def test_http_header_content_length_multiple_fields(self):
+ self.load('empty')
+
+ self.assertEqual(self.post(headers={
+ 'Host': 'localhost',
+ 'Content-Length': ['41', '42'],
+ 'Connection': 'close'
+ }, body='X' * 1000)['status'], 400, 'Content-Length multiple fields')
+
+ def test_http_header_host_absent(self):
+ self.load('host')
+
+ resp = self.get(headers={'Connection': 'close'})
+
+ self.assertEqual(resp['status'], 200, 'Host absent status')
+ self.assertNotEqual(resp['headers']['X-Server-Name'], '',
+ 'Host absent SERVER_NAME')
+
+ def test_http_header_host_empty(self):
+ self.load('host')
+
+ resp = self.get(headers={
+ 'Host': '',
+ 'Connection': 'close'
+ })
+
+ self.assertEqual(resp['status'], 200, 'Host empty status')
+ self.assertNotEqual(resp['headers']['X-Server-Name'], '',
+ 'Host empty SERVER_NAME')
+
+ def test_http_header_host_big(self):
+ self.load('empty')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'X' * 10000,
+ 'Connection': 'close'
+ })['status'], 431, 'Host big')
+
+ def test_http_header_host_port(self):
+ self.load('host')
+
+ resp = self.get(headers={
+ 'Host': 'exmaple.com:7080',
+ 'Connection': 'close'
+ })
+
+ self.assertEqual(resp['status'], 200, 'Host port status')
+ self.assertEqual(resp['headers']['X-Server-Name'], 'exmaple.com',
+ 'Host port SERVER_NAME')
+ self.assertEqual(resp['headers']['X-Http-Host'], 'exmaple.com:7080',
+ 'Host port HTTP_HOST')
+
+ def test_http_header_host_port_empty(self):
+ self.load('host')
+
+ resp = self.get(headers={
+ 'Host': 'exmaple.com:',
+ 'Connection': 'close'
+ })
+
+ self.assertEqual(resp['status'], 200, 'Host port empty status')
+ self.assertEqual(resp['headers']['X-Server-Name'], 'exmaple.com',
+ 'Host port empty SERVER_NAME')
+ self.assertEqual(resp['headers']['X-Http-Host'], 'exmaple.com:',
+ 'Host port empty HTTP_HOST')
+
+ def test_http_header_host_literal(self):
+ self.load('host')
+
+ resp = self.get(headers={
+ 'Host': '127.0.0.1',
+ 'Connection': 'close'
+ })
+
+ self.assertEqual(resp['status'], 200, 'Host literal status')
+ self.assertEqual(resp['headers']['X-Server-Name'], '127.0.0.1',
+ 'Host literal SERVER_NAME')
+
+ def test_http_header_host_literal_ipv6(self):
+ self.load('host')
+
+ resp = self.get(headers={
+ 'Host': '[::1]:7080',
+ 'Connection': 'close'
+ })
+
+ self.assertEqual(resp['status'], 200, 'Host literal ipv6 status')
+ self.assertEqual(resp['headers']['X-Server-Name'], '[::1]',
+ 'Host literal ipv6 SERVER_NAME')
+ self.assertEqual(resp['headers']['X-Http-Host'], '[::1]:7080',
+ 'Host literal ipv6 HTTP_HOST')
+
+ def test_http_header_host_trailing_period(self):
+ self.load('host')
+
+ resp = self.get(headers={
+ 'Host': '127.0.0.1.',
+ 'Connection': 'close'
+ })
+
+ self.assertEqual(resp['status'], 200, 'Host trailing period status')
+ self.assertEqual(resp['headers']['X-Server-Name'], '127.0.0.1',
+ 'Host trailing period SERVER_NAME')
+ self.assertEqual(resp['headers']['X-Http-Host'], '127.0.0.1.',
+ 'Host trailing period HTTP_HOST')
+
+ def test_http_header_host_trailing_period_2(self):
+ self.load('host')
+
+ resp = self.get(headers={
+ 'Host': 'EXAMPLE.COM.',
+ 'Connection': 'close'
+ })
+
+ self.assertEqual(resp['status'], 200, 'Host trailing period 2 status')
+ self.assertEqual(resp['headers']['X-Server-Name'], 'example.com',
+ 'Host trailing period 2 SERVER_NAME')
+ self.assertEqual(resp['headers']['X-Http-Host'], 'EXAMPLE.COM.',
+ 'Host trailing period 2 HTTP_HOST')
+
+ def test_http_header_host_case_insensitive(self):
+ self.load('host')
+
+ resp = self.get(headers={
+ 'Host': 'EXAMPLE.COM',
+ 'Connection': 'close'
+ })
+
+ self.assertEqual(resp['status'], 200, 'Host case insensitive')
+ self.assertEqual(resp['headers']['X-Server-Name'], 'example.com',
+ 'Host case insensitive SERVER_NAME')
+
+ def test_http_header_host_double_dot(self):
+ self.load('empty')
+
+ self.assertEqual(self.get(headers={
+ 'Host': '127.0.0..1',
+ 'Connection': 'close'
+ })['status'], 400, 'Host double dot')
+
+ def test_http_header_host_slash(self):
+ self.load('empty')
+
+ self.assertEqual(self.get(headers={
+ 'Host': '/localhost',
+ 'Connection': 'close'
+ })['status'], 400, 'Host slash')
+
+ def test_http_header_host_multiple_fields(self):
+ self.load('empty')
- self.assertEqual(resp['status'], 200, 'transfer encoding chunked')
+ self.assertEqual(self.get(headers={
+ 'Host': ['localhost', 'example.com'],
+ 'Connection': 'close'
+ })['status'], 400, 'Host multiple fields')
if __name__ == '__main__':
TestUnitHTTPHeader.main()
diff --git a/test/test_java_application.py b/test/test_java_application.py
new file mode 100644
index 00000000..d603ed0f
--- /dev/null
+++ b/test/test_java_application.py
@@ -0,0 +1,753 @@
+import time
+import unittest
+import unit
+
+class TestUnitJavaApplication(unit.TestUnitApplicationJava):
+
+ def setUpClass():
+ unit.TestUnit().check_modules('java')
+
+ def test_java_application_cookies(self):
+ self.load('cookies')
+
+ headers = self.get(headers={
+ 'Cookie': 'var1=val1; var2=val2',
+ 'Host': 'localhost',
+ 'Connection': 'close'
+ })['headers']
+
+ self.assertEqual(headers['X-Cookie-1'], 'val1', 'cookie 1')
+ self.assertEqual(headers['X-Cookie-2'], 'val2', 'cookie 2')
+
+ def test_java_application_filter(self):
+ self.load('filter')
+
+ headers = self.get()['headers']
+
+ self.assertEqual(headers['X-Filter-Before'], '1', 'filter before')
+ self.assertEqual(headers['X-Filter-After'], '1', 'filter after')
+
+ self.assertEqual(self.get(url='/test')['headers']['X-Filter-After'],
+ '0', 'filter after 2')
+
+ def test_java_application_get_variables(self):
+ self.load('get_params')
+
+ headers = self.get(url='/?var1=val1&var2=&var4=val4&var4=foo')['headers']
+
+ self.assertEqual(headers['X-Var-1'], 'val1', 'GET variables')
+ self.assertEqual(headers['X-Var-2'], 'true', 'GET variables 2')
+ self.assertEqual(headers['X-Var-3'], 'false', 'GET variables 3')
+
+ self.assertEqual(headers['X-Param-Names'], 'var4 var2 var1 ',
+ 'getParameterNames')
+ self.assertEqual(headers['X-Param-Values'], 'val4 foo ',
+ 'getParameterValues')
+ self.assertEqual(headers['X-Param-Map'],
+ 'var2= var1=val1 var4=val4,foo ', 'getParameterMap')
+
+ def test_java_application_post_variables(self):
+ self.load('post_params')
+
+ headers = self.post(headers={
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Host': 'localhost',
+ 'Connection': 'close'
+ }, body='var1=val1&var2=')['headers']
+
+ self.assertEqual(headers['X-Var-1'], 'val1', 'POST variables')
+ self.assertEqual(headers['X-Var-2'], 'true', 'POST variables 2')
+ self.assertEqual(headers['X-Var-3'], 'false', 'POST variables 3')
+
+ def test_java_application_session(self):
+ self.load('session')
+
+ headers = self.get(url='/?var1=val1')['headers']
+ session_id = headers['X-Session-Id']
+
+ self.assertEqual(headers['X-Var-1'], 'null', 'variable empty')
+ self.assertEqual(headers['X-Session-New'], 'true', 'session create')
+
+ headers = self.get(headers={
+ 'Host': 'localhost',
+ 'Cookie': 'JSESSIONID=' + session_id,
+ 'Connection': 'close'
+ }, url='/?var1=val2')['headers']
+
+ self.assertEqual(headers['X-Var-1'], 'val1', 'variable')
+ self.assertEqual(headers['X-Session-New'], 'false', 'session resume')
+ self.assertEqual(session_id, headers['X-Session-Id'], 'session same id')
+
+ def test_java_application_session_active(self):
+ self.load('session_inactive')
+
+ resp = self.get()
+ session_id = resp['headers']['X-Session-Id']
+
+ self.assertEqual(resp['status'], 200, 'session init')
+ self.assertEqual(resp['headers']['X-Session-Interval'], '2',
+ 'session interval')
+ self.assertLess(abs(self.date_to_sec_epoch(
+ resp['headers']['X-Session-Last-Access-Time']) - self.sec_epoch()),
+ 5, 'session last access time')
+
+ time.sleep(1)
+
+ resp = self.get(headers={
+ 'Host': 'localhost',
+ 'Cookie': 'JSESSIONID=' + session_id,
+ 'Connection': 'close'
+ })
+
+ self.assertEqual(resp['headers']['X-Session-Id'], session_id,
+ 'session active')
+
+ session_id = resp['headers']['X-Session-Id']
+
+ time.sleep(1)
+
+ resp = self.get(headers={
+ 'Host': 'localhost',
+ 'Cookie': 'JSESSIONID=' + session_id,
+ 'Connection': 'close'
+ })
+
+ self.assertEqual(resp['headers']['X-Session-Id'], session_id,
+ 'session active 2')
+
+ time.sleep(1)
+
+ resp = self.get(headers={
+ 'Host': 'localhost',
+ 'Cookie': 'JSESSIONID=' + session_id,
+ 'Connection': 'close'
+ })
+
+ self.assertEqual(resp['headers']['X-Session-Id'], session_id,
+ 'session active 3')
+
+ def test_java_application_session_inactive(self):
+ self.load('session_inactive')
+
+ resp = self.get()
+ session_id = resp['headers']['X-Session-Id']
+
+ time.sleep(3)
+
+ resp = self.get(headers={
+ 'Host': 'localhost',
+ 'Cookie': 'JSESSIONID=' + session_id,
+ 'Connection': 'close'
+ })
+
+ self.assertNotEqual(resp['headers']['X-Session-Id'], session_id,
+ 'session inactive')
+
+ def test_java_application_session_invalidate(self):
+ self.load('session_invalidate')
+
+ resp = self.get()
+ session_id = resp['headers']['X-Session-Id']
+
+ resp = self.get(headers={
+ 'Host': 'localhost',
+ 'Cookie': 'JSESSIONID=' + session_id,
+ 'Connection': 'close'
+ })
+
+ self.assertNotEqual(resp['headers']['X-Session-Id'], session_id,
+ 'session invalidate')
+
+ def test_java_application_session_listeners(self):
+ self.load('session_listeners')
+
+ headers = self.get(url='/test?var1=val1')['headers']
+ session_id = headers['X-Session-Id']
+
+ self.assertEqual(headers['X-Session-Created'], session_id,
+ 'session create')
+ self.assertEqual(headers['X-Attr-Added'], 'var1=val1',
+ 'attribute add')
+
+ headers = self.get(headers={
+ 'Host': 'localhost',
+ 'Cookie': 'JSESSIONID=' + session_id,
+ 'Connection': 'close'
+ }, url='/?var1=val2')['headers']
+
+ self.assertEqual(session_id, headers['X-Session-Id'], 'session same id')
+ self.assertEqual(headers['X-Attr-Replaced'], 'var1=val1',
+ 'attribute replace')
+
+ headers = self.get(headers={
+ 'Host': 'localhost',
+ 'Cookie': 'JSESSIONID=' + session_id,
+ 'Connection': 'close'
+ }, url='/')['headers']
+
+ self.assertEqual(session_id, headers['X-Session-Id'], 'session same id')
+ self.assertEqual(headers['X-Attr-Removed'], 'var1=val2',
+ 'attribute remove')
+
+ def test_java_application_jsp(self):
+ self.load('jsp')
+
+ headers = self.get(url='/index.jsp')['headers']
+
+ self.assertEqual(headers['X-Unit-JSP'], 'ok', 'JSP Ok header')
+
+ def test_java_application_url_pattern(self):
+ self.load('url_pattern')
+
+ headers = self.get(url='/foo/bar/index.html')['headers']
+
+ self.assertEqual(headers['X-Id'], 'servlet1', '#1 Servlet1 request')
+ self.assertEqual(headers['X-Request-URI'], '/foo/bar/index.html', '#1 request URI')
+ self.assertEqual(headers['X-Servlet-Path'], '/foo/bar', '#1 servlet path')
+ self.assertEqual(headers['X-Path-Info'], '/index.html', '#1 path info')
+
+ headers = self.get(url='/foo/bar/index.bop')['headers']
+
+ self.assertEqual(headers['X-Id'], 'servlet1', '#2 Servlet1 request')
+ self.assertEqual(headers['X-Request-URI'], '/foo/bar/index.bop', '#2 request URI')
+ self.assertEqual(headers['X-Servlet-Path'], '/foo/bar', '#2 servlet path')
+ self.assertEqual(headers['X-Path-Info'], '/index.bop', '#2 path info')
+
+ headers = self.get(url='/baz')['headers']
+
+ self.assertEqual(headers['X-Id'], 'servlet2', '#3 Servlet2 request')
+ self.assertEqual(headers['X-Request-URI'], '/baz', '#3 request URI')
+ self.assertEqual(headers['X-Servlet-Path'], '/baz', '#3 servlet path')
+ self.assertEqual(headers['X-Path-Info'], 'null', '#3 path info')
+
+ headers = self.get(url='/baz/index.html')['headers']
+
+ self.assertEqual(headers['X-Id'], 'servlet2', '#4 Servlet2 request')
+ self.assertEqual(headers['X-Request-URI'], '/baz/index.html', '#4 request URI')
+ self.assertEqual(headers['X-Servlet-Path'], '/baz', '#4 servlet path')
+ self.assertEqual(headers['X-Path-Info'], '/index.html', '#4 path info')
+
+ headers = self.get(url='/catalog')['headers']
+
+ self.assertEqual(headers['X-Id'], 'servlet3', '#5 Servlet3 request')
+ self.assertEqual(headers['X-Request-URI'], '/catalog', '#5 request URI')
+ self.assertEqual(headers['X-Servlet-Path'], '/catalog', '#5 servlet path')
+ self.assertEqual(headers['X-Path-Info'], 'null', '#5 path info')
+
+ headers = self.get(url='/catalog/index.html')['headers']
+
+ self.assertEqual(headers['X-Id'], 'default', '#6 default request')
+ self.assertEqual(headers['X-Request-URI'], '/catalog/index.html', '#6 request URI')
+ self.assertEqual(headers['X-Servlet-Path'], '/catalog/index.html', '#6 servlet path')
+ self.assertEqual(headers['X-Path-Info'], 'null', '#6 path info')
+
+ headers = self.get(url='/catalog/racecar.bop')['headers']
+
+ self.assertEqual(headers['X-Id'], 'servlet4', '#7 servlet4 request')
+ self.assertEqual(headers['X-Request-URI'], '/catalog/racecar.bop', '#7 request URI')
+ self.assertEqual(headers['X-Servlet-Path'], '/catalog/racecar.bop', '#7 servlet path')
+ self.assertEqual(headers['X-Path-Info'], 'null', '#7 path info')
+
+ headers = self.get( url='/index.bop')['headers']
+
+ self.assertEqual(headers['X-Id'], 'servlet4', '#8 servlet4 request')
+ self.assertEqual(headers['X-Request-URI'], '/index.bop', '#8 request URI')
+ self.assertEqual(headers['X-Servlet-Path'], '/index.bop', '#8 servlet path')
+ self.assertEqual(headers['X-Path-Info'], 'null', '#8 path info')
+
+ headers = self.get(url='/foo/baz')['headers']
+
+ self.assertEqual(headers['X-Id'], 'servlet0', '#9 servlet0 request')
+ self.assertEqual(headers['X-Request-URI'], '/foo/baz', '#9 request URI')
+ self.assertEqual(headers['X-Servlet-Path'], '/foo', '#9 servlet path')
+ self.assertEqual(headers['X-Path-Info'], '/baz', '#9 path info')
+
+ headers = self.get()['headers']
+
+ self.assertEqual(headers['X-Id'], 'default', '#10 default request')
+ self.assertEqual(headers['X-Request-URI'], '/', '#10 request URI')
+ self.assertEqual(headers['X-Servlet-Path'], '/', '#10 servlet path')
+ self.assertEqual(headers['X-Path-Info'], 'null', '#10 path info')
+
+ headers = self.get(url='/index.bop/')['headers']
+
+ self.assertEqual(headers['X-Id'], 'default', '#11 default request')
+ self.assertEqual(headers['X-Request-URI'], '/index.bop/', '#11 request URI')
+ self.assertEqual(headers['X-Servlet-Path'], '/index.bop/', '#11 servlet path')
+ self.assertEqual(headers['X-Path-Info'], 'null', '#11 path info')
+
+ def test_java_application_header(self):
+ self.load('header')
+
+ headers = self.get()['headers']
+
+ self.assertEqual(headers['X-Set-Utf8-Value'], '????', 'set Utf8 header value')
+ self.assertEqual(headers['X-Set-Utf8-Name-???'], 'x', 'set Utf8 header name')
+ self.assertEqual(headers['X-Add-Utf8-Value'], '????', 'add Utf8 header value')
+ self.assertEqual(headers['X-Add-Utf8-Name-???'], 'y', 'add Utf8 header name')
+ self.assertEqual(headers['X-Add-Test'], 'v1', 'add null header')
+ self.assertEqual('X-Set-Test1' in headers, False, 'set null header')
+ self.assertEqual(headers['X-Set-Test2'], '', 'set empty header')
+
+ def test_java_application_content_type(self):
+ self.load('content_type')
+
+ headers = self.get(url='/1')['headers']
+
+ self.assertEqual(headers['Content-Type'], 'text/plain;charset=utf-8', '#1 Content-Type header')
+ self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=utf-8', '#1 response Content-Type')
+ self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#1 response charset')
+
+ headers = self.get(url='/2')['headers']
+
+ self.assertEqual(headers['Content-Type'], 'text/plain;charset=iso-8859-1', '#2 Content-Type header')
+ self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=iso-8859-1', '#2 response Content-Type')
+ self.assertEqual(headers['X-Character-Encoding'], 'iso-8859-1', '#2 response charset')
+
+ headers = self.get(url='/3')['headers']
+
+ self.assertEqual(headers['Content-Type'], 'text/plain;charset=windows-1251', '#3 Content-Type header')
+ self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=windows-1251', '#3 response Content-Type')
+ self.assertEqual(headers['X-Character-Encoding'], 'windows-1251', '#3 response charset')
+
+ headers = self.get(url='/4')['headers']
+
+ self.assertEqual(headers['Content-Type'], 'text/plain;charset=windows-1251', '#4 Content-Type header')
+ self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=windows-1251', '#4 response Content-Type')
+ self.assertEqual(headers['X-Character-Encoding'], 'windows-1251', '#4 response charset')
+
+ headers = self.get(url='/5')['headers']
+
+ self.assertEqual(headers['Content-Type'], 'text/plain;charset=iso-8859-1', '#5 Content-Type header')
+ self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=iso-8859-1', '#5 response Content-Type')
+ self.assertEqual(headers['X-Character-Encoding'], 'iso-8859-1', '#5 response charset')
+
+ headers = self.get(url='/6')['headers']
+
+ self.assertEqual('Content-Type' in headers, False, '#6 no Content-Type header')
+ self.assertEqual('X-Content-Type' in headers, False, '#6 no response Content-Type')
+ self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#6 response charset')
+
+
+ headers = self.get(url='/7')['headers']
+
+ self.assertEqual(headers['Content-Type'], 'text/plain;charset=utf-8', '#7 Content-Type header')
+ self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=utf-8', '#7 response Content-Type')
+ self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#7 response charset')
+
+ headers = self.get(url='/8')['headers']
+
+ self.assertEqual(headers['Content-Type'], 'text/html;charset=utf-8', '#8 Content-Type header')
+ self.assertEqual(headers['X-Content-Type'], 'text/html;charset=utf-8', '#8 response Content-Type')
+ self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#8 response charset')
+
+ def test_java_application_welcome_files(self):
+ self.load('welcome_files')
+
+ headers = self.get()['headers']
+
+ resp = self.get(url='/dir1')
+
+ self.assertEqual(resp['status'], 302, 'dir redirect expected')
+
+ resp = self.get(url='/dir1/')
+
+ self.assertEqual('This is index.txt.' in resp['body'], True, 'dir1 index body')
+ self.assertEqual(resp['headers']['X-TXT-Filter'], '1', 'TXT Filter header')
+
+ headers = self.get(url='/dir2/')['headers']
+
+ self.assertEqual(headers['X-Unit-JSP'], 'ok', 'JSP Ok header')
+ self.assertEqual(headers['X-JSP-Filter'], '1', 'JSP Filter header')
+
+ headers = self.get(url='/dir3/')['headers']
+
+ self.assertEqual(headers['X-App-Servlet'], '1', 'URL pattern overrides welcome file')
+
+ headers = self.get(url='/dir4/')['headers']
+
+ self.assertEqual('X-App-Servlet' in headers, False, 'Static welcome file served first')
+
+ headers = self.get(url='/dir5/')['headers']
+
+ self.assertEqual(headers['X-App-Servlet'], '1', 'Servlet for welcome file served when no static file found')
+
+ def test_java_application_request_listeners(self):
+ self.load('request_listeners')
+
+ headers = self.get(url='/test1')['headers']
+
+ self.assertEqual(headers['X-Request-Initialized'], '/test1',
+ 'request initialized event')
+ self.assertEqual(headers['X-Request-Destroyed'], '',
+ 'request destroyed event')
+ self.assertEqual(headers['X-Attr-Added'], '',
+ 'attribute added event')
+ self.assertEqual(headers['X-Attr-Removed'], '',
+ 'attribute removed event')
+ self.assertEqual(headers['X-Attr-Replaced'], '',
+ 'attribute replaced event')
+
+ headers = self.get(url='/test2?var1=1')['headers']
+
+ self.assertEqual(headers['X-Request-Initialized'], '/test2',
+ 'request initialized event')
+ self.assertEqual(headers['X-Request-Destroyed'], '/test1',
+ 'request destroyed event')
+ self.assertEqual(headers['X-Attr-Added'], 'var=1;',
+ 'attribute added event')
+ self.assertEqual(headers['X-Attr-Removed'], 'var=1;',
+ 'attribute removed event')
+ self.assertEqual(headers['X-Attr-Replaced'], '',
+ 'attribute replaced event')
+
+ headers = self.get(url='/test3?var1=1&var2=2')['headers']
+
+ self.assertEqual(headers['X-Request-Initialized'], '/test3',
+ 'request initialized event')
+ self.assertEqual(headers['X-Request-Destroyed'], '/test2',
+ 'request destroyed event')
+ self.assertEqual(headers['X-Attr-Added'], 'var=1;',
+ 'attribute added event')
+ self.assertEqual(headers['X-Attr-Removed'], 'var=2;',
+ 'attribute removed event')
+ self.assertEqual(headers['X-Attr-Replaced'], 'var=1;',
+ 'attribute replaced event')
+
+ headers = self.get(url='/test4?var1=1&var2=2&var3=3')['headers']
+
+ self.assertEqual(headers['X-Request-Initialized'], '/test4',
+ 'request initialized event')
+ self.assertEqual(headers['X-Request-Destroyed'], '/test3',
+ 'request destroyed event')
+ self.assertEqual(headers['X-Attr-Added'], 'var=1;',
+ 'attribute added event')
+ self.assertEqual(headers['X-Attr-Removed'], '',
+ 'attribute removed event')
+ self.assertEqual(headers['X-Attr-Replaced'], 'var=1;var=2;',
+ 'attribute replaced event')
+
+ def test_java_application_request_uri_forward(self):
+ self.load('forward')
+
+ resp = self.get(url='/fwd?uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4')
+ headers = resp['headers']
+
+ self.assertEqual(headers['X-REQUEST-Id'], 'fwd',
+ 'initial request servlet mapping')
+ self.assertEqual(headers['X-Forward-To'], '/data/test?uri=new_uri&a=2&b=3',
+ 'forwarding triggered')
+ self.assertEqual(headers['X-REQUEST-Param-uri'], '/data/test?uri=new_uri&a=2&b=3',
+ 'original uri parameter')
+ self.assertEqual(headers['X-REQUEST-Param-a'], '1',
+ 'original a parameter')
+ self.assertEqual(headers['X-REQUEST-Param-c'], '4',
+ 'original c parameter')
+
+ self.assertEqual(headers['X-FORWARD-Id'], 'data',
+ 'forward request servlet mapping')
+ self.assertEqual(headers['X-FORWARD-Request-URI'], '/data/test',
+ 'forward request uri')
+ self.assertEqual(headers['X-FORWARD-Servlet-Path'], '/data',
+ 'forward request servlet path')
+ self.assertEqual(headers['X-FORWARD-Path-Info'], '/test',
+ 'forward request path info')
+ self.assertEqual(headers['X-FORWARD-Query-String'], 'uri=new_uri&a=2&b=3',
+ 'forward request query string')
+ self.assertEqual(headers['X-FORWARD-Param-uri'], 'new_uri,/data/test?uri=new_uri&a=2&b=3',
+ 'forward uri parameter')
+ self.assertEqual(headers['X-FORWARD-Param-a'], '2,1',
+ 'forward a parameter')
+ self.assertEqual(headers['X-FORWARD-Param-b'], '3',
+ 'forward b parameter')
+ self.assertEqual(headers['X-FORWARD-Param-c'], '4',
+ 'forward c parameter')
+
+ self.assertEqual(headers['X-javax.servlet.forward.request_uri'], '/fwd',
+ 'original request uri')
+ self.assertEqual(headers['X-javax.servlet.forward.context_path'], '',
+ 'original request context path')
+ self.assertEqual(headers['X-javax.servlet.forward.servlet_path'], '/fwd',
+ 'original request servlet path')
+ self.assertEqual(headers['X-javax.servlet.forward.path_info'], 'null',
+ 'original request path info')
+ self.assertEqual(headers['X-javax.servlet.forward.query_string'], 'uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4',
+ 'original request query')
+
+ self.assertEqual('Before forwarding' in resp['body'], False,
+ 'discarded data added before forward() call')
+ self.assertEqual('X-After-Forwarding' in headers, False,
+ 'cannot add headers after forward() call')
+ self.assertEqual('After forwarding' in resp['body'], False,
+ 'cannot add data after forward() call')
+
+ def test_java_application_named_dispatcher_forward(self):
+ self.load('forward')
+
+ resp = self.get(url='/fwd?disp=name&uri=data')
+ headers = resp['headers']
+
+ self.assertEqual(headers['X-REQUEST-Id'], 'fwd',
+ 'initial request servlet mapping')
+ self.assertEqual(headers['X-Forward-To'], 'data',
+ 'forwarding triggered')
+
+ self.assertEqual(headers['X-FORWARD-Id'], 'data',
+ 'forward request servlet mapping')
+ self.assertEqual(headers['X-FORWARD-Request-URI'], '/fwd',
+ 'forward request uri')
+ self.assertEqual(headers['X-FORWARD-Servlet-Path'], '/fwd',
+ 'forward request servlet path')
+ self.assertEqual(headers['X-FORWARD-Path-Info'], 'null',
+ 'forward request path info')
+ self.assertEqual(headers['X-FORWARD-Query-String'], 'disp=name&uri=data',
+ 'forward request query string')
+
+ self.assertEqual(headers['X-javax.servlet.forward.request_uri'], 'null',
+ 'original request uri')
+ self.assertEqual(headers['X-javax.servlet.forward.context_path'], 'null',
+ 'original request context path')
+ self.assertEqual(headers['X-javax.servlet.forward.servlet_path'], 'null',
+ 'original request servlet path')
+ self.assertEqual(headers['X-javax.servlet.forward.path_info'], 'null',
+ 'original request path info')
+ self.assertEqual(headers['X-javax.servlet.forward.query_string'], 'null',
+ 'original request query')
+
+ self.assertEqual('Before forwarding' in resp['body'], False,
+ 'discarded data added before forward() call')
+ self.assertEqual('X-After-Forwarding' in headers, False,
+ 'cannot add headers after forward() call')
+ self.assertEqual('After forwarding' in resp['body'], False,
+ 'cannot add data after forward() call')
+
+ def test_java_application_request_uri_include(self):
+ self.load('include')
+
+ resp = self.get(url='/inc?uri=/data/test')
+ headers = resp['headers']
+ body = resp['body']
+
+ self.assertEqual(headers['X-REQUEST-Id'], 'inc',
+ 'initial request servlet mapping')
+ self.assertEqual(headers['X-Include'], '/data/test',
+ 'including triggered')
+
+ self.assertEqual('X-INCLUDE-Id' in headers, False,
+ 'unable to add headers in include request')
+
+ self.assertEqual('javax.servlet.include.request_uri: /data/test' in body,
+ True, 'include request uri')
+# self.assertEqual('javax.servlet.include.context_path: ' in body,
+# 'include request context path')
+ self.assertEqual('javax.servlet.include.servlet_path: /data' in body,
+ True, 'include request servlet path')
+ self.assertEqual('javax.servlet.include.path_info: /test' in body,
+ True, 'include request path info')
+ self.assertEqual('javax.servlet.include.query_string: null' in body,
+ True, 'include request query')
+
+ self.assertEqual('Before include' in body, True,
+ 'preserve data added before include() call')
+ self.assertEqual(headers['X-After-Include'], 'you-should-see-this',
+ 'add headers after include() call')
+ self.assertEqual('After include' in body, True,
+ 'add data after include() call')
+
+ def test_java_application_named_dispatcher_include(self):
+ self.load('include')
+
+ resp = self.get(url='/inc?disp=name&uri=data')
+ headers = resp['headers']
+ body = resp['body']
+
+ self.assertEqual(headers['X-REQUEST-Id'], 'inc',
+ 'initial request servlet mapping')
+ self.assertEqual(headers['X-Include'], 'data',
+ 'including triggered')
+
+ self.assertEqual('X-INCLUDE-Id' in headers, False,
+ 'unable to add headers in include request')
+
+ self.assertEqual('javax.servlet.include.request_uri: null' in body,
+ True, 'include request uri')
+# self.assertEqual('javax.servlet.include.context_path: null' in body,
+# 'include request context path')
+ self.assertEqual('javax.servlet.include.servlet_path: null' in body,
+ True, 'include request servlet path')
+ self.assertEqual('javax.servlet.include.path_info: null' in body,
+ True, 'include request path info')
+ self.assertEqual('javax.servlet.include.query_string: null' in body,
+ True, 'include request query')
+
+ self.assertEqual('Before include' in body, True,
+ 'preserve data added before include() call')
+ self.assertEqual(headers['X-After-Include'], 'you-should-see-this',
+ 'add headers after include() call')
+ self.assertEqual('After include' in body, True,
+ 'add data after include() call')
+
+ def test_java_application_path_translation(self):
+ self.load('path_translation')
+
+ headers = self.get(url='/pt/test?path=/')['headers']
+
+ self.assertEqual(headers['X-Servlet-Path'], '/pt',
+ 'matched servlet path')
+ self.assertEqual(headers['X-Path-Info'], '/test',
+ 'the rest of the path')
+ self.assertEqual(headers['X-Path-Translated'],
+ headers['X-Real-Path'] + headers['X-Path-Info'],
+ 'translated path is the app root + path info')
+ self.assertEqual(
+ headers['X-Resource-Paths'].endswith('/WEB-INF/, /index.html]'),
+ True, 'app root directory content')
+ self.assertEqual(headers['X-Resource-As-Stream'], 'null',
+ 'no resource stream for root path')
+
+ headers = self.get(url='/test?path=/none')['headers']
+
+ self.assertEqual(headers['X-Servlet-Path'], '/test',
+ 'matched whole path')
+ self.assertEqual(headers['X-Path-Info'], 'null',
+ 'the rest of the path is null, whole path matched')
+ self.assertEqual(headers['X-Path-Translated'], 'null',
+ 'translated path is null because path info is null')
+ self.assertEqual(headers['X-Real-Path'].endswith('/none'), True,
+ 'read path is not null')
+ self.assertEqual(headers['X-Resource-Paths'], 'null',
+ 'no resource found')
+ self.assertEqual(headers['X-Resource-As-Stream'], 'null',
+ 'no resource stream')
+
+ def test_java_application_query_string(self):
+ self.load('query_string')
+
+ self.assertEqual(self.get(url='/?a=b')['headers']['X-Query-String'],
+ 'a=b', 'query string')
+
+ def test_java_application_query_empty(self):
+ self.load('query_string')
+
+ self.assertEqual(self.get(url='/?')['headers']['X-Query-String'], '',
+ 'query string empty')
+
+ def test_java_application_query_absent(self):
+ self.load('query_string')
+
+ self.assertEqual(self.get()['headers']['X-Query-String'], 'null',
+ 'query string absent')
+
+ def test_java_application_empty(self):
+ self.load('empty')
+
+ self.assertEqual(self.get()['status'], 200, 'empty')
+
+ def test_java_application_keepalive_body(self):
+ self.load('mirror')
+
+ (resp, sock) = self.post(headers={
+ 'Connection': 'keep-alive',
+ 'Content-Type': 'text/html',
+ 'Host': 'localhost'
+ }, start=True, body='0123456789' * 500)
+
+ self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
+
+ resp = self.post(headers={
+ 'Connection': 'close',
+ 'Content-Type': 'text/html',
+ 'Host': 'localhost'
+ }, sock=sock, body='0123456789')
+
+ self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
+
+ def test_java_application_http_10(self):
+ self.load('empty')
+
+ self.assertEqual(self.get(http_10=True)['status'], 200, 'HTTP 1.0')
+
+ def test_java_application_no_method(self):
+ self.load('empty')
+
+ self.assertEqual(self.post()['status'], 405, 'no method')
+
+ def test_java_application_get_header(self):
+ self.load('get_header')
+
+ self.assertEqual(self.get(headers={
+ 'X-Header': 'blah',
+ 'Content-Type': 'text/html',
+ 'Host': 'localhost'
+ })['headers']['X-Reply'], 'blah', 'get header')
+
+ def test_java_application_get_header_empty(self):
+ self.load('get_header')
+
+ self.assertNotIn('X-Reply', self.get()['headers'], 'get header empty')
+
+ def test_java_application_get_headers(self):
+ self.load('get_headers')
+
+ headers = self.get(headers={
+ 'X-Header': ['blah', 'blah'],
+ 'Content-Type': 'text/html',
+ 'Host': 'localhost'
+ })['headers']
+
+ self.assertEqual(headers['X-Reply-0'], 'blah', 'get headers')
+ self.assertEqual(headers['X-Reply-1'], 'blah', 'get headers 2')
+
+ def test_java_application_get_headers_empty(self):
+ self.load('get_headers')
+
+ self.assertNotIn('X-Reply-0', self.get()['headers'],
+ 'get headers empty')
+
+ def test_java_application_get_header_names(self):
+ self.load('get_header_names')
+
+ headers = self.get()['headers']
+
+ self.assertRegex(headers['X-Reply-0'], r'(?:Host|Connection)',
+ 'get header names')
+ self.assertRegex(headers['X-Reply-1'], r'(?:Host|Connection)',
+ 'get header names 2')
+ self.assertNotEqual(headers['X-Reply-0'], headers['X-Reply-1'],
+ 'get header names not equal')
+
+ def test_java_application_get_header_names_empty(self):
+ self.load('get_header_names')
+
+ self.assertNotIn('X-Reply-0', self.get(headers={})['headers'],
+ 'get header names empty')
+
+ def test_java_application_header_int(self):
+ self.load('header_int')
+
+ headers = self.get(headers={
+ 'X-Header': '2',
+ 'Content-Type': 'text/html',
+ 'Host': 'localhost'
+ })['headers']
+
+ self.assertEqual(headers['X-Set-Int'], '1', 'set int header')
+ self.assertEqual(headers['X-Get-Int'], '2', 'get int header')
+
+ def test_java_application_header_date(self):
+ self.load('header_date')
+
+ date = 'Fri, 15 Mar 2019 14:45:34 GMT'
+
+ headers = self.get(headers={
+ 'X-Header': date,
+ 'Content-Type': 'text/html',
+ 'Host': 'localhost'
+ })['headers']
+
+ self.assertEqual(headers['X-Set-Date'], 'Thu, 01 Jan 1970 00:00:01 GMT',
+ 'set date header')
+ self.assertEqual(headers['X-Get-Date'], date, 'get date header')
+
+if __name__ == '__main__':
+ TestUnitJavaApplication.main()
diff --git a/test/test_node_application.py b/test/test_node_application.py
index 5dedb5a3..cd64fefa 100644
--- a/test/test_node_application.py
+++ b/test/test_node_application.py
@@ -28,7 +28,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
resp = self.post(headers={
'Host': 'localhost',
'Content-Type': 'text/html',
- 'Custom-Header': 'blah'
+ 'Custom-Header': 'blah',
+ 'Connection': 'close'
}, body=body)
self.assertEqual(resp['status'], 200, 'status')
@@ -43,10 +44,11 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
raw_headers = headers.pop('Request-Raw-Headers')
self.assertRegex(raw_headers, r'^(?:Host|localhost|Content-Type|' \
- 'text\/html|Custom-Header|blah|Content-Length|17|,)+$',
- 'raw headers')
+ 'text\/html|Custom-Header|blah|Content-Length|17|Connection|' \
+ 'close|,)+$', 'raw headers')
self.assertDictEqual(headers, {
+ 'Connection': 'close',
'Content-Length': str(len(body)),
'Content-Type': 'text/html',
'Request-Method': 'POST',
@@ -91,17 +93,17 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.load('mirror')
(resp, sock) = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, body='0123456789' * 500)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'close',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, sock=sock, body='0123456789')
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
@@ -112,7 +114,6 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.assertEqual(self.get()['body'], '6\r\nbuffer\r\n0\r\n\r\n',
'write buffer')
- @unittest.expectedFailure
def test_node_application_write_callback(self):
self.load('write_callback')
@@ -121,11 +122,10 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.assertTrue(self.waitforfiles(self.testdir + '/node/callback'),
'write callback')
- def test_node_application_write_before_writeHead(self):
- self.skip_alerts.append(r'process \d+ exited on signal')
+ def test_node_application_write_before_write_head(self):
self.load('write_before_write_head')
- self.get()
+ self.assertEqual(self.get()['status'], 200, 'write before writeHead')
def test_node_application_double_end(self):
self.load('double_end')
@@ -144,7 +144,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
resp = self.get(headers={
'Host': 'localhost',
- 'X-Remove': 'X-Header'
+ 'X-Remove': 'X-Header',
+ 'Connection': 'close'
})
self.assertEqual(resp['headers']['Was-Header'], 'true', 'was header')
self.assertEqual(resp['headers']['Has-Header'], 'false', 'has header')
@@ -155,7 +156,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.assertEqual(self.get(headers={
'Host': 'localhost',
- 'X-Remove': 'blah'
+ 'X-Remove': 'blah',
+ 'Connection': 'close'
})['headers']['Has-Header'], 'true', 'remove header nonexisting')
def test_node_application_update_header(self):
@@ -182,7 +184,6 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.assertEqual(self.get()['headers']['X-Type'], 'number',
'get header type')
- @unittest.expectedFailure
def test_node_application_header_name_case(self):
self.load('header_name_case')
@@ -197,20 +198,20 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.assertEqual(self.post(headers={
'Host': 'localhost',
- 'Content-Type': 'text/html'
+ 'Content-Type': 'text/html',
+ 'Connection': 'close'
}, body='callback')['status'], 200, 'promise handler request')
self.assertTrue(self.waitforfiles(self.testdir + '/node/callback'),
'promise handler')
- @unittest.expectedFailure
def test_node_application_promise_handler_write_after_end(self):
- self.skip_alerts.append(r'process \d+ exited on signal')
self.load('promise_handler')
self.assertEqual(self.post(headers={
'Host': 'localhost',
'Content-Type': 'text/html',
- 'X-Write-Call': '1'
+ 'X-Write-Call': '1',
+ 'Connection': 'close'
}, body='callback')['status'], 200,
'promise handler request write after end')
@@ -219,7 +220,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.assertEqual(self.post(headers={
'Host': 'localhost',
- 'Content-Type': 'text/html'
+ 'Content-Type': 'text/html',
+ 'Connection': 'close'
}, body='end')['status'], 200, 'promise end request')
self.assertTrue(self.waitforfiles(self.testdir + '/node/callback'),
'promise end')
@@ -229,7 +231,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.post(headers={
'Host': 'localhost',
- 'Content-Type': 'text/html'
+ 'Content-Type': 'text/html',
+ 'Connection': 'close'
}, body='callback1')
self.assertTrue(self.waitforfiles(self.testdir + '/node/callback1'),
@@ -237,7 +240,8 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.post(headers={
'Host': 'localhost',
- 'Content-Type': 'text/html'
+ 'Content-Type': 'text/html',
+ 'Connection': 'close'
}, body='callback2')
self.assertTrue(self.waitforfiles(self.testdir + '/node/callback2'),
@@ -249,13 +253,11 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.assertNotIn('status', self.get(), 'header name valid')
- @unittest.expectedFailure
def test_node_application_header_value_object(self):
self.load('header_value_object')
self.assertIn('X-Header', self.get()['headers'], 'header value object')
- @unittest.expectedFailure
def test_node_application_get_header_names(self):
self.load('get_header_names')
@@ -267,12 +269,14 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.assertEqual(self.get(headers={
'Host': 'localhost',
- 'X-Header': 'length'
+ 'X-Header': 'length',
+ 'Connection': 'close'
})['headers']['X-Has-Header'], 'false', 'has header length')
self.assertEqual(self.get(headers={
'Host': 'localhost',
- 'X-Header': 'Date'
+ 'X-Header': 'Date',
+ 'Connection': 'close'
})['headers']['X-Has-Header'], 'false', 'has header date')
def test_node_application_write_multiple(self):
diff --git a/test/test_perl_application.py b/test/test_perl_application.py
index c9cb3f0c..b169baab 100644
--- a/test/test_perl_application.py
+++ b/test/test_perl_application.py
@@ -14,7 +14,8 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
resp = self.post(headers={
'Host': 'localhost',
'Content-Type': 'text/html',
- 'Custom-Header': 'blah'
+ 'Custom-Header': 'blah',
+ 'Connection': 'close'
}, body=body)
self.assertEqual(resp['status'], 200, 'status')
@@ -30,6 +31,7 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
'date header')
self.assertDictEqual(headers, {
+ 'Connection': 'close',
'Content-Length': str(len(body)),
'Content-Type': 'text/html',
'Request-Method': 'POST',
@@ -43,7 +45,7 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
'Psgi-Multiprocess': '1',
'Psgi-Run-Once': '',
'Psgi-Nonblocking': '',
- 'Psgi-Streaming': ''
+ 'Psgi-Streaming': '1'
}, 'headers')
self.assertEqual(resp['body'], body, 'body')
@@ -55,6 +57,25 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2',
'Query-String header')
+ def test_perl_application_query_string_empty(self):
+ self.load('query_string')
+
+ resp = self.get(url='/?')
+
+ self.assertEqual(resp['status'], 200, 'query string empty status')
+ self.assertEqual(resp['headers']['Query-String'], '',
+ 'query string empty')
+
+ @unittest.expectedFailure
+ def test_perl_application_query_string_absent(self):
+ self.load('query_string')
+
+ resp = self.get()
+
+ self.assertEqual(resp['status'], 200, 'query string absent status')
+ self.assertEqual(resp['headers']['Query-String'], '',
+ 'query string absent')
+
@unittest.expectedFailure
def test_perl_application_server_port(self):
self.load('server_port')
@@ -151,20 +172,49 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
self.load('variables')
(resp, sock) = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, body='0123456789' * 500)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'close',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, sock=sock, body='0123456789')
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
+ def test_perl_body_io_fake(self):
+ self.load('body_io_fake')
+
+ self.assertEqual(self.get()['body'], '21', 'body io fake')
+
+ self.assertIsNotNone(
+ self.search_in_log(r'\[error\].+IOFake getline\(\) \$\/ is \d+'),
+ 'body io fake $/ value')
+
+ self.assertIsNotNone(
+ self.search_in_log(r'\[error\].+IOFake close\(\) called'),
+ 'body io fake close')
+
+ def test_perl_delayed_response(self):
+ self.load('delayed_response')
+
+ resp = self.get()
+
+ self.assertEqual(resp['status'], 200, 'status')
+ self.assertEqual(resp['body'], 'Hello World!', 'body')
+
+ def test_perl_streaming_body(self):
+ self.load('streaming_body')
+
+ resp = self.get()
+
+ self.assertEqual(resp['status'], 200, 'status')
+ self.assertEqual(resp['body'], 'Hello World!', 'body')
+
if __name__ == '__main__':
TestUnitPerlApplication.main()
diff --git a/test/test_php_application.py b/test/test_php_application.py
index e0058d9a..ac74359d 100644
--- a/test/test_php_application.py
+++ b/test/test_php_application.py
@@ -7,9 +7,11 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
def setUpClass():
unit.TestUnit().check_modules('php')
- def search_disabled(self, name):
- p = re.compile(name + '\(\) has been disabled')
- return self.search_in_log(p)
+ def before_disable_functions(self):
+ body = self.get()['body']
+
+ self.assertRegex(body, r'time: \d+', 'disable_functions before time')
+ self.assertRegex(body, r'exec: \/\w+', 'disable_functions before exec')
def test_php_application_variables(self):
self.load('variables')
@@ -19,7 +21,8 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
resp = self.post(headers={
'Host': 'localhost',
'Content-Type': 'text/html',
- 'Custom-Header': 'blah'
+ 'Custom-Header': 'blah',
+ 'Connection': 'close'
}, body=body)
self.assertEqual(resp['status'], 200, 'status')
@@ -39,6 +42,7 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
headers.pop('Content-type')
self.assertDictEqual(headers, {
+ 'Connection': 'close',
'Content-Length': str(len(body)),
'Request-Method': 'POST',
'Request-Uri': '/',
@@ -48,6 +52,33 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
}, 'headers')
self.assertEqual(resp['body'], body, 'body')
+ def test_php_application_query_string(self):
+ self.load('query_string')
+
+ resp = self.get(url='/?var1=val1&var2=val2')
+
+ self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2',
+ 'query string')
+
+ def test_php_application_query_string_empty(self):
+ self.load('query_string')
+
+ resp = self.get(url='/?')
+
+ self.assertEqual(resp['status'], 200, 'query string empty status')
+ self.assertEqual(resp['headers']['Query-String'], '',
+ 'query string empty')
+
+ @unittest.expectedFailure
+ def test_php_application_query_string_absent(self):
+ self.load('query_string')
+
+ resp = self.get()
+
+ self.assertEqual(resp['status'], 200, 'query string absent status')
+ self.assertEqual(resp['headers']['Query-String'], '',
+ 'query string absent')
+
def test_php_application_phpinfo(self):
self.load('phpinfo')
@@ -69,17 +100,17 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
self.load('mirror')
(resp, sock) = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, body='0123456789' * 500)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'close',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, sock=sock, body='0123456789')
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
@@ -210,109 +241,97 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
'ini value repeat')
def test_php_application_disable_functions_exec(self):
- self.load('highlight_file_exec')
-
- self.conf({"admin": { "disable_functions": "exec" }},
- 'applications/highlight_file_exec/options')
-
- self.get()
-
- self.assertIsNotNone(self.search_disabled('exec'),
- 'disable_functions exec')
- self.assertIsNone(self.search_disabled('highlight_file'),
- 'disable_functions highlight_file')
+ self.load('time_exec')
- def test_php_application_disable_functions_highlight_file(self):
- self.load('highlight_file_exec')
+ self.before_disable_functions()
- self.conf({"admin": { "disable_functions": "highlight_file" }},
- 'applications/highlight_file_exec/options')
+ self.conf({"admin": { "disable_functions": "exec" }},
+ 'applications/time_exec/options')
- self.get()
+ body = self.get()['body']
- self.assertIsNone(self.search_disabled('exec'),
- 'disable_functions exec')
- self.assertIsNotNone(self.search_disabled('highlight_file'),
- 'disable_functions highlight_file')
+ self.assertRegex(body, r'time: \d+', 'disable_functions time')
+ self.assertNotRegex(body, r'exec: \/\w+', 'disable_functions exec')
def test_php_application_disable_functions_comma(self):
- self.load('highlight_file_exec')
+ self.load('time_exec')
+
+ self.before_disable_functions()
- self.conf({"admin": { "disable_functions": "exec,highlight_file" }},
- 'applications/highlight_file_exec/options')
+ self.conf({"admin": { "disable_functions": "exec,time" }},
+ 'applications/time_exec/options')
- self.get()
+ body = self.get()['body']
- self.assertIsNotNone(self.search_disabled('exec'),
- 'disable_functions exec')
- self.assertIsNotNone(self.search_disabled('highlight_file'),
- 'disable_functions highlight_file')
+ self.assertNotRegex(body, r'time: \d+', 'disable_functions comma time')
+ self.assertNotRegex(body, r'exec: \/\w+',
+ 'disable_functions comma exec')
def test_php_application_disable_functions_space(self):
- self.load('highlight_file_exec')
+ self.load('time_exec')
- self.conf({"admin": { "disable_functions": "exec highlight_file" }},
- 'applications/highlight_file_exec/options')
+ self.before_disable_functions()
- self.get()
+ self.conf({"admin": { "disable_functions": "exec time" }},
+ 'applications/time_exec/options')
- self.assertIsNotNone(self.search_disabled('exec'),
- 'disable_functions exec')
- self.assertIsNotNone(self.search_disabled('highlight_file'),
- 'disable_functions highlight_file')
+ body = self.get()['body']
+
+ self.assertNotRegex(body, r'time: \d+', 'disable_functions space time')
+ self.assertNotRegex(body, r'exec: \/\w+',
+ 'disable_functions space exec')
def test_php_application_disable_functions_user(self):
- self.load('highlight_file_exec')
+ self.load('time_exec')
+
+ self.before_disable_functions()
self.conf({"user": { "disable_functions": "exec" }},
- 'applications/highlight_file_exec/options')
+ 'applications/time_exec/options')
- self.get()
+ body = self.get()['body']
- self.assertIsNotNone(self.search_disabled('exec'),
- 'disable_functions exec')
- self.assertIsNone(self.search_disabled('highlight_file'),
- 'disable_functions highlight_file')
+ self.assertRegex(body, r'time: \d+', 'disable_functions user time')
+ self.assertNotRegex(body, r'exec: \/\w+', 'disable_functions user exec')
def test_php_application_disable_functions_nonexistent(self):
- self.load('highlight_file_exec')
+ self.load('time_exec')
+
+ self.before_disable_functions()
self.conf({"admin": { "disable_functions": "blah" }},
- 'applications/highlight_file_exec/options')
+ 'applications/time_exec/options')
- self.get()
+ body = self.get()['body']
- self.assertIsNone(self.search_disabled('exec'),
- 'disable_functions exec')
- self.assertIsNone(self.search_disabled('highlight_file'),
- 'disable_functions highlight_file')
+ self.assertRegex(body, r'time: \d+',
+ 'disable_functions nonexistent time')
+ self.assertRegex(body, r'exec: \/\w+',
+ 'disable_functions nonexistent exec')
def test_php_application_disable_classes(self):
self.load('date_time')
- self.get()
-
- self.assertIsNone(self.search_disabled('DateTime'),
+ self.assertRegex(self.get()['body'], r'012345',
'disable_classes before')
self.conf({"admin": { "disable_classes": "DateTime" }},
'applications/date_time/options')
- self.get()
-
- self.assertIsNotNone(self.search_disabled('DateTime'),
- 'disable_classes')
+ self.assertNotRegex(self.get()['body'], r'012345',
+ 'disable_classes before')
def test_php_application_disable_classes_user(self):
self.load('date_time')
+ self.assertRegex(self.get()['body'], r'012345',
+ 'disable_classes before')
+
self.conf({"user": { "disable_classes": "DateTime" }},
'applications/date_time/options')
- self.get()
-
- self.assertIsNotNone(self.search_disabled('DateTime'),
- 'disable_classes user')
+ self.assertNotRegex(self.get()['body'], r'012345',
+ 'disable_classes before')
if __name__ == '__main__':
TestUnitPHPApplication.main()
diff --git a/test/test_python_application.py b/test/test_python_application.py
index 667047bc..a8631085 100644
--- a/test/test_python_application.py
+++ b/test/test_python_application.py
@@ -1,3 +1,4 @@
+import time
import unittest
import unit
@@ -14,7 +15,8 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
resp = self.post(headers={
'Host': 'localhost',
'Content-Type': 'text/html',
- 'Custom-Header': 'blah'
+ 'Custom-Header': 'blah',
+ 'Connection': 'close'
}, body=body)
self.assertEqual(resp['status'], 200, 'status')
@@ -30,6 +32,7 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
'date header')
self.assertDictEqual(headers, {
+ 'Connection': 'close',
'Content-Length': str(len(body)),
'Content-Type': 'text/html',
'Request-Method': 'POST',
@@ -53,6 +56,24 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2',
'Query-String header')
+ def test_python_application_query_string_empty(self):
+ self.load('query_string')
+
+ resp = self.get(url='/?')
+
+ self.assertEqual(resp['status'], 200, 'query string empty status')
+ self.assertEqual(resp['headers']['Query-String'], '',
+ 'query string empty')
+
+ def test_python_application_query_string_absent(self):
+ self.load('query_string')
+
+ resp = self.get()
+
+ self.assertEqual(resp['status'], 200, 'query string absent status')
+ self.assertEqual(resp['headers']['Query-String'], '',
+ 'query string absent')
+
@unittest.expectedFailure
def test_python_application_server_port(self):
self.load('server_port')
@@ -67,13 +88,12 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
'204 header transfer encoding')
def test_python_application_ctx_iter_atexit(self):
- self.skip_alerts.append(r'sendmsg.+failed')
self.load('ctx_iter_atexit')
resp = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'close',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, body='0123456789')
self.assertEqual(resp['status'], 200, 'ctx iter status')
@@ -86,6 +106,8 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
self.stop()
+ time.sleep(0.2)
+
self.assertIsNotNone(self.search_in_log(r'RuntimeError'),
'ctx iter atexit')
@@ -93,26 +115,22 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
self.load('mirror')
(resp, sock) = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, body='0123456789' * 500)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'close',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, sock=sock, body='0123456789')
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
def test_python_keepalive_reconfigure(self):
- self.skip_alerts.extend([
- r'sendmsg.+failed',
- r'recvmsg.+failed'
- ])
self.load('mirror')
body = '0123456789'
@@ -121,9 +139,9 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
for i in range(conns):
(resp, sock) = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, body=body)
self.assertEqual(resp['body'], body, 'keep-alive open')
@@ -136,9 +154,9 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
for i in range(conns):
(resp, sock) = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, sock=socks[i], body=body)
self.assertEqual(resp['body'], body, 'keep-alive request')
@@ -149,9 +167,9 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
for i in range(conns):
resp = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'close',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, sock=socks[i], body=body)
self.assertEqual(resp['body'], body, 'keep-alive close')
@@ -161,15 +179,14 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
}, 'applications/mirror/processes'), 'reconfigure 3')
def test_python_keepalive_reconfigure_2(self):
- self.skip_alerts.append(r'sendmsg.+failed')
self.load('mirror')
body = '0123456789'
(resp, sock) = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, body=body)
self.assertEqual(resp['body'], body, 'reconfigure 2 keep-alive 1')
@@ -177,9 +194,9 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
self.load('empty')
(resp, sock) = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'close',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, sock=sock, body=body)
self.assertEqual(resp['status'], 200, 'reconfigure 2 keep-alive 2')
@@ -195,7 +212,6 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
self.assertEqual(resp, {}, 'reconfigure 2 keep-alive 3')
def test_python_keepalive_reconfigure_3(self):
- self.skip_alerts.append(r'sendmsg.+failed')
self.load('empty')
(resp, sock) = self.http(b"""GET / HTTP/1.1
@@ -214,7 +230,6 @@ Connection: close
self.assertEqual(resp['status'], 200, 'reconfigure 3')
def test_python_atexit(self):
- self.skip_alerts.append(r'sendmsg.+failed')
self.load('atexit')
self.get()
diff --git a/test/test_python_procman.py b/test/test_python_procman.py
index 65268d49..2efe59c0 100644
--- a/test/test_python_procman.py
+++ b/test/test_python_procman.py
@@ -226,7 +226,7 @@ class TestUnitPythonProcman(unit.TestUnitApplicationPython):
(resp, sock) = self.get(headers={
'Host': 'localhost',
'Connection': 'keep-alive'
- }, start=True)
+ }, start=True, read_timeout=1)
self.assertEqual(len(self.pids_for_process()), 1,
'keepalive connection 1')
diff --git a/test/test_routing.py b/test/test_routing.py
new file mode 100644
index 00000000..07097fc8
--- /dev/null
+++ b/test/test_routing.py
@@ -0,0 +1,458 @@
+import unittest
+import unit
+
+class TestUnitRouting(unit.TestUnitApplicationProto):
+
+ def setUpClass():
+ unit.TestUnit().check_modules('python')
+
+ def setUp(self):
+ super().setUp()
+
+ self.conf({
+ "listeners": {
+ "*:7080": {
+ "pass": "routes"
+ }
+ },
+ "routes": [{
+ "match": { "method": "GET" },
+ "action": { "pass": "applications/empty" }
+ }],
+ "applications": {
+ "empty": {
+ "type": "python",
+ "processes": { "spare": 0 },
+ "path": self.current_dir + '/python/empty',
+ "working_directory": self.current_dir + '/python/empty',
+ "module": "wsgi"
+ },
+ "mirror": {
+ "type": "python",
+ "processes": { "spare": 0 },
+ "path": self.current_dir + '/python/mirror',
+ "working_directory": self.current_dir + '/python/mirror',
+ "module": "wsgi"
+ }
+ }
+ })
+
+ def test_routes_match_method_positive(self):
+ self.assertEqual(self.get()['status'], 200, 'method positive GET')
+ self.assertEqual(self.post()['status'], 404, 'method positive POST')
+
+ def test_routes_match_method_positive_many(self):
+ self.assertIn('success', self.conf([{
+ "match": { "method": ["GET", "POST"] },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'method positive many configure')
+
+ self.assertEqual(self.get()['status'], 200, 'method positive many GET')
+ self.assertEqual(self.post()['status'], 200,
+ 'method positive many POST')
+ self.assertEqual(self.delete()['status'], 404,
+ 'method positive many DELETE')
+
+ def test_routes_match_method_negative(self):
+ self.assertIn('success', self.conf([{
+ "match": { "method": "!GET" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'method negative configure')
+
+ self.assertEqual(self.get()['status'], 404, 'method negative GET')
+ self.assertEqual(self.post()['status'], 200, 'method negative POST')
+
+ def test_routes_match_method_negative_many(self):
+ self.assertIn('success', self.conf([{
+ "match": { "method": ["!GET", "!POST"] },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'method negative many configure')
+
+ self.assertEqual(self.get()['status'], 404, 'method negative many GET')
+ self.assertEqual(self.post()['status'], 404,
+ 'method negative many POST')
+ self.assertEqual(self.delete()['status'], 200,
+ 'method negative many DELETE')
+
+ def test_routes_match_method_wildcard_left(self):
+ self.assertIn('success', self.conf([{
+ "match": { "method": "*ET" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'method wildcard left configure')
+
+ self.assertEqual(self.get()['status'], 200, 'method wildcard left GET')
+ self.assertEqual(self.post()['status'], 404,
+ 'method wildcard left POST')
+
+ def test_routes_match_method_wildcard_right(self):
+ self.assertIn('success', self.conf([{
+ "match": { "method": "GE*" },
+ "action": { "pass": "applications/empty"}
+ }], 'routes'), 'method wildcard right configure')
+
+ self.assertEqual(self.get()['status'], 200,
+ 'method wildcard right GET')
+ self.assertEqual(self.post()['status'], 404,
+ 'method wildcard right POST')
+
+ def test_routes_match_method_wildcard_left_right(self):
+ self.assertIn('success', self.conf([{
+ "match": { "method": "*GET*" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'method wildcard left right configure')
+
+ self.assertEqual(self.get()['status'], 200,
+ 'method wildcard right GET')
+ self.assertEqual(self.post()['status'], 404,
+ 'method wildcard right POST')
+
+ def test_routes_match_method_wildcard(self):
+ self.assertIn('success', self.conf([{
+ "match": { "method": "*" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'method wildcard configure')
+
+ self.assertEqual(self.get()['status'], 200, 'method wildcard')
+
+ def test_routes_match_method_case_insensitive(self):
+ self.assertIn('success', self.conf([{
+ "match": { "method": "get" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'method case insensitive configure')
+
+ self.assertEqual(self.get()['status'], 200, 'method case insensitive')
+
+ def test_routes_absent(self):
+ self.conf({
+ "listeners": {
+ "*:7081": {
+ "pass": "applications/empty"
+ }
+ },
+ "applications": {
+ "empty": {
+ "type": "python",
+ "processes": { "spare": 0 },
+ "path": self.current_dir + '/python/empty',
+ "working_directory": self.current_dir + '/python/empty',
+ "module": "wsgi"
+ }
+ }
+ })
+
+ self.assertEqual(self.get(port=7081)['status'], 200, 'routes absent')
+
+ def test_routes_pass_invalid(self):
+ self.assertIn('error', self.conf({ "pass": "routes/blah" },
+ 'listeners/*:7080'), 'routes invalid')
+
+ def test_route_empty(self):
+ self.assertIn('success', self.conf({
+ "listeners": {
+ "*:7080": {
+ "pass": "routes/main"
+ }
+ },
+ "routes": {"main": []},
+ "applications": {
+ "empty": {
+ "type": "python",
+ "processes": { "spare": 0 },
+ "path": self.current_dir + '/python/empty',
+ "working_directory": self.current_dir + '/python/empty',
+ "module": "wsgi"
+ },
+ "mirror": {
+ "type": "python",
+ "processes": { "spare": 0 },
+ "path": self.current_dir + '/python/mirror',
+ "working_directory": self.current_dir + '/python/mirror',
+ "module": "wsgi"
+ }
+ }
+ }), 'route empty configure')
+
+ self.assertEqual(self.get()['status'], 404, 'route empty')
+
+ def test_routes_route_empty(self):
+ self.assertIn('success', self.conf({}, 'listeners'),
+ 'routes empty listeners configure')
+
+ self.assertIn('success', self.conf({}, 'routes'),
+ 'routes empty configure')
+
+ def test_routes_route_match_absent(self):
+ self.assertIn('success', self.conf([{
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'route match absent configure')
+
+ self.assertEqual(self.get()['status'], 200, 'route match absent')
+
+ def test_routes_route_action_absent(self):
+ self.skip_alerts.append(r'failed to apply new conf')
+
+ self.assertIn('error', self.conf([{
+ "match": { "method": "GET" }
+ }], 'routes'), 'route pass absent configure')
+
+ def test_routes_route_pass_absent(self):
+ self.skip_alerts.append(r'failed to apply new conf')
+
+ self.assertIn('error', self.conf([{
+ "match": { "method": "GET" },
+ "action": {}
+ }], 'routes'), 'route pass absent configure')
+
+ def test_routes_rules_two(self):
+ self.assertIn('success', self.conf([{
+ "match": { "method": "GET" },
+ "action": { "pass": "applications/empty" }
+ },
+ {
+ "match": { "method": "POST" },
+ "action": { "pass": "applications/mirror" }
+ }], 'routes'), 'rules two configure')
+
+ self.assertEqual(self.get()['status'], 200, 'rules two match first')
+ self.assertEqual(self.post(headers={
+ 'Host': 'localhost',
+ 'Content-Type': 'text/html',
+ 'Connection': 'close'
+ }, body='X')['status'], 200, 'rules two match second')
+
+ def test_routes_two(self):
+ self.assertIn('success', self.conf({
+ "listeners": {
+ "*:7080": {
+ "pass": "routes/first"
+ }
+ },
+ "routes": {
+ "first": [{
+ "match": { "method": "GET" },
+ "action": { "pass": "routes/second" }
+ }],
+ "second": [{
+ "match": { "host": "localhost" },
+ "action": { "pass": "applications/empty" }
+ }],
+ },
+ "applications": {
+ "empty": {
+ "type": "python",
+ "processes": { "spare": 0 },
+ "path": self.current_dir + '/python/empty',
+ "working_directory": self.current_dir + '/python/empty',
+ "module": "wsgi"
+ }
+ }
+ }), 'routes two configure')
+
+ self.assertEqual(self.get()['status'], 200, 'routes two')
+
+ def test_routes_match_host_positive(self):
+ self.assertIn('success', self.conf([{
+ "match": { "host": "localhost" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'match host positive configure')
+
+ self.assertEqual(self.get()['status'], 200,
+ 'match host positive localhost')
+
+ self.assertEqual(self.get(headers={'Connection': 'close'})['status'],
+ 404, 'match host positive empty')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'localhost.',
+ 'Connection': 'close'
+ })['status'], 200, 'match host positive trailing dot')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'www.localhost',
+ 'Connection': 'close'
+ })['status'], 404, 'match host positive www.localhost')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'localhost1',
+ 'Connection': 'close'
+ })['status'], 404, 'match host positive localhost1')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'example.com',
+ 'Connection': 'close'
+ })['status'], 404, 'match host positive example.com')
+
+ def test_routes_match_host_ipv4(self):
+ self.assertIn('success', self.conf([{
+ "match": { "host": "127.0.0.1" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'match host ipv4 configure')
+
+ self.assertEqual(self.get(headers={
+ 'Host': '127.0.0.1',
+ 'Connection': 'close'
+ })['status'], 200, 'match host ipv4')
+
+ def test_routes_match_host_ipv6(self):
+ self.assertIn('success', self.conf([{
+ "match": { "host": "[::1]" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'match host ipv6 configure')
+
+ self.assertEqual(self.get(headers={
+ 'Host': '[::1]',
+ 'Connection': 'close'
+ })['status'], 200, 'match host ipv6')
+
+ self.assertEqual(self.get(headers={
+ 'Host': '[::1]:7080',
+ 'Connection': 'close'
+ })['status'], 200, 'match host ipv6 port')
+
+ def test_routes_match_host_positive_many(self):
+ self.assertIn('success', self.conf([{
+ "match": { "host": ["localhost", "example.com"] },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'match host positive many configure')
+
+ self.assertEqual(self.get()['status'], 200,
+ 'match host positive many localhost')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'example.com',
+ 'Connection': 'close'
+ })['status'], 200, 'match host positive many example.com')
+
+ def test_routes_match_host_positive_and_negative(self):
+ self.assertIn('success', self.conf([{
+ "match": { "host": ["*example.com", "!www.example.com"] },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'match host positive and negative configure')
+
+ self.assertEqual(self.get()['status'], 404,
+ 'match host positive and negative localhost')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'example.com',
+ 'Connection': 'close'
+ })['status'], 200, 'match host positive and negative example.com')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'www.example.com',
+ 'Connection': 'close'
+ })['status'], 404, 'match host positive and negative www.example.com')
+
+ self.assertEqual(self.get(headers={
+ 'Host': '!www.example.com',
+ 'Connection': 'close'
+ })['status'], 200, 'match host positive and negative !www.example.com')
+
+ def test_routes_match_host_positive_and_negative_wildcard(self):
+ self.assertIn('success', self.conf([{
+ "match": { "host": ["*example*", "!www.example*"] },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'match host positive and negative wildcard configure')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'example.com',
+ 'Connection': 'close'
+ })['status'], 200,
+ 'match host positive and negative wildcard example.com')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'www.example.com',
+ 'Connection': 'close'
+ })['status'], 404,
+ 'match host positive and negative wildcard www.example.com')
+
+ def test_routes_match_host_case_insensitive(self):
+ self.assertIn('success', self.conf([{
+ "match": { "host": "Example.com" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'host case insensitive configure')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'example.com',
+ 'Connection': 'close'
+ })['status'], 200, 'host case insensitive example.com')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'EXAMPLE.COM',
+ 'Connection': 'close'
+ })['status'], 200, 'host case insensitive EXAMPLE.COM')
+
+ def test_routes_match_host_port(self):
+ self.assertIn('success', self.conf([{
+ "match": { "host": "example.com" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'match host port configure')
+
+ self.assertEqual(self.get(headers={
+ 'Host': 'example.com:7080',
+ 'Connection': 'close'
+ })['status'], 200, 'match host port')
+
+ def test_routes_match_uri_positive(self):
+ self.assertIn('success', self.conf([{
+ "match": { "uri": "/" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'match uri positive configure')
+
+ self.assertEqual(self.get()['status'], 200, 'match uri positive')
+ self.assertEqual(self.get(url='/blah')['status'], 404,
+ 'match uri positive blah')
+ self.assertEqual(self.get(url='/#blah')['status'], 200,
+ 'match uri positive #blah')
+ self.assertEqual(self.get(url='/?var')['status'], 200,
+ 'match uri params')
+ self.assertEqual(self.get(url='//')['status'], 200,
+ 'match uri adjacent slashes')
+ self.assertEqual(self.get(url='/blah/../')['status'], 200,
+ 'match uri relative path')
+ self.assertEqual(self.get(url='/./')['status'], 200,
+ 'match uri relative path')
+
+ def test_routes_match_uri_case_sensitive(self):
+ self.assertIn('success', self.conf([{
+ "match": { "uri": "/BLAH" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'match uri case sensitive configure')
+
+ self.assertEqual(self.get(url='/blah')['status'], 404,
+ 'match uri case sensitive blah')
+ self.assertEqual(self.get(url='/BlaH')['status'], 404,
+ 'match uri case sensitive BlaH')
+ self.assertEqual(self.get(url='/BLAH')['status'], 200,
+ 'match uri case sensitive BLAH')
+
+ def test_routes_match_uri_normalize(self):
+ self.assertIn('success', self.conf([{
+ "match": { "uri": "/blah" },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'match uri normalize configure')
+
+ self.assertEqual(self.get(url='/%62%6c%61%68')['status'], 200,
+ 'match uri normalize')
+
+ def test_routes_match_rules(self):
+ self.assertIn('success', self.conf([{
+ "match": {
+ "method": "GET",
+ "host": "localhost",
+ "uri": "/"
+ },
+ "action": { "pass": "applications/empty" }
+ }], 'routes'), 'routes match rules configure')
+
+ self.assertEqual(self.get()['status'], 200, 'routes match rules')
+
+ def test_routes_loop(self):
+ self.assertIn('success', self.conf([{
+ "match": { "uri": "/" },
+ "action": { "pass": "routes" }
+ }], 'routes'), 'routes loop configure')
+
+ self.assertEqual(self.get()['status'], 500, 'routes loop')
+
+if __name__ == '__main__':
+ TestUnitRouting.main()
diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py
index 57ab88cd..262fc497 100644
--- a/test/test_ruby_application.py
+++ b/test/test_ruby_application.py
@@ -14,7 +14,8 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
resp = self.post(headers={
'Host': 'localhost',
'Content-Type': 'text/html',
- 'Custom-Header': 'blah'
+ 'Custom-Header': 'blah',
+ 'Connection': 'close'
}, body=body)
self.assertEqual(resp['status'], 200, 'status')
@@ -30,6 +31,7 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
'date header')
self.assertDictEqual(headers, {
+ 'Connection': 'close',
'Content-Length': str(len(body)),
'Content-Type': 'text/html',
'Request-Method': 'POST',
@@ -56,6 +58,25 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2',
'Query-String header')
+ def test_ruby_application_query_string_empty(self):
+ self.load('query_string')
+
+ resp = self.get(url='/?')
+
+ self.assertEqual(resp['status'], 200, 'query string empty status')
+ self.assertEqual(resp['headers']['Query-String'], '',
+ 'query string empty')
+
+ @unittest.expectedFailure
+ def test_ruby_application_query_string_absent(self):
+ self.load('query_string')
+
+ resp = self.get()
+
+ self.assertEqual(resp['status'], 200, 'query string absent status')
+ self.assertEqual(resp['headers']['Query-String'], '',
+ 'query string absent')
+
@unittest.expectedFailure
def test_ruby_application_server_port(self):
self.load('server_port')
@@ -189,7 +210,6 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
'errors write int')
def test_ruby_application_at_exit(self):
- self.skip_alerts.append(r'sendmsg.+failed')
self.load('at_exit')
self.get()
@@ -268,17 +288,17 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
self.load('mirror')
(resp, sock) = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, body='0123456789' * 500)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={
+ 'Host': 'localhost',
'Connection': 'close',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, sock=sock, body='0123456789')
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
diff --git a/test/test_settings.py b/test/test_settings.py
index b4ac33dc..13bfad49 100644
--- a/test/test_settings.py
+++ b/test/test_settings.py
@@ -14,7 +14,7 @@ class TestUnitSettings(unit.TestUnitApplicationPython):
self.conf({'http': { 'header_read_timeout': 2 }}, 'settings')
(resp, sock) = self.http(b"""GET / HTTP/1.1
-""", start=True, raw=True)
+""", start=True, read_timeout=1, raw=True)
time.sleep(3)
@@ -28,22 +28,20 @@ Connection: close
def test_settings_header_read_timeout_update(self):
self.load('empty')
- r = None
-
self.conf({'http': { 'header_read_timeout': 4 }}, 'settings')
(resp, sock) = self.http(b"""GET / HTTP/1.1
-""", start=True, raw=True, no_recv=True)
+""", start=True, read_timeout=1, raw=True, no_recv=True)
time.sleep(2)
(resp, sock) = self.http(b"""Host: localhost
-""", start=True, sock=sock, raw=True, no_recv=True)
+""", start=True, sock=sock, read_timeout=1, raw=True, no_recv=True)
time.sleep(2)
(resp, sock) = self.http(b"""X-Blah: blah
-""", start=True, sock=sock, raw=True)
+""", start=True, sock=sock, read_timeout=1, raw=True)
if len(resp) != 0:
sock.close()
@@ -68,7 +66,7 @@ Host: localhost
Content-Length: 10
Connection: close
-""", start=True, raw_resp=True, raw=True)
+""", start=True, raw_resp=True, read_timeout=1, raw=True)
time.sleep(3)
@@ -86,15 +84,17 @@ Host: localhost
Content-Length: 10
Connection: close
-""", start=True, raw=True)
+""", start=True, read_timeout=1, raw=True)
time.sleep(2)
- (resp, sock) = self.http(b"""012""", start=True, sock=sock, raw=True)
+ (resp, sock) = self.http(b"""012""", start=True, sock=sock,
+ read_timeout=1, raw=True)
time.sleep(2)
- (resp, sock) = self.http(b"""345""", start=True, sock=sock, raw=True)
+ (resp, sock) = self.http(b"""345""", start=True, sock=sock,
+ read_timeout=1, raw=True)
time.sleep(2)
@@ -120,6 +120,7 @@ Connection: close
Host: localhost
Content-Type: text/html
Content-Length: %d
+Connection: close
""" % data_len + ('X' * data_len)
@@ -142,15 +143,15 @@ Content-Length: %d
self.conf({'http': { 'idle_timeout': 2 }}, 'settings')
(resp, sock) = self.get(headers={
- 'Connection': 'keep-alive',
- 'Host': 'localhost'
- }, start=True)
+ 'Host': 'localhost',
+ 'Connection': 'keep-alive'
+ }, start=True, read_timeout=1)
time.sleep(3)
resp = self.get(headers={
- 'Connection': 'close',
- 'Host': 'localhost'
+ 'Host': 'localhost',
+ 'Connection': 'close'
}, sock=sock)
self.assertEqual(resp['status'], 408, 'status idle timeout')
diff --git a/test/test_tls.py b/test/test_tls.py
index fa5c9754..2131bf30 100644
--- a/test/test_tls.py
+++ b/test/test_tls.py
@@ -306,23 +306,25 @@ basicConstraints = critical,CA:TRUE""" % {
self.assertEqual(self.get_ssl()['status'], 200,
'certificate chain intermediate server')
+ @unittest.expectedFailure
def test_tls_reconfigure(self):
self.load('empty')
self.certificate()
- (resp, sock) = self.http(b"""GET / HTTP/1.1
-""", start=True, raw=True, no_recv=True)
-
- self.add_tls()
+ (resp, sock) = self.get(headers={
+ 'Host': 'localhost',
+ 'Connection': 'keep-alive'
+ }, start=True)
- resp = self.http(b"""Host: localhost
-Connection: close
+ self.assertEqual(resp['status'], 200, 'initial status')
-""", sock=sock, raw=True)
+ self.add_tls()
- self.assertEqual(resp['status'], 200, 'update status')
- self.assertEqual(self.get_ssl()['status'], 200, 'update tls status')
+ self.assertEqual(self.get(sock=sock)['status'], 200,
+ 'reconfigure status')
+ self.assertEqual(self.get_ssl()['status'], 200,
+ 'reconfigure tls status')
def test_tls_keepalive(self):
self.load('mirror')
@@ -332,17 +334,17 @@ Connection: close
self.add_tls(application='mirror')
(resp, sock) = self.post_ssl(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, body='0123456789')
self.assertEqual(resp['body'], '0123456789', 'keepalive 1')
resp = self.post_ssl(headers={
+ 'Host': 'localhost',
'Connection': 'close',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, sock=sock, body='0123456789')
self.assertEqual(resp['body'], '0123456789', 'keepalive 2')
@@ -356,8 +358,8 @@ Connection: close
self.add_tls()
(resp, sock) = self.get_ssl(headers={
- 'Connection': 'keep-alive',
- 'Host': 'localhost'
+ 'Host': 'localhost',
+ 'Connection': 'keep-alive'
}, start=True)
self.conf({
@@ -367,8 +369,8 @@ Connection: close
try:
resp = self.get_ssl(headers={
- 'Connection': 'close',
- 'Host': 'localhost'
+ 'Host': 'localhost',
+ 'Connection': 'close'
}, sock=sock)
except:
resp = None
@@ -395,9 +397,9 @@ Connection: close
self.add_tls(application='mirror')
(resp, sock) = self.post_ssl(headers={
+ 'Host': 'localhost',
'Connection': 'keep-alive',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, start=True, body='0123456789')
app_id = self.findall(r'(\d+)#\d+ "mirror" application started')[0]
@@ -408,9 +410,9 @@ Connection: close
'#)(\d+)#\d+ "mirror" application started'))
resp = self.post_ssl(headers={
+ 'Host': 'localhost',
'Connection': 'close',
- 'Content-Type': 'text/html',
- 'Host': 'localhost'
+ 'Content-Type': 'text/html'
}, sock=sock, body='0123456789')
self.assertEqual(resp['status'], 200, 'application respawn status')
diff --git a/test/unit.py b/test/unit.py
index e88ed684..6cca7f48 100644
--- a/test/unit.py
+++ b/test/unit.py
@@ -179,7 +179,8 @@ class TestUnit(unittest.TestCase):
self._started = True
- self.skip_alerts = [r'read signalfd\(4\) failed']
+ self.skip_alerts = [r'read signalfd\(4\) failed', r'sendmsg.+failed',
+ r'recvmsg.+failed']
self.skip_sanitizer = False
def _stop(self):
@@ -235,7 +236,7 @@ class TestUnit(unittest.TestCase):
if sanitizer_errors:
self._print_path_to_log()
- self.assertFalse(sanitizer_error, 'sanitizer error(s)')
+ self.assertFalse(sanitizer_errors, 'sanitizer error(s)')
if found:
print('skipped.')
@@ -285,7 +286,6 @@ class TestUnitHTTP(TestUnit):
port = 7080 if 'port' not in kwargs else kwargs['port']
url = '/' if 'url' not in kwargs else kwargs['url']
http = 'HTTP/1.0' if 'http_10' in kwargs else 'HTTP/1.1'
- blocking = False if 'blocking' not in kwargs else kwargs['blocking']
headers = ({
'Host': 'localhost',
@@ -309,6 +309,9 @@ class TestUnitHTTP(TestUnit):
if 'sock' not in kwargs:
sock = socket.socket(sock_types[sock_type], socket.SOCK_STREAM)
+ if sock_type == sock_types['ipv4'] or sock_type == sock_types['ipv6']:
+ sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+
if 'wrapper' in kwargs:
sock = kwargs['wrapper'](sock)
@@ -319,8 +322,6 @@ class TestUnitHTTP(TestUnit):
sock.close()
return None
- sock.setblocking(blocking)
-
else:
sock = kwargs['sock']
@@ -335,7 +336,12 @@ class TestUnitHTTP(TestUnit):
headers['Content-Length'] = len(body)
for header, value in headers.items():
- req += header + ': ' + str(value) + crlf
+ if isinstance(value, list):
+ for v in value:
+ req += header + ': ' + str(v) + crlf
+
+ else:
+ req += header + ': ' + str(value) + crlf
req = (req + crlf).encode() + body
@@ -350,8 +356,9 @@ class TestUnitHTTP(TestUnit):
resp = ''
if 'no_recv' not in kwargs:
- enc = 'utf-8' if 'encoding' not in kwargs else kwargs['encoding']
- resp = self.recvall(sock).decode(enc)
+ enc = 'utf-8' if 'encoding' not in kwargs else kwargs['encoding']
+ read_timeout = 5 if 'read_timeout' not in kwargs else kwargs['read_timeout']
+ resp = self.recvall(sock, read_timeout=read_timeout).decode(enc)
if TestUnit.detailed:
print('<<<', resp.encode('utf-8'), sep='\n')
@@ -377,9 +384,9 @@ class TestUnitHTTP(TestUnit):
def put(self, **kwargs):
return self.http('PUT', **kwargs)
- def recvall(self, sock, buff_size=4096):
+ def recvall(self, sock, read_timeout=5, buff_size=4096):
data = b''
- while select.select([sock], [], [], 1)[0]:
+ while select.select([sock], [], [], read_timeout)[0]:
try:
part = sock.recv(buff_size)
except:
@@ -428,7 +435,7 @@ class TestUnitControl(TestUnitHTTP):
# TODO http client
def conf(self, conf, path='/config'):
- if isinstance(conf, dict):
+ if isinstance(conf, dict) or isinstance(conf, list):
conf = json.dumps(conf)
if path[:1] != '/':
@@ -593,6 +600,72 @@ class TestUnitApplicationNode(TestUnitApplicationProto):
}
})
+class TestUnitApplicationJava(TestUnitApplicationProto):
+ def load(self, script, name='app'):
+
+ app_path = self.testdir + '/java'
+ web_inf_path = app_path + '/WEB-INF/'
+ classes_path = web_inf_path + 'classes/'
+
+ script_path = self.current_dir + '/java/' + script + '/'
+
+ if not os.path.isdir(app_path):
+ os.makedirs(app_path)
+
+ src = []
+
+ for f in os.listdir(script_path):
+ if f.endswith('.java'):
+ src.append(script_path + f)
+ continue
+
+ if f.startswith('.') or f == 'Makefile':
+ continue
+
+ if os.path.isdir(script_path + f):
+ if f == 'WEB-INF':
+ continue
+
+ shutil.copytree(script_path + f, app_path + '/' + f)
+ continue
+
+ if f == 'web.xml':
+ if not os.path.isdir(web_inf_path):
+ os.makedirs(web_inf_path)
+
+ shutil.copy2(script_path + f, web_inf_path)
+ else:
+ shutil.copy2(script_path + f, app_path)
+
+ if src:
+ if not os.path.isdir(classes_path):
+ os.makedirs(classes_path)
+
+ javac = ['javac', '-encoding', 'utf-8', '-d', classes_path,
+ '-classpath',
+ self.pardir + '/build/tomcat-servlet-api-9.0.13.jar']
+ javac.extend(src)
+
+ process = subprocess.Popen(javac)
+ process.communicate()
+
+ self.conf({
+ "listeners": {
+ "*:7080": {
+ "application": script
+ }
+ },
+ "applications": {
+ script: {
+ "unit_jars": self.pardir + '/build',
+ "type": "java",
+ "processes": { "spare": 0 },
+ "working_directory": script_path,
+ "webapp": app_path
+ }
+ }
+ })
+
class TestUnitApplicationPerl(TestUnitApplicationProto):
def load(self, script, name='psgi.pl'):
self.conf({
@@ -637,15 +710,27 @@ class TestUnitApplicationTLS(TestUnitApplicationProto):
return self.conf(k.read() + c.read(), '/certificates/' + crt)
def get_ssl(self, **kwargs):
- return self.get(blocking=True, wrapper=self.context.wrap_socket,
+ return self.get(wrapper=self.context.wrap_socket,
**kwargs)
def post_ssl(self, **kwargs):
- return self.post(blocking=True, wrapper=self.context.wrap_socket,
+ return self.post(wrapper=self.context.wrap_socket,
**kwargs)
def get_server_certificate(self, addr=('127.0.0.1', 7080)):
- return ssl.get_server_certificate(addr)
+
+ ssl_list = dir(ssl)
+
+ if 'PROTOCOL_TLS' in ssl_list:
+ ssl_version = ssl.PROTOCOL_TLS
+
+ elif 'PROTOCOL_TLSv1_2' in ssl_list:
+ ssl_version = ssl.PROTOCOL_TLSv1_2
+
+ else:
+ ssl_version = ssl.PROTOCOL_TLSv1_1
+
+ return ssl.get_server_certificate(addr, ssl_version=ssl_version)
def load(self, script, name=None):
if name is None: