diff options
Diffstat (limited to 'test')
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: |