Repository: asterixdb Updated Branches: refs/heads/master 62914c636 -> 7def53f4e
[ASTERIXDB-2052][OTH] Release resources on http request rejection - user model changes: no - storage format changes: no - interface changes: no details: - When a request is rejected, we release its resources. - A test case was added which sends 3500+ rejected requests and causes the server to throw out of memory error prior to this fix. Change-Id: Ia0e3f3e6e2f94a31f296b3491a07f624a4fea604 Reviewed-on: https://asterix-gerrit.ics.uci.edu/1955 Sonar-Qube: Jenkins <[email protected]> Tested-by: Jenkins <[email protected]> Contrib: Jenkins <[email protected]> Integration-Tests: Jenkins <[email protected]> Reviewed-by: Till Westmann <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/7def53f4 Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/7def53f4 Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/7def53f4 Branch: refs/heads/master Commit: 7def53f4e75abbb50012823ce6cb44fad911e117 Parents: 62914c6 Author: Abdullah Alamoudi <[email protected]> Authored: Mon Aug 21 15:59:00 2017 -0700 Committer: abdullah alamoudi <[email protected]> Committed: Mon Aug 21 17:27:09 2017 -0700 ---------------------------------------------------------------------- .../api/http/server/QueryServiceServlet.java | 7 + hyracks-fullstack/hyracks/hyracks-http/pom.xml | 5 +- .../hyracks/http/server/ChunkedResponse.java | 2 +- .../hyracks/http/server/HttpRequestHandler.java | 8 +- .../apache/hyracks/http/server/HttpServer.java | 9 +- .../hyracks/http/servlet/ChattyServlet.java | 5 + .../hyracks/http/servlet/SleepyServlet.java | 66 +++++++++ .../hyracks/http/servlet/SlowServlet.java | 43 ------ .../hyracks/http/test/HttpServerTest.java | 140 ++++++++++++++++--- 9 files changed, 214 insertions(+), 71 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/asterixdb/blob/7def53f4/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java index 1cec616..1f1d282 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java @@ -62,6 +62,7 @@ import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; + import io.netty.handler.codec.http.HttpResponseStatus; public class QueryServiceServlet extends AbstractQueryApiServlet { @@ -93,6 +94,12 @@ public class QueryServiceServlet extends AbstractQueryApiServlet { // Servlet methods should not throw exceptions // http://cwe.mitre.org/data/definitions/600.html GlobalConfig.ASTERIX_LOGGER.log(Level.SEVERE, e.getMessage(), e); + } catch (Throwable th) {// NOSONAR: Logging and re-throwing + try { + GlobalConfig.ASTERIX_LOGGER.log(Level.SEVERE, th.getMessage(), th); + } catch (Throwable ignored) { // NOSONAR: Logging failure + } + throw th; } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/7def53f4/hyracks-fullstack/hyracks/hyracks-http/pom.xml ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/pom.xml b/hyracks-fullstack/hyracks/hyracks-http/pom.xml index 6439adb..cb69caa 100644 --- a/hyracks-fullstack/hyracks/hyracks-http/pom.xml +++ b/hyracks-fullstack/hyracks/hyracks-http/pom.xml @@ -27,6 +27,9 @@ <artifactId>hyracks-http</artifactId> <properties> <root.dir>${basedir}/../..</root.dir> + <direct.mem>-XX:MaxDirectMemorySize</direct.mem> + <num.arenas>-Dio.netty.allocator.numDirectArenas</num.arenas> + <max.order>-Dio.netty.allocator.maxOrder</max.order> </properties> <build> <plugins> @@ -34,7 +37,7 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> - <argLine>-XX:MaxDirectMemorySize=16M</argLine> + <argLine>${direct.mem}=16M ${num.arenas}=4 ${max.order}=7</argLine> </configuration> </plugin> </plugins> http://git-wip-us.apache.org/repos/asf/asterixdb/blob/7def53f4/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedResponse.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedResponse.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedResponse.java index 64be051..47714ae 100644 --- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedResponse.java +++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedResponse.java @@ -113,7 +113,7 @@ public class ChunkedResponse implements IServletResponse { } else { // There was an error if (headerSent) { - LOGGER.log(Level.WARNING,"Error after header write of chunked response"); + LOGGER.log(Level.WARNING, "Error after header write of chunked response"); if (error != null) { error.release(); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/7def53f4/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpRequestHandler.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpRequestHandler.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpRequestHandler.java index aa0f32a..cabb01f 100644 --- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpRequestHandler.java +++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpRequestHandler.java @@ -82,7 +82,11 @@ public class HttpRequestHandler implements Callable<Void> { } public void reject() throws IOException { - response.setStatus(HttpResponseStatus.SERVICE_UNAVAILABLE); - response.close(); + try { + response.setStatus(HttpResponseStatus.SERVICE_UNAVAILABLE); + response.close(); + } finally { + request.getHttpRequest().release(); + } } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/7def53f4/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java index 6ceafc6..45634ad 100644 --- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java +++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java @@ -60,6 +60,7 @@ public class HttpServer { private final Object lock = new Object(); private final AtomicInteger threadId = new AtomicInteger(); private final ConcurrentMap<String, Object> ctx; + private final LinkedBlockingQueue<Runnable> workQueue; private final List<IServlet> servlets; private final EventLoopGroup bossGroup; private final EventLoopGroup workerGroup; @@ -81,8 +82,8 @@ public class HttpServer { this.port = port; ctx = new ConcurrentHashMap<>(); servlets = new ArrayList<>(); - executor = new ThreadPoolExecutor(numExecutorThreads, numExecutorThreads, 0L, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue<>(requestQueueSize), + workQueue = new LinkedBlockingQueue<>(requestQueueSize); + executor = new ThreadPoolExecutor(numExecutorThreads, numExecutorThreads, 0L, TimeUnit.MILLISECONDS, workQueue, runnable -> new Thread(runnable, "HttpExecutor(port:" + port + ")-" + threadId.getAndIncrement())); long directMemoryBudget = numExecutorThreads * (long) HIGH_WRITE_BUFFER_WATER_MARK + numExecutorThreads * HttpServerInitializer.RESPONSE_CHUNK_SIZE; @@ -270,4 +271,8 @@ public class HttpServer { protected EventLoopGroup getWorkerGroup() { return workerGroup; } + + public int getWorkQueueSize() { + return workQueue.size(); + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/7def53f4/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/ChattyServlet.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/ChattyServlet.java b/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/ChattyServlet.java index 863eddd..bf0452b 100644 --- a/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/ChattyServlet.java +++ b/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/ChattyServlet.java @@ -54,6 +54,11 @@ public class ChattyServlet extends AbstractServlet { } @Override + protected void post(IServletRequest request, IServletResponse response) throws Exception { + get(request, response); + } + + @Override protected void get(IServletRequest request, IServletResponse response) throws Exception { response.setStatus(HttpResponseStatus.OK); HttpUtil.setContentType(response, HttpUtil.ContentType.TEXT_HTML, HttpUtil.Encoding.UTF8); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/7def53f4/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/SleepyServlet.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/SleepyServlet.java b/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/SleepyServlet.java new file mode 100644 index 0000000..6bfa0cf --- /dev/null +++ b/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/SleepyServlet.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.hyracks.http.servlet; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.ConcurrentMap; + +import org.apache.hyracks.http.api.IServletRequest; +import org.apache.hyracks.http.api.IServletResponse; +import org.apache.hyracks.http.server.AbstractServlet; +import org.apache.hyracks.http.server.utils.HttpUtil; + +import io.netty.handler.codec.http.HttpResponseStatus; + +public class SleepyServlet extends AbstractServlet { + + private volatile boolean sleep = true; + + public SleepyServlet(ConcurrentMap<String, Object> ctx, String[] paths) { + super(ctx, paths); + } + + @Override + protected void post(IServletRequest request, IServletResponse response) throws Exception { + get(request, response); + } + + @Override + protected void get(IServletRequest request, IServletResponse response) throws Exception { + response.setStatus(HttpResponseStatus.OK); + if (sleep) { + synchronized (this) { + while (sleep) { + this.wait(); + } + } + } + HttpUtil.setContentType(response, HttpUtil.ContentType.TEXT_HTML, HttpUtil.Encoding.UTF8); + response.outputStream().write("I am playing hard to get".getBytes(StandardCharsets.UTF_8)); + } + + public synchronized void wakeUp() { + sleep = false; + notifyAll(); + } + + public void sleep() { + sleep = true; + } +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/7def53f4/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/SlowServlet.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/SlowServlet.java b/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/SlowServlet.java deleted file mode 100644 index 065d803..0000000 --- a/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/servlet/SlowServlet.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.hyracks.http.servlet; - -import java.nio.charset.StandardCharsets; -import java.util.concurrent.ConcurrentMap; - -import org.apache.hyracks.http.api.IServletRequest; -import org.apache.hyracks.http.api.IServletResponse; -import org.apache.hyracks.http.server.AbstractServlet; -import org.apache.hyracks.http.server.utils.HttpUtil; - -import io.netty.handler.codec.http.HttpResponseStatus; - -public class SlowServlet extends AbstractServlet { - public SlowServlet(ConcurrentMap<String, Object> ctx, String[] paths) { - super(ctx, paths); - } - - @Override - protected void get(IServletRequest request, IServletResponse response) throws Exception { - response.setStatus(HttpResponseStatus.OK); - Thread.sleep(5000); // NOSONAR - HttpUtil.setContentType(response, HttpUtil.ContentType.TEXT_HTML, HttpUtil.Encoding.UTF8); - response.outputStream().write("I am playing hard to get".getBytes(StandardCharsets.UTF_8)); - } -} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/7def53f4/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/test/HttpServerTest.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/test/HttpServerTest.java b/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/test/HttpServerTest.java index 6512dc1..66d1b77 100644 --- a/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/test/HttpServerTest.java +++ b/hyracks-fullstack/hyracks/hyracks-http/src/test/java/org/apache/hyracks/http/test/HttpServerTest.java @@ -30,6 +30,9 @@ import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.io.IOUtils; @@ -37,12 +40,13 @@ import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.StandardHttpRequestRetryHandler; import org.apache.hyracks.http.server.HttpServer; import org.apache.hyracks.http.server.WebManager; import org.apache.hyracks.http.servlet.ChattyServlet; -import org.apache.hyracks.http.servlet.SlowServlet; +import org.apache.hyracks.http.servlet.SleepyServlet; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -52,16 +56,14 @@ import io.netty.handler.codec.http.HttpResponseStatus; public class HttpServerTest { static final boolean PRINT_TO_CONSOLE = false; static final int PORT = 9898; - static final int NUM_EXECUTOR_THREADS = 16; - static final int SERVER_QUEUE_SIZE = 16; - static final int NUM_OF_REQUESTS = 48; static final String HOST = "localhost"; static final String PROTOCOL = "http"; static final String PATH = "/"; static final AtomicInteger SUCCESS_COUNT = new AtomicInteger(); static final AtomicInteger UNAVAILABLE_COUNT = new AtomicInteger(); static final AtomicInteger OTHER_COUNT = new AtomicInteger(); - static final List<Thread> THREADS = new ArrayList<>(); + static final List<Future<Void>> FUTURES = new ArrayList<>(); + static final ExecutorService executor = Executors.newCachedThreadPool(); @Before public void setUp() { @@ -73,31 +75,106 @@ public class HttpServerTest { @Test public void testOverloadingServer() throws Exception { WebManager webMgr = new WebManager(); + int numExecutors = 16; + int serverQueueSize = 16; + int numRequests = 48; HttpServer server = - new HttpServer(webMgr.getBosses(), webMgr.getWorkers(), PORT, NUM_EXECUTOR_THREADS, SERVER_QUEUE_SIZE); - SlowServlet servlet = new SlowServlet(server.ctx(), new String[] { PATH }); + new HttpServer(webMgr.getBosses(), webMgr.getWorkers(), PORT, numExecutors, serverQueueSize); + SleepyServlet servlet = new SleepyServlet(server.ctx(), new String[] { PATH }); server.addServlet(servlet); webMgr.add(server); webMgr.start(); + int expectedSuccess = numExecutors + serverQueueSize; + int expectedUnavailable = numRequests - expectedSuccess; try { - request(NUM_OF_REQUESTS); - for (Thread thread : THREADS) { - thread.join(); + request(expectedSuccess); + waitTillQueued(server, serverQueueSize); + ArrayList<Future<Void>> successSet = started(); + request(expectedUnavailable); + ArrayList<Future<Void>> rejectedSet = started(); + for (Future<Void> f : rejectedSet) { + f.get(); + } + servlet.wakeUp(); + for (Future<Void> f : successSet) { + f.get(); } - Assert.assertEquals(32, SUCCESS_COUNT.get()); - Assert.assertEquals(16, UNAVAILABLE_COUNT.get()); + Assert.assertEquals(expectedSuccess, SUCCESS_COUNT.get()); + Assert.assertEquals(expectedUnavailable, UNAVAILABLE_COUNT.get()); Assert.assertEquals(0, OTHER_COUNT.get()); + } catch (Throwable th) { + th.printStackTrace(); + throw th; } finally { webMgr.stop(); } } + private void waitTillQueued(HttpServer server, int expectedQueued) throws Exception { + int maxAttempts = 5; + int attempt = 0; + int queued = server.getWorkQueueSize(); + while (queued != expectedQueued) { + attempt++; + if (attempt > maxAttempts) { + throw new Exception("Number of queued requests (" + queued + ") didn't match the expected number (" + + expectedQueued + ")"); + } + Thread.sleep(1000); // NOSONAR polling is the clean way + queued = server.getWorkQueueSize(); + } + } + + @Test + public void testReleaseRejectedRequest() throws Exception { + WebManager webMgr = new WebManager(); + int numRequests = 64; + int numExecutors = 2; + int serverQueueSize = 2; + int numPatches = 60; + HttpServer server = + new HttpServer(webMgr.getBosses(), webMgr.getWorkers(), PORT, numExecutors, serverQueueSize); + SleepyServlet servlet = new SleepyServlet(server.ctx(), new String[] { PATH }); + server.addServlet(servlet); + webMgr.add(server); + webMgr.start(); + request(numExecutors + serverQueueSize); + ArrayList<Future<Void>> stuck = started(); + waitTillQueued(server, serverQueueSize); + try { + try { + for (int i = 0; i < numPatches; i++) { + ChattyServlet.printMemUsage(); + request(numRequests); + for (Future<Void> f : FUTURES) { + f.get(); + } + FUTURES.clear(); + } + } finally { + ChattyServlet.printMemUsage(); + servlet.wakeUp(); + for (Future<Void> f : stuck) { + f.get(); + } + } + } finally { + webMgr.stop(); + } + } + + private ArrayList<Future<Void>> started() { + ArrayList<Future<Void>> started = new ArrayList<>(FUTURES); + FUTURES.clear(); + return started; + } + @Test public void testChattyServer() throws Exception { - ChattyServlet.printMemUsage(); int numRequests = 64; int numExecutors = 32; int serverQueueSize = 32; + ChattyServlet.printMemUsage(); WebManager webMgr = new WebManager(); HttpServer server = new HttpServer(webMgr.getBosses(), webMgr.getWorkers(), PORT, numExecutors, serverQueueSize); @@ -107,8 +184,8 @@ public class HttpServerTest { webMgr.start(); try { request(numRequests); - for (Thread thread : THREADS) { - thread.join(); + for (Future<Void> thread : FUTURES) { + thread.get(); } Assert.assertEquals(numRequests, SUCCESS_COUNT.get()); Assert.assertEquals(0, UNAVAILABLE_COUNT.get()); @@ -120,10 +197,12 @@ public class HttpServerTest { @Test public void testMalformedString() throws Exception { + int numExecutors = 16; + int serverQueueSize = 16; WebManager webMgr = new WebManager(); HttpServer server = - new HttpServer(webMgr.getBosses(), webMgr.getWorkers(), PORT, NUM_EXECUTOR_THREADS, SERVER_QUEUE_SIZE); - SlowServlet servlet = new SlowServlet(server.ctx(), new String[] { PATH }); + new HttpServer(webMgr.getBosses(), webMgr.getWorkers(), PORT, numExecutors, serverQueueSize); + SleepyServlet servlet = new SleepyServlet(server.ctx(), new String[] { PATH }); server.addServlet(servlet); webMgr.add(server); webMgr.start(); @@ -160,9 +239,9 @@ public class HttpServerTest { private void request(int count) { for (int i = 0; i < count; i++) { - Thread next = new Thread(() -> { + Future<Void> next = executor.submit(() -> { try { - HttpUriRequest request = request(null); + HttpUriRequest request = post(null); HttpResponse response = executeHttpRequest(request); if (response.getStatusLine().getStatusCode() == HttpResponseStatus.OK.code()) { SUCCESS_COUNT.incrementAndGet(); @@ -183,10 +262,11 @@ public class HttpServerTest { IOUtils.closeQuietly(in); } catch (Throwable th) { th.printStackTrace(); + throw th; } + return null; }); - THREADS.add(next); - next.start(); + FUTURES.add(next); } } @@ -200,10 +280,26 @@ public class HttpServerTest { } } - protected HttpUriRequest request(String query) throws URISyntaxException { + protected HttpUriRequest get(String query) throws URISyntaxException { URI uri = new URI(PROTOCOL, null, HOST, PORT, PATH, query, null); RequestBuilder builder = RequestBuilder.get(uri); builder.setCharset(StandardCharsets.UTF_8); return builder.build(); } + + protected HttpUriRequest post(String query) throws URISyntaxException { + URI uri = new URI(PROTOCOL, null, HOST, PORT, PATH, query, null); + RequestBuilder builder = RequestBuilder.post(uri); + StringBuilder str = new StringBuilder(); + for (int i = 0; i < 32; i++) { + str.append("This is a string statement that will be ignored"); + str.append('\n'); + } + String statement = str.toString(); + builder.setHeader("Content-type", "application/x-www-form-urlencoded"); + builder.addParameter("statement", statement); + builder.setEntity(new StringEntity(statement, StandardCharsets.UTF_8)); + builder.setCharset(StandardCharsets.UTF_8); + return builder.build(); + } }
