diff options
Diffstat (limited to 'bundles/org.eclipse.equinox.http.servlet.tests')
15 files changed, 925 insertions, 9 deletions
diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF index 7dec26cdc..cf06baa9e 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.equinox.http.servlet.tests Bundle-SymbolicName: org.eclipse.equinox.http.servlet.tests -Bundle-Version: 1.5.300.qualifier +Bundle-Version: 1.6.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Eclipse-BundleShape: dir Require-Bundle: org.junit;bundle-version="4.0" diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml b/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml index a9b7e11a7..1be02a941 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml +++ b/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml @@ -19,7 +19,7 @@ </parent> <groupId>org.eclipse.equinox</groupId> <artifactId>org.eclipse.equinox.http.servlet.tests</artifactId> - <version>1.5.300-SNAPSHOT</version> + <version>1.6.0-SNAPSHOT</version> <packaging>eclipse-test-plugin</packaging> <build> diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/AllTests.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/AllTests.java index d2f0dfe60..129fca466 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/AllTests.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/AllTests.java @@ -13,8 +13,13 @@ *******************************************************************************/ package org.eclipse.equinox.http.servlet.testbase; +import org.eclipse.equinox.http.servlet.tests.AuthenticationTest; import org.eclipse.equinox.http.servlet.tests.DispatchingTest; +import org.eclipse.equinox.http.servlet.tests.PreprocessorTestCase; import org.eclipse.equinox.http.servlet.tests.ServletTest; +import org.eclipse.equinox.http.servlet.tests.TestHttpServiceAndErrorPage; +import org.eclipse.equinox.http.servlet.tests.TestHttpServiceAndNamedServlet; +import org.eclipse.equinox.http.servlet.tests.TestUpload; import org.eclipse.equinox.http.servlet.tests.Test_140_11_3; import org.eclipse.equinox.http.servlet.tests.Test_140_2_17to22; import org.eclipse.equinox.http.servlet.tests.Test_140_2_26to27; @@ -36,6 +41,7 @@ import org.eclipse.equinox.http.servlet.tests.Test_table_140_1_HTTP_WHITEBOARD_C import org.eclipse.equinox.http.servlet.tests.Test_table_140_1_HTTP_WHITEBOARD_CONTEXT_NAME_tieGoesToOldest; import org.eclipse.equinox.http.servlet.tests.Test_table_140_1_HTTP_WHITEBOARD_CONTEXT_PATH_type; import org.eclipse.equinox.http.servlet.tests.Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED; +import org.eclipse.equinox.http.servlet.tests.Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate; import org.eclipse.equinox.http.servlet.tests.Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ERROR_PAGE_4xx; import org.eclipse.equinox.http.servlet.tests.Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ERROR_PAGE_exception; import org.eclipse.equinox.http.servlet.tests.Test_table_140_5_HTTP_WHITEBOARD_FILTER_DISPATCHER_error; @@ -49,7 +55,9 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses({ + AuthenticationTest.class, DispatchingTest.class, + PreprocessorTestCase.class, ServletTest.class, Test_140_11_3.class, Test_140_2_17to22.class, @@ -72,13 +80,17 @@ import org.junit.runners.Suite.SuiteClasses; Test_table_140_1_HTTP_WHITEBOARD_CONTEXT_NAME_tieGoesToOldest.class, Test_table_140_1_HTTP_WHITEBOARD_CONTEXT_PATH_type.class, Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED.class, + Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate.class, Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ERROR_PAGE_4xx.class, Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ERROR_PAGE_exception.class, Test_table_140_5_HTTP_WHITEBOARD_FILTER_DISPATCHER_error.class, Test_table_140_5_HTTP_WHITEBOARD_FILTER_DISPATCHER_request.class, Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN.class, Test_table_140_5_HTTP_WHITEBOARD_FILTER_REGEX.class, - Test_table_140_6_HTTP_WHITEBOARD_RESOURCE_validation.class + Test_table_140_6_HTTP_WHITEBOARD_RESOURCE_validation.class, + TestHttpServiceAndErrorPage.class, + TestHttpServiceAndNamedServlet.class, + TestUpload.class, }) public class AllTests { // see @SuiteClasses diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java index 1a8022cb1..e4f2617f8 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java @@ -15,6 +15,7 @@ package org.eclipse.equinox.http.servlet.testbase; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import java.io.IOException; import java.io.OutputStream; @@ -29,6 +30,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -57,6 +59,7 @@ import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.http.HttpService; +import org.osgi.service.http.NamespaceException; import org.osgi.service.http.context.ServletContextHelper; import org.osgi.service.http.runtime.HttpServiceRuntime; import org.osgi.service.http.runtime.HttpServiceRuntimeConstants; @@ -73,6 +76,7 @@ import org.osgi.service.http.runtime.dto.ServletContextDTO; import org.osgi.service.http.runtime.dto.ServletDTO; import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; public class BaseTest { @@ -92,7 +96,34 @@ public class BaseTest { advisor = new BundleAdvisor(bundleContext); stopJetty(); startBundles(); - runtimeTracker = new ServiceTracker<>(bundleContext, HttpServiceRuntime.class, null); + runtimeTracker = new ServiceTracker<>(bundleContext, HttpServiceRuntime.class, new ServiceTrackerCustomizer<HttpServiceRuntime,ServiceReference<HttpServiceRuntime>>() { + + @Override + public ServiceReference<HttpServiceRuntime> addingService( + ServiceReference<HttpServiceRuntime> reference) { + final Object obj = reference + .getProperty(Constants.SERVICE_CHANGECOUNT); + if (obj != null) { + httpRuntimeChangeCount.set(Long.valueOf(obj.toString())); + } + return reference; + } + + @Override + public void modifiedService( + ServiceReference<HttpServiceRuntime> reference, + ServiceReference<HttpServiceRuntime> service) { + addingService(reference); + } + + @Override + public void removedService( + ServiceReference<HttpServiceRuntime> reference, + ServiceReference<HttpServiceRuntime> service) { + httpRuntimeChangeCount.set(-1); + } + + }); runtimeTracker.open(); runtimeTracker.waitForService(100); startJetty(); @@ -454,6 +485,99 @@ public class BaseTest { return getHttpServiceRuntime().getRuntimeDTO().failedResourceDTOs; } + protected long waitForRegistration(final long previousCount) { + return waitForRegistration(previousCount, 100); + } + + protected long waitForRegistration(final long previousCount, + int maxAttempts) { + while (this.httpRuntimeChangeCount.longValue() == previousCount) { + if (maxAttempts <= 0) { + throw new IllegalStateException("Max attempts exceeded"); + } + try { + Thread.sleep(20L); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + maxAttempts--; + } + return this.httpRuntimeChangeCount.longValue(); + } + + protected long getHttpRuntimeChangeCount() { + return httpRuntimeChangeCount.longValue(); + } + + protected void registerDummyServletInHttpService() + throws ServletException, NamespaceException { + final String path = "/tesths"; + final HttpService service = this.getHttpService(); + service.registerServlet(path, new HttpServlet() { + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, + HttpServletResponse resp) throws IOException { + resp.getWriter().print("helloworld"); + resp.flushBuffer(); + } + }, null, null); + } + + protected void unregisterDummyServletFromHttpService() { + this.getHttpService().unregister("/tesths"); + } + + protected ServletContextDTO getServletContextDTOForDummyServlet() { + for (final ServletContextDTO dto : this.getHttpServiceRuntime() + .getRuntimeDTO().servletContextDTOs) { + for (final ServletDTO sd : dto.servletDTOs) { + if (sd.patterns.length > 0 + && "/tesths".equals(sd.patterns[0])) { + return dto; + } + } + } + fail("Servlet context for http service not found"); + return null; + } + + protected FailedErrorPageDTO getFailedErrorPageDTOByException( + String exception) { + for (FailedErrorPageDTO failedErrorPageDTO : getFailedErrorPageDTOs()) { + for (String ex : failedErrorPageDTO.exceptions) { + if (exception.equals(ex)) { + return failedErrorPageDTO; + } + } + } + + return null; + } + + protected ErrorPageDTO getErrorPageDTOByException(String context, + String exception) { + ServletContextDTO servletContextDTO = getServletContextDTOByName( + context); + + if (servletContextDTO == null) { + return null; + } + + for (ErrorPageDTO errorPageDTO : servletContextDTO.errorPageDTOs) { + for (String ex : errorPageDTO.exceptions) { + if (exception.equals(ex)) { + return errorPageDTO; + } + } + } + + return null; + } + + final AtomicLong httpRuntimeChangeCount = new AtomicLong(-1); + protected static final String PROTOTYPE = "prototype/"; protected static final String CONFIGURE = "configure"; protected static final String UNREGISTER = "unregister"; @@ -480,7 +604,7 @@ public class BaseTest { protected BundleAdvisor advisor; protected ServletRequestAdvisor requestAdvisor; protected final Collection<ServiceRegistration<? extends Object>> registrations = new ArrayList<ServiceRegistration<? extends Object>>(); - protected ServiceTracker<HttpServiceRuntime, HttpServiceRuntime> runtimeTracker; + protected ServiceTracker<HttpServiceRuntime, ServiceReference<HttpServiceRuntime>> runtimeTracker; protected static class TestFilter implements Filter { AtomicInteger called = new AtomicInteger(0); diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/AuthenticationTest.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/AuthenticationTest.java new file mode 100644 index 000000000..2c1dd6261 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/AuthenticationTest.java @@ -0,0 +1,183 @@ +/******************************************************************************* + * Copyright (c) Jan. 26, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; + +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.junit.Test; +import org.osgi.framework.BundleContext; +import org.osgi.service.http.context.ServletContextHelper; + +public class AuthenticationTest extends BaseTest { + + @Test + public void test_forwardSecurity() throws Exception { + final List<String> callStack = new ArrayList<>(); + setup(callStack); + + // request without auth -> no servlet invoked + requestAdvisor.request("context1/servlet?forward=true"); + assertTrue(callStack.isEmpty()); + + // request with auth and forward -> servlet invoked + requestAdvisor.request("context1/servlet?forward=true&auth=true"); + assertEquals(6, callStack.size()); + assertEquals(Arrays.asList("handle1", "servlet/context1", "handle1", "servlet/context1", "finish1", "finish1"), callStack); + callStack.clear(); + } + + @Test + public void test_handleFinishSecurity() throws Exception { + final List<String> callStack = new ArrayList<>(); + setup(callStack); + + // request without auth -> no servlet invoked + requestAdvisor.request("context1/servlet"); + assertTrue(callStack.isEmpty()); + + // request with auth -> servlet invoked + requestAdvisor.request("context1/servlet?auth=true"); + assertEquals(3, callStack.size()); + assertEquals(Arrays.asList("handle1", "servlet/context1", "finish1"), callStack); + callStack.clear(); + + // request to context2, no auth required + requestAdvisor.request("context2/servlet"); + assertEquals(3, callStack.size()); + assertEquals(Arrays.asList("handle2", "servlet/context2", "finish2"), callStack); + } + + private static final String AUTH_PAR = "auth"; + + private static final String REC_PAR = "rec"; + + private void setup(final List<String> callStack) throws Exception { + final BundleContext context = getBundleContext(); + + // setup context 1 + final Dictionary<String,Object> ctx1Props = new Hashtable<String,Object>(); + ctx1Props.put(HTTP_WHITEBOARD_CONTEXT_NAME, "context1"); + ctx1Props.put(HTTP_WHITEBOARD_CONTEXT_PATH, "/context1"); + registrations.add(context.registerService( + ServletContextHelper.class, + new ServletContextHelper() { + + @Override + public boolean handleSecurity(final HttpServletRequest request, final HttpServletResponse response) + throws IOException { + + if (request.getParameter(AUTH_PAR) != null) { + callStack.add("handle1"); + return true; + } + return false; + } + + @Override + public void finishSecurity(final HttpServletRequest request, final HttpServletResponse response) { + callStack.add("finish1"); + } + + }, + ctx1Props) + ); + + // setup context 2 + final Dictionary<String,Object> ctx2Props = new Hashtable<String,Object>(); + ctx2Props.put(HTTP_WHITEBOARD_CONTEXT_NAME, "context2"); + ctx2Props.put(HTTP_WHITEBOARD_CONTEXT_PATH, "/context2"); + registrations.add(context.registerService( + ServletContextHelper.class, + new ServletContextHelper() { + + @Override + public boolean handleSecurity(final HttpServletRequest request, final HttpServletResponse response) + throws IOException { + + callStack.add("handle2"); + return true; + } + + @Override + public void finishSecurity(final HttpServletRequest request, final HttpServletResponse response) { + callStack.add("finish2"); + } + + }, + ctx2Props) + ); + + // servlet for both contexts + @SuppressWarnings("serial") + class AServlet extends HttpServlet { + + @Override + protected void service(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + + callStack.add("servlet" + request.getContextPath()); + + if (request.getContextPath().equals("/context1") + && request.getAttribute(REC_PAR) == null) { + if (request.getParameter("forward") != null) { + request.setAttribute(REC_PAR, "true"); + request.getRequestDispatcher("/servlet") + .forward(request, response); + return; + } else if (request.getParameter("include") != null) { + request.setAttribute(REC_PAR, "true"); + request.getRequestDispatcher("/servlet") + .include(request, response); + } else if (request.getParameter("throw") != null) { + callStack.add("throw"); + throw new ServletException("throw"); + } + } + response.setStatus(200); + } + + }; + + final Dictionary<String,Object> servletProps = new Hashtable<String,Object>(); + + servletProps.put(HTTP_WHITEBOARD_SERVLET_PATTERN, new String[] {"/servlet"}); + servletProps.put(HTTP_WHITEBOARD_CONTEXT_SELECT, "(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=context1)"); + registrations.add(context.registerService(Servlet.class, new AServlet(), servletProps)); + + servletProps.put(HTTP_WHITEBOARD_CONTEXT_SELECT, "(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=context2)"); + registrations.add(context.registerService(Servlet.class, new AServlet(), servletProps)); + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/PreprocessorTestCase.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/PreprocessorTestCase.java new file mode 100644 index 000000000..22a3683a5 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/PreprocessorTestCase.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright (c) Jan. 26, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; + +import javax.servlet.FilterChain; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.eclipse.equinox.http.servlet.tests.util.MockPreprocessor; +import org.eclipse.equinox.http.servlet.tests.util.MockServlet; +import org.junit.Test; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.http.runtime.dto.PreprocessorDTO; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; +import org.osgi.service.http.whiteboard.Preprocessor; + +public class PreprocessorTestCase extends BaseTest { + + @Test + public void testPreprocessorInitParameters() throws Exception { + Dictionary<String,Object> properties = new Hashtable<>(); + properties + .put(HttpWhiteboardConstants.HTTP_WHITEBOARD_PREPROCESSOR_INIT_PARAM_PREFIX + + "param1", "value1"); + properties + .put(HttpWhiteboardConstants.HTTP_WHITEBOARD_PREPROCESSOR_INIT_PARAM_PREFIX + + "param2", "value2"); + properties + .put(HttpWhiteboardConstants.HTTP_WHITEBOARD_PREPROCESSOR_INIT_PARAM_PREFIX + + "param3", 345l); + + long before = this.getHttpRuntimeChangeCount(); + final ServiceRegistration<Preprocessor> reg = getBundleContext() + .registerService(Preprocessor.class, new MockPreprocessor(), + properties); + registrations.add(reg); + this.waitForRegistration(before); + + final PreprocessorDTO[] dtos = this.getHttpServiceRuntime() + .getRuntimeDTO().preprocessorDTOs; + assertEquals(1, dtos.length); + + assertTrue(dtos[0].initParams.containsKey("param1")); + assertTrue(dtos[0].initParams.containsKey("param2")); + assertFalse(dtos[0].initParams.containsKey("param3")); + assertEquals(getServiceId(reg), dtos[0].serviceId); + } + + @Test + public void testPreprocessorRanking() throws Exception { + // register preprocessor with ranking -5 + Dictionary<String,Object> properties = new Hashtable<>(); + properties.put(Constants.SERVICE_RANKING, -5); + + long before = this.getHttpRuntimeChangeCount(); + registrations + .add(getBundleContext().registerService(Preprocessor.class.getName(), + new MockPreprocessor().around("d"), properties)); + before = this.waitForRegistration(before); + + // register preprocessor with ranking 8 + properties = new Hashtable<>(); + properties.put(Constants.SERVICE_RANKING, 8); + + registrations + .add(getBundleContext().registerService(Preprocessor.class.getName(), + new MockPreprocessor().around("a"), properties)); + before = this.waitForRegistration(before); + + // register preprocessor with invalid ranking + properties = new Hashtable<>(); + properties.put(Constants.SERVICE_RANKING, 3L); // this is invalid -> + // ranking = 0 + + registrations + .add(getBundleContext().registerService(Preprocessor.class.getName(), + new MockPreprocessor().around("b"), properties)); + before = this.waitForRegistration(before); + + // register preprocessor with no ranking + properties = new Hashtable<>(); + + registrations + .add(getBundleContext().registerService(Preprocessor.class.getName(), + new MockPreprocessor().around("c"), properties)); + before = this.waitForRegistration(before); + + // check that we have four preprocessors + final PreprocessorDTO[] dtos = this.getHttpServiceRuntime() + .getRuntimeDTO().preprocessorDTOs; + assertEquals(4, dtos.length); + + // register endpoint + properties = new Hashtable<>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, + "/available"); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet().content("hello"), properties)); + + assertEquals("abcdhellodcba", requestAdvisor.request("available")); + } + + /** + * Test a request with a servlet registered at that url and check if the + * preprocessor is invoked. Do the same with a non existing url. + */ + @Test + public void testPreprocessorInvocation() throws Exception { + // register preprocessor + final List<String> filterActions = new ArrayList<>(); + long before = this.getHttpRuntimeChangeCount(); + registrations.add(getBundleContext().registerService( + Preprocessor.class.getName(), new MockPreprocessor() { + + @Override + public void doFilter(ServletRequest request, + ServletResponse response, FilterChain chain) + throws IOException, ServletException { + filterActions.add("a"); + super.doFilter(request, new HttpServletResponseWrapper( + (HttpServletResponse) response) { + + private boolean hasStatus = false; + + private void addStatus(final int sc) { + if (!hasStatus) { + hasStatus = true; + filterActions.add(String.valueOf(sc)); + } + } + + @Override + public void setStatus(int sc) { + addStatus(sc); + super.setStatus(sc); + } + + @Override + public void sendError(int sc, String msg) + throws IOException { + addStatus(sc); + super.sendError(sc, msg); + } + + @Override + public void sendError(int sc) throws IOException { + addStatus(sc); + super.sendError(sc); + } + + }, chain); + filterActions.add("b"); + } + + }, null)); + before = this.waitForRegistration(before); + + // register endpoint + Dictionary<String,Object> properties = new Hashtable<>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, + "/available"); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet().content("hello"), properties)); + + assertEquals("hello", requestAdvisor.request("available")); + assertEquals(2, filterActions.size()); + assertEquals("a", filterActions.get(0)); + assertEquals("b", filterActions.get(1)); + + // request a non existing pattern - this will somehow set the status + // code to 404 + filterActions.clear(); + requestAdvisor.request("foo", null); + assertEquals(3, filterActions.size()); + assertEquals("a", filterActions.get(0)); + assertEquals("404", filterActions.get(1)); + assertEquals("b", filterActions.get(2)); + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java index 2a835c755..299c6febb 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java @@ -2666,7 +2666,6 @@ public class ServletTest extends BaseTest { List<FileItem> items = null; try { - @SuppressWarnings("unchecked") List<FileItem> parseRequest = upload.parseRequest(req); items = parseRequest; } catch (FileUploadException e) { diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndErrorPage.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndErrorPage.java new file mode 100644 index 000000000..1a550fa1b --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndErrorPage.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) Jan. 26, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.Dictionary; +import java.util.Hashtable; + +import javax.servlet.Servlet; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.eclipse.equinox.http.servlet.tests.util.MockServlet; +import org.junit.Test; +import org.osgi.service.http.runtime.dto.ServletContextDTO; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; + +public class TestHttpServiceAndErrorPage extends BaseTest { + + /** + * Registration of error page with http service (allowed) and error page and + * pattern with http service (not allowed) + */ + @Test + public void testHttpServiceAndErrorPage() throws Exception { + registerDummyServletInHttpService(); + try { + final String name1 = "testname1"; + final String name2 = "testname2"; + Dictionary<String,Object> properties = new Hashtable<String,Object>(); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ERROR_PAGE, + name1); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, + "(" + HttpWhiteboardConstants.HTTP_SERVICE_CONTEXT_PROPERTY + + "=*)"); + long before = getHttpRuntimeChangeCount(); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet(), properties)); + before = waitForRegistration(before); + + properties = new Hashtable<>(); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ERROR_PAGE, + name2); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, + "/" + name2); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, + "(" + HttpWhiteboardConstants.HTTP_SERVICE_CONTEXT_PROPERTY + + "=*)"); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet(), properties)); + before = waitForRegistration(before); + + assertNull(getFailedErrorPageDTOByException(name1)); + assertNotNull("" + getHttpServiceRuntime().getRuntimeDTO(), + getFailedErrorPageDTOByException(name2)); + + final ServletContextDTO scDTO = getServletContextDTOForDummyServlet(); + assertNotNull(getErrorPageDTOByException(scDTO.name, name1)); + assertNull(getErrorPageDTOByException(scDTO.name, name2)); + } finally { + unregisterDummyServletFromHttpService(); + } + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndNamedServlet.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndNamedServlet.java new file mode 100644 index 000000000..ade206faf --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestHttpServiceAndNamedServlet.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) Jan. 26, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.Dictionary; +import java.util.Hashtable; + +import javax.servlet.Servlet; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.eclipse.equinox.http.servlet.tests.util.MockServlet; +import org.junit.Test; +import org.osgi.service.http.runtime.dto.ServletContextDTO; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; + +public class TestHttpServiceAndNamedServlet extends BaseTest { + + /** + * Registration of named servlet with http service (allowed) and named + * servlet and pattern with http service (not allowed) + */ + @Test + public void testHttpServiceAndNamedServlet() throws Exception { + registerDummyServletInHttpService(); + try { + final String name1 = "testname1"; + final String name2 = "testname2"; + Dictionary<String,Object> properties = new Hashtable<String,Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME, + name1); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, + "(" + HttpWhiteboardConstants.HTTP_SERVICE_CONTEXT_PROPERTY + + "=*)"); + long before = getHttpRuntimeChangeCount(); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet(), properties)); + before = waitForRegistration(before); + + properties = new Hashtable<>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME, + name2); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, + "/" + name2); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, + "(" + HttpWhiteboardConstants.HTTP_SERVICE_CONTEXT_PROPERTY + + "=*)"); + registrations.add(getBundleContext().registerService( + Servlet.class, new MockServlet(), properties)); + before = waitForRegistration(before); + + assertNull(getFailedServletDTOByName(name1)); + assertNotNull("" + getHttpServiceRuntime().getRuntimeDTO(), + getFailedServletDTOByName(name2)); + + final ServletContextDTO scDTO = getServletContextDTOForDummyServlet(); + assertNotNull(getServletDTOByName(scDTO.name, name1)); + assertNull(getServletDTOByName(scDTO.name, name2)); + } finally { + unregisterDummyServletFromHttpService(); + } + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestUpload.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestUpload.java new file mode 100644 index 000000000..ed5804b14 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/TestUpload.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) Jan. 26, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_MULTIPART_ENABLED; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_MULTIPART_MAXFILESIZE; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN; + +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import java.util.Collection; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.Part; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.junit.Test; + +public class TestUpload extends BaseTest { + + @Test + public void testUpload() throws Exception { + final CountDownLatch receivedLatch = new CountDownLatch(1); + final Map<String,Long> contents = new HashMap<>(); + setupUploadServlet(receivedLatch, contents); + + postContent(getClass().getResource("resource1.txt"), 201); + assertTrue(receivedLatch.await(5, TimeUnit.SECONDS)); + assertEquals(1, contents.size()); + assertEquals(25L, (long) contents.get("text.txt")); + } + + private void setupUploadServlet(final CountDownLatch receivedLatch, + final Map<String,Long> contents) + throws Exception { + final Dictionary<String,Object> servletProps = new Hashtable<String,Object>(); + servletProps.put(HTTP_WHITEBOARD_SERVLET_PATTERN, "/post"); + servletProps.put(HTTP_WHITEBOARD_SERVLET_MULTIPART_ENABLED, + Boolean.TRUE); + servletProps.put(HTTP_WHITEBOARD_SERVLET_MULTIPART_MAXFILESIZE, 1024L); + + @SuppressWarnings("serial") + final Servlet uploadServlet = new HttpServlet() { + @Override + protected void doPost(HttpServletRequest req, + HttpServletResponse resp) + throws IOException, ServletException { + try { + final Collection<Part> parts = req.getParts(); + for (final Part p : parts) { + contents.put(p.getName(), p.getSize()); + } + resp.setStatus(201); + } finally { + receivedLatch.countDown(); + } + + } + }; + + long before = this.getHttpRuntimeChangeCount(); + registrations.add(getBundleContext().registerService( + Servlet.class.getName(), uploadServlet, servletProps)); + this.waitForRegistration(before); + } + + private void postContent(final URL resource, final int expectedRT) throws IOException { + Map<String, List<Object>> map = new HashMap<String, List<Object>>(); + + map.put("method", Arrays.<Object>asList("POST")); + map.put("text.txt", Arrays.<Object>asList(resource)); + + Map<String, List<String>> result = requestAdvisor.upload("post", map); + + assertEquals(expectedRT + "", result.get("responseCode").get(0)); + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_140_4_9.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_140_4_9.java index 08ac3ef5d..3b9dce65d 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_140_4_9.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_140_4_9.java @@ -67,7 +67,7 @@ public class Test_140_4_9 extends BaseTest { invoked.set(false); assertEquals("a", requestAdvisor.request("some/path/b.html")); assertTrue(invoked.get()); - assertEquals("404", requestAdvisor.request("", null).get("responseCode").get(0)); + assertEquals("a", requestAdvisor.request("")); } } diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate.java new file mode 100644 index 000000000..62c6d72ec --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) Jan. 26, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Dictionary; +import java.util.Hashtable; + +import javax.servlet.Servlet; +import javax.servlet.http.HttpServlet; + +import org.eclipse.equinox.http.servlet.testbase.BaseTest; +import org.junit.Test; +import org.osgi.framework.BundleContext; +import org.osgi.service.http.runtime.dto.RequestInfoDTO; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; + +public class Test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate extends BaseTest { + + @SuppressWarnings("serial") + @Test + public void test_table_140_4_HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED_validate() throws Exception { + BundleContext context = getBundleContext(); + + Dictionary<String, Object> properties = new Hashtable<String, Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, "blah"); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/a"); + registrations.add(context.registerService(Servlet.class, new HttpServlet() {}, properties)); + + RequestInfoDTO requestInfoDTO = calculateRequestInfoDTO("/a"); + + assertNotNull(requestInfoDTO); + assertNotNull(requestInfoDTO.servletDTO); + assertFalse(requestInfoDTO.servletDTO.asyncSupported); + + properties = new Hashtable<String, Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, "true"); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/b"); + registrations.add(context.registerService(Servlet.class, new HttpServlet() {}, properties)); + + requestInfoDTO = calculateRequestInfoDTO("/b"); + + assertNotNull(requestInfoDTO); + assertNotNull(requestInfoDTO.servletDTO); + assertTrue(requestInfoDTO.servletDTO.asyncSupported); + + properties = new Hashtable<String, Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, "false"); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/c"); + registrations.add(context.registerService(Servlet.class, new HttpServlet() {}, properties)); + + requestInfoDTO = calculateRequestInfoDTO("/c"); + + assertNotNull(requestInfoDTO); + assertNotNull(requestInfoDTO.servletDTO); + assertFalse(requestInfoDTO.servletDTO.asyncSupported); + + properties = new Hashtable<String, Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, 234l); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/d"); + registrations.add(context.registerService(Servlet.class, new HttpServlet() {}, properties)); + + requestInfoDTO = calculateRequestInfoDTO("/d"); + + assertNotNull(requestInfoDTO); + assertNotNull(requestInfoDTO.servletDTO); + assertFalse(requestInfoDTO.servletDTO.asyncSupported); + + properties = new Hashtable<String, Object>(); + properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/e"); + registrations.add(context.registerService(Servlet.class, new HttpServlet() {}, properties)); + + requestInfoDTO = calculateRequestInfoDTO("/e"); + + assertNotNull(requestInfoDTO); + assertNotNull(requestInfoDTO.servletDTO); + assertFalse(requestInfoDTO.servletDTO.asyncSupported); + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN.java index 7e06520df..bd2d91867 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN.java @@ -68,7 +68,7 @@ public class Test_table_140_5_HTTP_WHITEBOARD_FILTER_PATTERN extends BaseTest { assertEquals("bab", requestAdvisor.request("a")); assertEquals("bab", requestAdvisor.request("a.html")); assertEquals("bab", requestAdvisor.request("some/path/b.html")); - assertEquals("a", requestAdvisor.request("")); + assertEquals("bab", requestAdvisor.request("")); properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN, ""); sr.setProperties(properties); diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/MockPreprocessor.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/MockPreprocessor.java new file mode 100644 index 000000000..f4edb2350 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/MockPreprocessor.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) Jan. 26, 2019 Liferay, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Liferay, Inc. - tests + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests.util; + +import org.osgi.service.http.whiteboard.Preprocessor; + +public class MockPreprocessor extends MockFilter implements Preprocessor { + +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java index 6d03d4015..a5f82a12b 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java @@ -281,6 +281,10 @@ public class ServletRequestAdvisor extends Object { connection.setReadTimeout(150 * 1000); if (headers != null) { + if (headers.containsKey("method")) { + connection.setRequestMethod((String)headers.remove("method").get(0)); + } + for(Map.Entry<String, List<Object>> entry : headers.entrySet()) { for(Object entryValue : entry.getValue()) { if (entryValue instanceof String) { @@ -339,7 +343,9 @@ public class ServletRequestAdvisor extends Object { writer.append("--" + boundary); writer.append(CRLF); - writer.append("Content-Disposition: form-data; name=\"file\"; filename=\""); + writer.append("Content-Disposition: form-data; name=\""); + writer.append(param); + writer.append("\"; filename=\""); writer.append(fileName); writer.append("\""); writer.append(CRLF); |