+ * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + *
+ * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * - Neither the name tuckey.org nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ +package org.tuckey.web.filters.urlrewrite.test; + +import jakarta.servlet.AsyncContext; +import jakarta.servlet.DispatcherType; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletConnection; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import jakarta.servlet.http.HttpUpgradeHandler; +import jakarta.servlet.http.Part; +import junit.framework.TestCase; +import org.tuckey.web.filters.urlrewrite.Conf; +import org.tuckey.web.filters.urlrewrite.NormalRewrittenUrl; +import org.tuckey.web.filters.urlrewrite.Rule; +import org.tuckey.web.filters.urlrewrite.UrlRewriter; +import org.tuckey.web.filters.urlrewrite.utils.Log; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * The idea for UrlRewriteTestCase is that users can extend it to create their own + * simple unit tests instead of having to manually setup a mock request and the filter. + *
+ * note, Ideally this would be in a separate urlrewrite-test.jar but that + * seems a little over the top for one class. + */ +public class UrlRewriteTestCase extends TestCase { + + Conf conf; + UrlRewriter urlRewriter; + + public void loadConf(URL confFileUrl) { + Log.setLevel("SYSOUT:DEBUG"); + conf = new Conf(confFileUrl); + assertTrue("Conf should load without errors", conf.isOk()); + urlRewriter = new UrlRewriter(conf); + } + + public Rule getRule(String ruleName) { + List rules = urlRewriter.getConf().getRules(); + Rule rule = null; + if (rules != null) { + for (int i = 0; i < rules.size(); i++) { + Rule loopRule = (Rule) rules.get(i); + if (ruleName.equalsIgnoreCase(loopRule.getName())) { + rule = loopRule; + } + } + } + if (rule == null) { + assertTrue("Rule by the name " + ruleName + " does not exist", false); + } + return rule; + } + + /** + * Checks to see if the specified rule name matches the url specified. + * + * @param ruleName - the name of the rule + * @param requestUrl - the url to check + */ + public void assertRuleMatches(String ruleName, String requestUrl) { + + Rule rule = getRule(ruleName); + + MockResponse response = new MockResponse(); + MockRequest request = new MockRequest(requestUrl); + NormalRewrittenUrl rewrittenUrl = null; + try { + rewrittenUrl = (NormalRewrittenUrl) rule.matches(request.getRequestURI(), request, response); + + } catch (IOException e) { + assertNull("IOException during rule matching " + e.toString(), e); + + } catch (ServletException e) { + assertNull("ServletException during rule matching " + e.toString(), e); + + } catch (InvocationTargetException e) { + assertNull("InvocationTargetException during rule matching " + e.toString(), e); + + } + assertNotNull("Rule " + ruleName + " does not match", rewrittenUrl); + } + + public void assertRuleDoesNotMatches(String ruleName, String requestUrl) { + Rule rule = getRule(ruleName); + + MockResponse response = new MockResponse(); + MockRequest request = new MockRequest(requestUrl); + NormalRewrittenUrl rewrittenUrl = null; + try { + rewrittenUrl = (NormalRewrittenUrl) rule.matches(request.getRequestURI(), request, response); + + } catch (IOException e) { + assertNull("IOException during rule matching " + e.toString(), e); + + } catch (ServletException e) { + assertNull("ServletException during rule matching " + e.toString(), e); + + } catch (InvocationTargetException e) { + assertNull("InvocationTargetException during rule matching " + e.toString(), e); + + } + assertNull("Rule " + ruleName + " match", rewrittenUrl); + } + + + /** + * An empty method so that Junit doesn't complain when running tests. + */ + public void testUrlRerwriteTestCase() { + // do nothing + } +} + + +class MockRequest implements HttpServletRequest { + + private String requestURI; + private int serverPort = 80; + private String queryString; + private String method = "GET"; + private Hashtable headers = new Hashtable(); + private Hashtable attrs = new Hashtable(); + private Hashtable parameters = new Hashtable(); + private String authType; + private int contentLength; + private String contentType; + private String contextPath = ""; + private Cookie[] cookies; + private int cookieCounter; + private String pathInfo; + private String pathTranslated; + private String protocol; + private String remoteAddr; + private String remoteHost; + private String remoteUser; + private String requestedSessionId; + private String requestUrl; + private String serverName; + private String servletPath; + private String scheme; + private int localPort = 0; + + public MockRequest() { + } + + public MockRequest(String requestURI) { + this.requestURI = contextPath + requestURI; + this.requestUrl = requestURI; + this.servletPath = requestURI; + } + + public void setRequestURI(String requestURI) { + this.requestURI = requestURI; + } + + public String getAuthType() { + return authType; + } + + public void setAuthType(String s) { + authType = s; + } + + + public Cookie[] getCookies() { + return cookies; + } + + public long getDateHeader(String s) { + return 0; + } + + public String getHeader(String s) { + if (s == null) { + return null; + } + return (String) headers.get(s); + } + + public Enumeration getHeaders(String s) { + return headers.elements(); + } + + public Enumeration getHeaderNames() { + return headers.keys(); + } + + public int getIntHeader(String s) { + return 0; + } + + public String getMethod() { + return method; + } + + public String getPathInfo() { + return pathInfo; + } + + public String getPathTranslated() { + return pathTranslated; + } + + public String getContextPath() { + return contextPath; + } + + public String getQueryString() { + return queryString; + } + + public String getRemoteUser() { + return remoteUser; + } + + private ArrayList roles = new ArrayList(); + + public boolean isUserInRole(String s) { + return roles.contains(s); + } + + public void addRole(String s) { + roles.add(s); + } + + public void removeRole(String s) { + roles.remove(s); + } + + + public Principal getUserPrincipal() { + return null; + } + + public String getRequestedSessionId() { + return requestedSessionId; + } + + public String getRequestURI() { + return requestURI; + } + + public StringBuffer getRequestURL() { + if (requestUrl == null) return null; + return new StringBuffer(requestUrl); + } + + public String getServletPath() { + return servletPath; + } + + public HttpSession getSession(boolean b) { + return null; + } + + public void setSessionNew(boolean b) { + } + + public HttpSession getSession() { + return null; + } + + @Override + public String changeSessionId() { + return null; + } + + public boolean isRequestedSessionIdValid() { + return false; + } + + public boolean isRequestedSessionIdFromCookie() { + return false; + } + + public boolean isRequestedSessionIdFromURL() { + return false; + } + + @Override + public boolean authenticate(HttpServletResponse httpServletResponse) throws IOException, ServletException { + return false; + } + + @Override + public void login(String s, String s1) throws ServletException { + + } + + @Override + public void logout() throws ServletException { + + } + + @Override + public Collection+ * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + *
+ * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * - Neither the name tuckey.org nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+package org.tuckey.web.testhelper;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterRegistration;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.Servlet;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRegistration;
+import jakarta.servlet.SessionCookieConfig;
+import jakarta.servlet.SessionTrackingMode;
+import jakarta.servlet.descriptor.JspConfigDescriptor;
+import org.tuckey.web.filters.urlrewrite.UrlRewriteFilterTest;
+import org.tuckey.web.filters.urlrewrite.utils.Log;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Paul Tuckey
+ * @version $Revision: 1 $ $Date: 2006-08-01 21:40:28 +1200 (Tue, 01 Aug 2006) $
+ */
+public class MockServletContext implements ServletContext {
+
+ private static Log log = Log.getLog(MockServletContext.class);
+ private final Hashtable attributes = new Hashtable();
+
+ @Override
+ public String getContextPath() {
+ return null;
+ }
+
+ public ServletContext getContext(String s) {
+ return new MockServletContext();
+ }
+
+ public Object getAttribute(String name) {
+ return this.attributes.get(name);
+ }
+
+ public int getMajorVersion() {
+ return 0;
+ }
+
+ public int getMinorVersion() {
+ return 0;
+ }
+
+ @Override
+ public int getEffectiveMajorVersion() {
+ return 0;
+ }
+
+ @Override
+ public int getEffectiveMinorVersion() {
+ return 0;
+ }
+
+ public String getMimeType(String s) {
+ return null;
+ }
+
+ public Set getResourcePaths(String s) {
+ return null;
+ }
+
+ public URL getResource(String s) throws MalformedURLException {
+ return null;
+ }
+
+ public InputStream getResourceAsStream(String s) {
+ return null;
+ }
+
+ public RequestDispatcher getRequestDispatcher(String s) {
+ return null;
+ }
+
+ public RequestDispatcher getNamedDispatcher(String s) {
+ return null;
+ }
+
+ public Servlet getServlet(String s) throws ServletException {
+ return null;
+ }
+
+ public Enumeration getServlets() {
+ return null;
+ }
+
+ public Enumeration getServletNames() {
+ return null;
+ }
+
+ public void log(String s) {
+
+ }
+
+ public void log(Exception e, String s) {
+
+ }
+
+ public void log(String s, Throwable throwable) {
+
+ }
+
+ public String getRealPath(String s) {
+ URL url = UrlRewriteFilterTest.class.getResource("conf-test1.xml");
+ if (url == null) {
+ log.error("could not get base path for comparison");
+ return null;
+ } else {
+ String basePath = url.getFile();
+ log.debug("TEST ONLY using base path of " + basePath);
+ if (basePath.endsWith("conf-test1.xml"))
+ basePath = basePath.substring(0, basePath.length() - "conf-test1.xml".length());
+ if (basePath.endsWith("/")) basePath = basePath.substring(0, basePath.length() - 1);
+ return basePath + (s == null ? "" : s);
+ }
+ }
+
+ public String getServerInfo() {
+ return null;
+ }
+
+ public String getInitParameter(String s) {
+ return null;
+ }
+
+ public Enumeration getInitParameterNames() {
+ return null;
+ }
+
+ @Override
+ public boolean setInitParameter(String s, String s1) {
+ return false;
+ }
+
+ public Enumeration getAttributeNames() {
+ return null;
+ }
+
+ public void setAttribute(String name, Object value) {
+ if (value != null) {
+ this.attributes.put(name, value);
+ } else {
+ this.attributes.remove(name);
+ }
+ }
+
+ public void removeAttribute(String s) {
+
+ }
+
+ public String getServletContextName() {
+ return null;
+ }
+
+ @Override
+ public ServletRegistration.Dynamic addServlet(String s, String s1) {
+ return null;
+ }
+
+ @Override
+ public ServletRegistration.Dynamic addServlet(String s, Servlet servlet) {
+ return null;
+ }
+
+ @Override
+ public ServletRegistration.Dynamic addServlet(String s, Class extends Servlet> aClass) {
+ return null;
+ }
+
+ @Override
+ public ServletRegistration.Dynamic addJspFile(String s, String s1) {
+ return null;
+ }
+
+ @Override
+ public
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * - Neither the name tuckey.org nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+package org.tuckey.web.testhelper;
+
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.http.HttpSession;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * @author Paul Tuckey
+ * @version $Revision: 1 $ $Date: 2006-08-01 21:40:28 +1200 (Tue, 01 Aug 2006) $
+ */
+public class MockSession implements HttpSession {
+
+ MockServletContext servletContext = new MockServletContext();
+ Hashtable attrs = new Hashtable();
+ private boolean sessionNew;
+
+ public long getCreationTime() {
+ return 0;
+ }
+
+ public String getId() {
+ return null;
+ }
+
+ public long getLastAccessedTime() {
+ return 0;
+ }
+
+ public void setServletContext(ServletContext sc) {
+ servletContext = (MockServletContext) sc;
+ }
+
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+
+ public void setMaxInactiveInterval(int i) {
+
+ }
+
+ public int getMaxInactiveInterval() {
+ return 0;
+ }
+
+ public Object getAttribute(String s) {
+ return attrs.get(s);
+ }
+
+ /**
+ * @deprecated
+ */
+ public Object getValue(String s) {
+ return null;
+ }
+
+ public Enumeration getAttributeNames() {
+ return null;
+ }
+
+ /**
+ * @deprecated
+ */
+ public String[] getValueNames() {
+ return new String[0];
+ }
+
+ public void setAttribute(String s, Object o) {
+ attrs.put(s, o);
+ }
+
+ /**
+ * @deprecated
+ */
+ public void putValue(String s, Object o) {
+
+ }
+
+ public void removeAttribute(String s) {
+ attrs.remove(s);
+ }
+
+ /**
+ * @deprecated
+ */
+ public void removeValue(String s) {
+
+ }
+
+ public void invalidate() {
+
+ }
+
+ public boolean isNew() {
+ return sessionNew;
+ }
+
+ public void setNew(boolean sessionNew) {
+ this.sessionNew = sessionNew;
+ }
+}