Repository: asterixdb Updated Branches: refs/heads/master e0d8e5078 -> a14cebbf0
[ASTERIXDB-2013][HYR] non-POST x-www-form-urlencoded, config null value handling - handle null config values when marshall/unmarshalling - support non-post x-www-form-urlencoded directly - don't assume POSTs are x-www-form-urlencoded - add support to TestExecutor for POST/PUT form-urlencoded parameters Change-Id: I670b815a5276d870f7d538d1ce9d8bef2d0fcf4f Reviewed-on: https://asterix-gerrit.ics.uci.edu/1911 Reviewed-by: Till Westmann <[email protected]> Tested-by: Jenkins <[email protected]> Contrib: Jenkins <[email protected]> Integration-Tests: Jenkins <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/a14cebbf Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/a14cebbf Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/a14cebbf Branch: refs/heads/master Commit: a14cebbf0c62cec4593eaa3e81b3b4919286be05 Parents: e0d8e50 Author: Michael Blow <[email protected]> Authored: Fri Aug 4 19:59:30 2017 -0400 Committer: Michael Blow <[email protected]> Committed: Fri Aug 4 19:13:50 2017 -0700 ---------------------------------------------------------------------- .../api/http/server/QueryResultApiServlet.java | 2 +- .../api/http/server/QueryServiceServlet.java | 6 +- .../api/http/server/QueryStatusApiServlet.java | 2 +- .../hyracks/bootstrap/CCApplication.java | 4 +- .../asterix/test/common/TestExecutor.java | 185 +++++++++++-------- .../org/apache/hyracks/api/config/IOption.java | 7 + .../apache/hyracks/api/config/IOptionType.java | 7 + .../hyracks-control-common/pom.xml | 4 + .../control/common/config/ConfigManager.java | 2 +- .../control/common/config/OptionTypes.java | 69 ++++++- .../hyracks/http/api/IServletRequest.java | 17 ++ .../apache/hyracks/http/server/BaseRequest.java | 18 ++ .../http/server/FormUrlEncodedRequest.java | 99 ++++++++++ .../apache/hyracks/http/server/PostRequest.java | 89 --------- .../hyracks/http/server/utils/HttpUtil.java | 19 +- 15 files changed, 343 insertions(+), 187 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java index 42e23ba..901aff8 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java @@ -41,7 +41,7 @@ import io.netty.handler.codec.http.HttpResponseStatus; public class QueryResultApiServlet extends AbstractQueryApiServlet { private static final Logger LOGGER = Logger.getLogger(QueryResultApiServlet.class.getName()); - public QueryResultApiServlet(ConcurrentMap<String, Object> ctx, String[] paths, IApplicationContext appCtx) { + public QueryResultApiServlet(ConcurrentMap<String, Object> ctx, IApplicationContext appCtx, String... paths) { super(appCtx, ctx, paths); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/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 9ee064e..1cec616 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,8 +62,6 @@ 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.HttpHeaderNames; import io.netty.handler.codec.http.HttpResponseStatus; public class QueryServiceServlet extends AbstractQueryApiServlet { @@ -317,9 +315,7 @@ public class QueryServiceServlet extends AbstractQueryApiServlet { } private RequestParameters getRequestParameters(IServletRequest request) throws IOException { - final String contentTypeParam = request.getHttpRequest().headers().get(HttpHeaderNames.CONTENT_TYPE); - int sep = contentTypeParam.indexOf(';'); - final String contentType = sep < 0 ? contentTypeParam.trim() : contentTypeParam.substring(0, sep).trim(); + final String contentType = HttpUtil.getContentTypeOnly(request); RequestParameters param = new RequestParameters(); param.host = host(request); param.path = servletPath(request); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryStatusApiServlet.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryStatusApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryStatusApiServlet.java index 71dddc0..cec65f7 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryStatusApiServlet.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryStatusApiServlet.java @@ -41,7 +41,7 @@ import io.netty.handler.codec.http.HttpResponseStatus; public class QueryStatusApiServlet extends AbstractQueryApiServlet { private static final Logger LOGGER = Logger.getLogger(QueryStatusApiServlet.class.getName()); - public QueryStatusApiServlet(ConcurrentMap<String, Object> ctx, String[] paths, IApplicationContext appCtx) { + public QueryStatusApiServlet(ConcurrentMap<String, Object> ctx, IApplicationContext appCtx, String... paths) { super(appCtx, ctx, paths); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java index 3627974..e8636c8 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java @@ -287,9 +287,9 @@ public class CCApplication extends BaseCCApplication { case Servlets.RUNNING_REQUESTS: return new QueryCancellationServlet(ctx, paths); case Servlets.QUERY_STATUS: - return new QueryStatusApiServlet(ctx, paths, appCtx); + return new QueryStatusApiServlet(ctx, appCtx, paths); case Servlets.QUERY_RESULT: - return new QueryResultApiServlet(ctx, paths, appCtx); + return new QueryResultApiServlet(ctx, appCtx, paths); case Servlets.QUERY_SERVICE: return new QueryServiceServlet(ctx, paths, appCtx, SQLPP, ccExtensionManager.getCompilationProvider(SQLPP), getStatementExecutorFactory(), http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java index 10b528f..1079832 100644 --- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java +++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java @@ -65,6 +65,7 @@ import org.apache.asterix.testframework.context.TestCaseContext.OutputFormat; import org.apache.asterix.testframework.context.TestFileContext; import org.apache.asterix.testframework.xml.ComparisonEnum; import org.apache.asterix.testframework.xml.TestCase.CompilationUnit; +import org.apache.asterix.testframework.xml.TestCase.CompilationUnit.Parameter; import org.apache.asterix.testframework.xml.TestGroup; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; @@ -102,16 +103,17 @@ public class TestExecutor { // see // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers/417184 private static final long MAX_URL_LENGTH = 2000l; - private static final Pattern JAVA_BLOCK_COMMENT_PATTERN = - Pattern.compile("/\\*.*\\*/", Pattern.MULTILINE | Pattern.DOTALL); + private static final Pattern JAVA_BLOCK_COMMENT_PATTERN = Pattern.compile("/\\*.*\\*/", + Pattern.MULTILINE | Pattern.DOTALL); private static final Pattern JAVA_LINE_COMMENT_PATTERN = Pattern.compile("//.*$", Pattern.MULTILINE); private static final Pattern SHELL_LINE_COMMENT_PATTERN = Pattern.compile("#.*$", Pattern.MULTILINE); private static final Pattern REGEX_LINES_PATTERN = Pattern.compile("^(-)?/(.*)/([im]*)$"); - private static final Pattern POLL_TIMEOUT_PATTERN = - Pattern.compile("polltimeoutsecs=(\\d+)(\\D|$)", Pattern.MULTILINE); + private static final Pattern POLL_TIMEOUT_PATTERN = Pattern.compile("polltimeoutsecs=(\\d+)(\\D|$)", + Pattern.MULTILINE); private static final Pattern POLL_DELAY_PATTERN = Pattern.compile("polldelaysecs=(\\d+)(\\D|$)", Pattern.MULTILINE); private static final Pattern HANDLE_VARIABLE_PATTERN = Pattern.compile("handlevariable=(\\w+)"); private static final Pattern VARIABLE_REF_PATTERN = Pattern.compile("\\$(\\w+)"); + private static final Pattern HTTP_PARAM_PATTERN = Pattern.compile("param (\\w+)=(.*)", Pattern.MULTILINE); public static final int TRUNCATE_THRESHOLD = 16384; @@ -166,10 +168,10 @@ public class TestExecutor { public void runScriptAndCompareWithResult(File scriptFile, PrintWriter print, File expectedFile, File actualFile, ComparisonEnum compare) throws Exception { System.err.println("Expected results file: " + expectedFile.toString()); - BufferedReader readerExpected = - new BufferedReader(new InputStreamReader(new FileInputStream(expectedFile), "UTF-8")); - BufferedReader readerActual = - new BufferedReader(new InputStreamReader(new FileInputStream(actualFile), "UTF-8")); + BufferedReader readerExpected = new BufferedReader( + new InputStreamReader(new FileInputStream(expectedFile), "UTF-8")); + BufferedReader readerActual = new BufferedReader( + new InputStreamReader(new FileInputStream(actualFile), "UTF-8")); boolean regex = false; try { if (ComparisonEnum.BINARY.equals(compare)) { @@ -352,10 +354,10 @@ public class TestExecutor { public void runScriptAndCompareWithResultRegex(File scriptFile, File expectedFile, File actualFile) throws Exception { String lineExpected, lineActual; - try (BufferedReader readerExpected = - new BufferedReader(new InputStreamReader(new FileInputStream(expectedFile), "UTF-8")); - BufferedReader readerActual = - new BufferedReader(new InputStreamReader(new FileInputStream(actualFile), "UTF-8"))) { + try (BufferedReader readerExpected = new BufferedReader( + new InputStreamReader(new FileInputStream(expectedFile), "UTF-8")); + BufferedReader readerActual = new BufferedReader( + new InputStreamReader(new FileInputStream(actualFile), "UTF-8"))) { StringBuilder actual = new StringBuilder(); while ((lineActual = readerActual.readLine()) != null) { actual.append(lineActual).append('\n'); @@ -510,8 +512,7 @@ public class TestExecutor { } } - public InputStream executeQuery(String str, OutputFormat fmt, URI uri, List<CompilationUnit.Parameter> params) - throws Exception { + public InputStream executeQuery(String str, OutputFormat fmt, URI uri, List<Parameter> params) throws Exception { HttpUriRequest method = constructHttpMethod(str, uri, "query", false, params); // Set accepted output response type method.setHeader("Accept", fmt.mimeType()); @@ -523,21 +524,19 @@ public class TestExecutor { return executeQueryService(str, fmt, uri, new ArrayList<>(), false); } - public InputStream executeQueryService(String str, OutputFormat fmt, URI uri, - List<CompilationUnit.Parameter> params, boolean jsonEncoded) throws Exception { + public InputStream executeQueryService(String str, OutputFormat fmt, URI uri, List<Parameter> params, + boolean jsonEncoded) throws Exception { return executeQueryService(str, fmt, uri, params, jsonEncoded, null, false); } - public InputStream executeQueryService(String str, OutputFormat fmt, URI uri, - List<CompilationUnit.Parameter> params, boolean jsonEncoded, Predicate<Integer> responseCodeValidator) - throws Exception { + public InputStream executeQueryService(String str, OutputFormat fmt, URI uri, List<Parameter> params, + boolean jsonEncoded, Predicate<Integer> responseCodeValidator) throws Exception { return executeQueryService(str, fmt, uri, params, jsonEncoded, responseCodeValidator, false); } - protected InputStream executeQueryService(String str, OutputFormat fmt, URI uri, - List<CompilationUnit.Parameter> params, boolean jsonEncoded, Predicate<Integer> responseCodeValidator, - boolean cancellable) throws Exception { - final List<CompilationUnit.Parameter> newParams = upsertParam(params, "format", fmt.mimeType()); + protected InputStream executeQueryService(String str, OutputFormat fmt, URI uri, List<Parameter> params, + boolean jsonEncoded, Predicate<Integer> responseCodeValidator, boolean cancellable) throws Exception { + final List<Parameter> newParams = upsertParam(params, "format", fmt.mimeType()); HttpUriRequest method = jsonEncoded ? constructPostMethodJson(str, uri, "statement", newParams) : constructPostMethodUrl(str, uri, "statement", newParams); // Set accepted output response type @@ -549,12 +548,11 @@ public class TestExecutor { return response.getEntity().getContent(); } - protected List<CompilationUnit.Parameter> upsertParam(List<CompilationUnit.Parameter> params, String name, - String value) { + protected List<Parameter> upsertParam(List<Parameter> params, String name, String value) { boolean replaced = false; - List<CompilationUnit.Parameter> result = new ArrayList<>(); - for (CompilationUnit.Parameter param : params) { - CompilationUnit.Parameter newParam = new CompilationUnit.Parameter(); + List<Parameter> result = new ArrayList<>(); + for (Parameter param : params) { + Parameter newParam = new Parameter(); newParam.setName(param.getName()); if (name.equals(param.getName())) { newParam.setValue(value); @@ -565,7 +563,7 @@ public class TestExecutor { result.add(newParam); } if (!replaced) { - CompilationUnit.Parameter newParam = new CompilationUnit.Parameter(); + Parameter newParam = new Parameter(); newParam.setName(name); newParam.setValue(value); result.add(newParam); @@ -574,7 +572,7 @@ public class TestExecutor { } private HttpUriRequest constructHttpMethod(String statement, URI uri, String stmtParam, boolean postStmtAsParam, - List<CompilationUnit.Parameter> otherParams) throws URISyntaxException { + List<Parameter> otherParams) throws URISyntaxException { if (statement.length() + uri.toString().length() < MAX_URL_LENGTH) { // Use GET for small-ish queries return constructGetMethod(uri, upsertParam(otherParams, stmtParam, statement)); @@ -585,32 +583,49 @@ public class TestExecutor { } } - private HttpUriRequest constructGetMethod(URI endpoint, List<CompilationUnit.Parameter> params) { + private HttpUriRequest constructGetMethod(URI endpoint, List<Parameter> params) { RequestBuilder builder = RequestBuilder.get(endpoint); - for (CompilationUnit.Parameter param : params) { + for (Parameter param : params) { builder.addParameter(param.getName(), param.getValue()); } builder.setCharset(StandardCharsets.UTF_8); return builder.build(); } - private HttpUriRequest constructGetMethod(URI endpoint, OutputFormat fmt, List<CompilationUnit.Parameter> params) { + private HttpUriRequest buildRequest(String method, URI uri, List<Parameter> params) { + RequestBuilder builder = RequestBuilder.create(method); + builder.setUri(uri); + for (Parameter param : params) { + builder.addParameter(param.getName(), param.getValue()); + } + builder.setCharset(StandardCharsets.UTF_8); + return builder.build(); + } + + private HttpUriRequest buildRequest(String method, URI uri, OutputFormat fmt, List<Parameter> params) { + HttpUriRequest request = buildRequest(method, uri, params); + // Set accepted output response type + request.setHeader("Accept", fmt.mimeType()); + return request; + } + + private HttpUriRequest constructGetMethod(URI endpoint, OutputFormat fmt, List<Parameter> params) { HttpUriRequest method = constructGetMethod(endpoint, params); // Set accepted output response type method.setHeader("Accept", fmt.mimeType()); return method; } - private HttpUriRequest constructPostMethod(URI uri, List<CompilationUnit.Parameter> params) { + private HttpUriRequest constructPostMethod(URI uri, List<Parameter> params) { RequestBuilder builder = RequestBuilder.post(uri); - for (CompilationUnit.Parameter param : params) { + for (Parameter param : params) { builder.addParameter(param.getName(), param.getValue()); } builder.setCharset(StandardCharsets.UTF_8); return builder.build(); } - private HttpUriRequest constructPostMethod(URI uri, OutputFormat fmt, List<CompilationUnit.Parameter> params) { + private HttpUriRequest constructPostMethod(URI uri, OutputFormat fmt, List<Parameter> params) { HttpUriRequest method = constructPostMethod(uri, params); // Set accepted output response type method.setHeader("Accept", fmt.mimeType()); @@ -618,10 +633,10 @@ public class TestExecutor { } protected HttpUriRequest constructPostMethodUrl(String statement, URI uri, String stmtParam, - List<CompilationUnit.Parameter> otherParams) { + List<Parameter> otherParams) { RequestBuilder builder = RequestBuilder.post(uri); if (stmtParam != null) { - for (CompilationUnit.Parameter param : upsertParam(otherParams, stmtParam, statement)) { + for (Parameter param : upsertParam(otherParams, stmtParam, statement)) { builder.addParameter(param.getName(), param.getValue()); } builder.addParameter(stmtParam, statement); @@ -634,14 +649,14 @@ public class TestExecutor { } protected HttpUriRequest constructPostMethodJson(String statement, URI uri, String stmtParam, - List<CompilationUnit.Parameter> otherParams) { + List<Parameter> otherParams) { if (stmtParam == null) { throw new NullPointerException("Statement parameter required."); } RequestBuilder builder = RequestBuilder.post(uri); ObjectMapper om = new ObjectMapper(); ObjectNode content = om.createObjectNode(); - for (CompilationUnit.Parameter param : upsertParam(otherParams, stmtParam, statement)) { + for (Parameter param : upsertParam(otherParams, stmtParam, statement)) { content.put(param.getName(), param.getValue()); } try { @@ -654,23 +669,26 @@ public class TestExecutor { } public InputStream executeJSONGet(OutputFormat fmt, URI uri) throws Exception { - return executeJSONGet(fmt, uri, code -> code == HttpStatus.SC_OK); + return executeJSON(fmt, "GET", uri, Collections.emptyList()); } - public InputStream executeJSONGet(OutputFormat fmt, URI uri, Predicate<Integer> responseCodeValidator) - throws Exception { - HttpUriRequest request = constructGetMethod(uri, fmt, new ArrayList<>()); - HttpResponse response = executeAndCheckHttpRequest(request, responseCodeValidator); - return response.getEntity().getContent(); + public InputStream executeJSONGet(OutputFormat fmt, URI uri, List<Parameter> params, + Predicate<Integer> responseCodeValidator) throws Exception { + return executeJSON(fmt, "GET", uri, params, responseCodeValidator); } - public InputStream executeJSONPost(OutputFormat fmt, URI uri) throws Exception { - return executeJSONPost(fmt, uri, code -> code == HttpStatus.SC_OK); + public InputStream executeJSON(OutputFormat fmt, String method, URI uri, List<Parameter> params) throws Exception { + return executeJSON(fmt, method, uri, params, code -> code == HttpStatus.SC_OK); } - public InputStream executeJSONPost(OutputFormat fmt, URI uri, Predicate<Integer> responseCodeValidator) + public InputStream executeJSON(OutputFormat fmt, String method, URI uri, Predicate<Integer> responseCodeValidator) throws Exception { - HttpUriRequest request = constructPostMethod(uri, fmt, new ArrayList<>()); + return executeJSON(fmt, method, uri, Collections.emptyList(), responseCodeValidator); + } + + public InputStream executeJSON(OutputFormat fmt, String method, URI uri, List<Parameter> params, + Predicate<Integer> responseCodeValidator) throws Exception { + HttpUriRequest request = buildRequest(method, uri, fmt, params); HttpResponse response = executeAndCheckHttpRequest(request, responseCodeValidator); return response.getEntity().getContent(); } @@ -679,8 +697,8 @@ public class TestExecutor { // Insert and Delete statements are executed here public void executeUpdate(String str, URI uri) throws Exception { // Create a method instance. - HttpUriRequest request = - RequestBuilder.post(uri).setEntity(new StringEntity(str, StandardCharsets.UTF_8)).build(); + HttpUriRequest request = RequestBuilder.post(uri).setEntity(new StringEntity(str, StandardCharsets.UTF_8)) + .build(); // Execute the method. executeAndCheckHttpRequest(request); @@ -690,10 +708,10 @@ public class TestExecutor { public InputStream executeAnyAQLAsync(String statement, boolean defer, OutputFormat fmt, URI uri, Map<String, Object> variableCtx) throws Exception { // Create a method instance. - HttpUriRequest request = - RequestBuilder.post(uri).addParameter("mode", defer ? "asynchronous-deferred" : "asynchronous") - .setEntity(new StringEntity(statement, StandardCharsets.UTF_8)) - .setHeader("Accept", fmt.mimeType()).build(); + HttpUriRequest request = RequestBuilder.post(uri) + .addParameter("mode", defer ? "asynchronous-deferred" : "asynchronous") + .setEntity(new StringEntity(statement, StandardCharsets.UTF_8)).setHeader("Accept", fmt.mimeType()) + .build(); String handleVar = getHandleVariable(statement); @@ -719,8 +737,8 @@ public class TestExecutor { // create function statement public void executeDDL(String str, URI uri) throws Exception { // Create a method instance. - HttpUriRequest request = - RequestBuilder.post(uri).setEntity(new StringEntity(str, StandardCharsets.UTF_8)).build(); + HttpUriRequest request = RequestBuilder.post(uri).setEntity(new StringEntity(str, StandardCharsets.UTF_8)) + .build(); // Execute the method. executeAndCheckHttpRequest(request); @@ -730,8 +748,8 @@ public class TestExecutor { // and returns the contents as a string // This string is later passed to REST API for execution. public String readTestFile(File testFile) throws Exception { - BufferedReader reader = - new BufferedReader(new InputStreamReader(new FileInputStream(testFile), StandardCharsets.UTF_8)); + BufferedReader reader = new BufferedReader( + new InputStreamReader(new FileInputStream(testFile), StandardCharsets.UTF_8)); String line; StringBuilder stringBuilder = new StringBuilder(); String ls = System.getProperty("line.separator"); @@ -786,8 +804,8 @@ public class TestExecutor { private static String getProcessOutput(Process p) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - Future<Integer> future = - Executors.newSingleThreadExecutor().submit(() -> IOUtils.copy(p.getInputStream(), new OutputStream() { + Future<Integer> future = Executors.newSingleThreadExecutor() + .submit(() -> IOUtils.copy(p.getInputStream(), new OutputStream() { @Override public void write(int b) throws IOException { baos.write(b); @@ -966,6 +984,7 @@ public class TestExecutor { break; case "get": case "post": + case "put": expectedResultFile = (queryCount.intValue() >= expectedResultFileCtxs.size()) ? null : expectedResultFileCtxs.get(queryCount.intValue()).getFile(); actualResultFile = expectedResultFile == null ? null @@ -1071,11 +1090,12 @@ public class TestExecutor { String handleVar = getHandleVariable(statement); final String trimmedPathAndQuery = stripLineComments(stripJavaComments(statement)).trim(); final String variablesReplaced = replaceVarRef(trimmedPathAndQuery, variableCtx); + final List<Parameter> params = extractParameters(statement); InputStream resultStream; if ("http".equals(extension)) { - resultStream = executeHttp(reqType, variablesReplaced, fmt); + resultStream = executeHttp(reqType, variablesReplaced, fmt, params); } else if ("uri".equals(extension)) { - resultStream = executeURI(reqType, URI.create(variablesReplaced), fmt); + resultStream = executeURI(reqType, URI.create(variablesReplaced), fmt, params); } else { throw new IllegalArgumentException("Unexpected format for method " + reqType + ": " + extension); } @@ -1100,7 +1120,7 @@ public class TestExecutor { public void executeQuery(OutputFormat fmt, String statement, Map<String, Object> variableCtx, String reqType, File testFile, File expectedResultFile, File actualResultFile, MutableInt queryCount, int numResultFiles, - List<CompilationUnit.Parameter> params, ComparisonEnum compare) throws Exception { + List<Parameter> params, ComparisonEnum compare) throws Exception { InputStream resultStream = null; if (testFile.getName().endsWith("aql")) { if (reqType.equalsIgnoreCase("query")) { @@ -1158,7 +1178,7 @@ public class TestExecutor { long limitTime = startTime + TimeUnit.SECONDS.toMillis(timeoutSecs); ctx.setType(ctx.getType().substring("poll".length())); boolean expectedException = false; - Exception finalException; + Exception finalException = null; LOGGER.fine("polling for up to " + timeoutSecs + " seconds w/ " + retryDelaySecs + " second(s) delay"); int responsesReceived = 0; final ExecutorService executorService = Executors.newSingleThreadExecutor(); @@ -1177,11 +1197,16 @@ public class TestExecutor { if (responsesReceived == 0) { throw new Exception( "Poll limit (" + timeoutSecs + "s) exceeded without obtaining *any* result from server"); + } else if (finalException != null) { + throw new Exception("Poll limit (" + timeoutSecs + + "s) exceeded without obtaining expected result; last exception:", finalException); } else { throw new Exception("Poll limit (" + timeoutSecs + "s) exceeded without obtaining expected result"); } } catch (Exception e) { + LOGGER.log(Level.FINE, "received exception on poll", e); + responsesReceived++; if (isExpected(e, cUnit)) { expectedException = true; finalException = e; @@ -1250,21 +1275,27 @@ public class TestExecutor { return tmpStmt; } - protected InputStream executeHttp(String ctxType, String endpoint, OutputFormat fmt) throws Exception { + protected static List<Parameter> extractParameters(String statement) { + List<Parameter> params = new ArrayList<>(); + final Matcher m = HTTP_PARAM_PATTERN.matcher(statement); + while (m.find()) { + final Parameter param = new Parameter(); + param.setName(m.group(1)); + param.setValue(m.group(2)); + params.add(param); + } + return params; + } + + protected InputStream executeHttp(String ctxType, String endpoint, OutputFormat fmt, List<Parameter> params) + throws Exception { String[] split = endpoint.split("\\?"); URI uri = createEndpointURI(split[0], split.length > 1 ? split[1] : null); - return executeURI(ctxType, uri, fmt); + return executeURI(ctxType, uri, fmt, params); } - private InputStream executeURI(String ctxType, URI uri, OutputFormat fmt) throws Exception { - switch (ctxType) { - case "get": - return executeJSONGet(fmt, uri); - case "post": - return executeJSONPost(fmt, uri); - default: - throw new AssertionError("Not implemented: " + ctxType); - } + private InputStream executeURI(String ctxType, URI uri, OutputFormat fmt, List<Parameter> params) throws Exception { + return executeJSON(fmt, ctxType.toUpperCase(), uri, params); } private void killNC(String nodeId, CompilationUnit cUnit) throws Exception { http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOption.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOption.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOption.java index 834d73c..b8e7635 100644 --- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOption.java +++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOption.java @@ -20,6 +20,9 @@ package org.apache.hyracks.api.config; import java.util.function.Function; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.text.WordUtils; + public interface IOption { String name(); @@ -64,6 +67,10 @@ public interface IOption { return name().toLowerCase().replace("_", "."); } + default String json() { + return StringUtils.remove(WordUtils.capitalize("z" + name().toLowerCase(), '_').substring(1), '_'); + } + default String toIniString() { return "[" + section().sectionName() + "] " + ini(); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOptionType.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOptionType.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOptionType.java index 1bd6097..d2a254f 100644 --- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOptionType.java +++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOptionType.java @@ -18,6 +18,8 @@ */ package org.apache.hyracks.api.config; +import com.fasterxml.jackson.databind.node.ObjectNode; + public interface IOptionType<T> { /** * @throws IllegalArgumentException when the supplied string cannot be interpreted @@ -34,6 +36,11 @@ public interface IOptionType<T> { } /** + * @return the value in a format suitable for serialized JSON + */ + void serializeJSONField(String fieldName, Object value, ObjectNode node); + + /** * @return the value in a format suitable for serialized ini file */ default String serializeToIni(Object value) { http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/pom.xml ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/pom.xml b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/pom.xml index 5120047..80ef088 100644 --- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/pom.xml +++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/pom.xml @@ -75,5 +75,9 @@ <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> </dependencies> </project> http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/ConfigManager.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/ConfigManager.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/ConfigManager.java index fcaee6d..a595301 100644 --- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/ConfigManager.java +++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/ConfigManager.java @@ -425,7 +425,7 @@ public class ConfigManager implements IConfigManager, Serializable { } public List<String> getNodeNames() { - return Collections.unmodifiableList(new ArrayList(nodeSpecificMap.keySet())); + return Collections.unmodifiableList(new ArrayList<>(nodeSpecificMap.keySet())); } public IApplicationConfig getNodeEffectiveConfig(String nodeId) { http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java index 02b9325..1e92a7a 100644 --- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java +++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java @@ -21,14 +21,20 @@ package org.apache.hyracks.control.common.config; import java.net.MalformedURLException; import java.util.logging.Level; +import org.apache.commons.lang3.StringUtils; import org.apache.hyracks.api.config.IOptionType; import org.apache.hyracks.util.StorageUtil; +import com.fasterxml.jackson.databind.node.ObjectNode; + public class OptionTypes { public static final IOptionType<Integer> INTEGER_BYTE_UNIT = new IOptionType<Integer>() { @Override public Integer parse(String s) { + if (s == null) { + return null; + } long result1 = StorageUtil.getByteValue(s); if (result1 > Integer.MAX_VALUE || result1 < Integer.MIN_VALUE) { throw new IllegalArgumentException( @@ -46,12 +52,17 @@ public class OptionTypes { public String serializeToHumanReadable(Object value) { return value + " (" + StorageUtil.toHumanReadableSize((int)value) + ")"; } + + @Override + public void serializeJSONField(String fieldName, Object value, ObjectNode node) { + node.put(fieldName, (int)value); + } }; public static final IOptionType<Long> LONG_BYTE_UNIT = new IOptionType<Long>() { @Override public Long parse(String s) { - return StorageUtil.getByteValue(s); + return s == null ? null : StorageUtil.getByteValue(s); } @Override @@ -63,6 +74,11 @@ public class OptionTypes { public String serializeToHumanReadable(Object value) { return value + " (" + StorageUtil.toHumanReadableSize((long)value) + ")"; } + + @Override + public void serializeJSONField(String fieldName, Object value, ObjectNode node) { + node.put(fieldName, (long)value); + } }; public static final IOptionType<Integer> INTEGER = new IOptionType<Integer>() { @@ -75,6 +91,11 @@ public class OptionTypes { public Class<Integer> targetType() { return Integer.class; } + + @Override + public void serializeJSONField(String fieldName, Object value, ObjectNode node) { + node.put(fieldName, (int)value); + } }; public static final IOptionType<Double> DOUBLE = new IOptionType<Double>() { @@ -87,6 +108,11 @@ public class OptionTypes { public Class<Double> targetType() { return Double.class; } + + @Override + public void serializeJSONField(String fieldName, Object value, ObjectNode node) { + node.put(fieldName, (double)value); + } }; public static final IOptionType<String> STRING = new IOptionType<String>() { @@ -99,6 +125,11 @@ public class OptionTypes { public Class<String> targetType() { return String.class; } + + @Override + public void serializeJSONField(String fieldName, Object value, ObjectNode node) { + node.put(fieldName, (String)value); + } }; public static final IOptionType<Long> LONG = new IOptionType<Long>() { @@ -111,6 +142,11 @@ public class OptionTypes { public Class<Long> targetType() { return Long.class; } + + @Override + public void serializeJSONField(String fieldName, Object value, ObjectNode node) { + node.put(fieldName, (long)value); + } }; public static final IOptionType<Boolean> BOOLEAN = new IOptionType<Boolean>() { @@ -123,12 +159,17 @@ public class OptionTypes { public Class<Boolean> targetType() { return Boolean.class; } + + @Override + public void serializeJSONField(String fieldName, Object value, ObjectNode node) { + node.put(fieldName, (boolean)value); + } }; public static final IOptionType<Level> LEVEL = new IOptionType<Level>() { @Override public Level parse(String s) { - return Level.parse(s); + return s == null ? null : Level.parse(s); } @Override @@ -137,20 +178,25 @@ public class OptionTypes { } @Override - public Object serializeToJSON(Object value) { - return ((Level)value).getName(); + public String serializeToJSON(Object value) { + return value == null ? null : ((Level)value).getName(); } @Override public String serializeToIni(Object value) { return ((Level)value).getName(); } + + @Override + public void serializeJSONField(String fieldName, Object value, ObjectNode node) { + node.put(fieldName, serializeToJSON(value)); + } }; public static final IOptionType<String []> STRING_ARRAY = new IOptionType<String []>() { @Override public String [] parse(String s) { - return s.split("\\s*,\\s*"); + return s == null ? null : s.split("\\s*,\\s*"); } @Override @@ -162,13 +208,18 @@ public class OptionTypes { public String serializeToIni(Object value) { return String.join(",", (String [])value); } + + @Override + public void serializeJSONField(String fieldName, Object value, ObjectNode node) { + node.put(fieldName, value == null ? null : StringUtils.join((String [])value, ',')); + } }; public static final IOptionType<java.net.URL> URL = new IOptionType<java.net.URL>() { @Override public java.net.URL parse(String s) { try { - return new java.net.URL(s); + return s == null ? null : new java.net.URL(s); } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } @@ -178,8 +229,12 @@ public class OptionTypes { public Class<java.net.URL> targetType() { return java.net.URL.class; } - }; + @Override + public void serializeJSONField(String fieldName, Object value, ObjectNode node) { + node.put(fieldName, value == null ? null : String.valueOf(value)); + } + }; private OptionTypes() { } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java index 610c3d1..be201df 100644 --- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java +++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java @@ -18,6 +18,9 @@ */ package org.apache.hyracks.http.api; +import java.util.Map; +import java.util.Set; + import io.netty.handler.codec.http.FullHttpRequest; /** @@ -38,6 +41,20 @@ public interface IServletRequest { String getParameter(CharSequence name); /** + * Get the names of all request parameters + * + * @return the list of parameter names + */ + Set<String> getParameterNames(); + + /** + * Get the all request parameters + * + * @return the parameters + */ + Map<String, String> getParameters(); + + /** * Get a request header * * @param name http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java index 5b354af..0c633cf 100644 --- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java +++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java @@ -19,8 +19,11 @@ package org.apache.hyracks.http.server; import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.hyracks.http.api.IServletRequest; import org.apache.hyracks.http.server.utils.HttpUtil; @@ -54,6 +57,21 @@ public class BaseRequest implements IServletRequest { } @Override + public Set<String> getParameterNames() { + return Collections.unmodifiableSet(parameters.keySet()); + } + + @Override + public Map<String, String> getParameters() { + HashMap<String, String> paramMap = new HashMap<>(); + for (String name : parameters.keySet()) { + paramMap.put(name, HttpUtil.getParameter(parameters, name)); + + } + return Collections.unmodifiableMap(paramMap); + } + + @Override public String getHeader(CharSequence name) { return request.headers().get(name); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java new file mode 100644 index 0000000..743a2c4 --- /dev/null +++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java @@ -0,0 +1,99 @@ +/* + * 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.server; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.hyracks.http.api.IServletRequest; +import org.apache.hyracks.http.server.utils.HttpUtil; + +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.QueryStringDecoder; +import io.netty.handler.codec.http.multipart.Attribute; +import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; +import io.netty.handler.codec.http.multipart.InterfaceHttpData; +import io.netty.handler.codec.http.multipart.MixedAttribute; + +public class FormUrlEncodedRequest extends BaseRequest implements IServletRequest { + + private final List<String> names; + private final List<String> values; + + public static IServletRequest create(FullHttpRequest request) throws IOException { + List<String> names = new ArrayList<>(); + List<String> values = new ArrayList<>(); + HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(request); + try { + List<InterfaceHttpData> bodyHttpDatas = decoder.getBodyHttpDatas(); + for (InterfaceHttpData data : bodyHttpDatas) { + if (data.getHttpDataType().equals(InterfaceHttpData.HttpDataType.Attribute)) { + Attribute attr = (MixedAttribute) data; + names.add(data.getName()); + values.add(attr.getValue()); + } + } + } finally { + decoder.destroy(); + } + return new FormUrlEncodedRequest(request, new QueryStringDecoder(request.uri()).parameters(), names, values); + } + + protected FormUrlEncodedRequest(FullHttpRequest request, Map<String, List<String>> parameters, List<String> names, + List<String> values) { + super(request, parameters); + this.names = names; + this.values = values; + } + + @Override + public String getParameter(CharSequence name) { + for (int i = 0; i < names.size(); i++) { + if (name.equals(names.get(i))) { + return values.get(i); + } + } + return HttpUtil.getParameter(parameters, name); + } + + @Override + public Set<String> getParameterNames() { + HashSet<String> paramNames = new HashSet<>(); + paramNames.addAll(parameters.keySet()); + paramNames.addAll(names); + return Collections.unmodifiableSet(paramNames); + } + + @Override + public Map<String, String> getParameters() { + HashMap<String, String> paramMap = new HashMap<>(); + paramMap.putAll(super.getParameters()); + for (int i = 0; i < names.size(); i++) { + paramMap.put(names.get(i), values.get(i)); + } + + return Collections.unmodifiableMap(paramMap); + } +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/PostRequest.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/PostRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/PostRequest.java deleted file mode 100644 index 1dcb088..0000000 --- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/PostRequest.java +++ /dev/null @@ -1,89 +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.server; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.apache.hyracks.http.api.IServletRequest; -import org.apache.hyracks.http.server.utils.HttpUtil; - -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.QueryStringDecoder; -import io.netty.handler.codec.http.multipart.Attribute; -import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; -import io.netty.handler.codec.http.multipart.InterfaceHttpData; -import io.netty.handler.codec.http.multipart.MixedAttribute; - -public class PostRequest extends BaseRequest implements IServletRequest { - - private static final Logger LOGGER = Logger.getLogger(PostRequest.class.getName()); - - private final List<String> names; - private final List<String> values; - - public static IServletRequest create(FullHttpRequest request) throws IOException { - List<String> names = new ArrayList<>(); - List<String> values = new ArrayList<>(); - HttpPostRequestDecoder decoder = null; - try { - decoder = new HttpPostRequestDecoder(request); - } catch (Exception e) { - //ignore. this means that the body of the POST request does not have key value pairs - LOGGER.log(Level.WARNING, "Failed to decode a post message. Fix the API not to have queries as POST body", - e); - } - if (decoder != null) { - try { - List<InterfaceHttpData> bodyHttpDatas = decoder.getBodyHttpDatas(); - for (InterfaceHttpData data : bodyHttpDatas) { - if (data.getHttpDataType().equals(InterfaceHttpData.HttpDataType.Attribute)) { - Attribute attr = (MixedAttribute) data; - names.add(data.getName()); - values.add(attr.getValue()); - } - } - } finally { - decoder.destroy(); - } - } - return new PostRequest(request, new QueryStringDecoder(request.uri()).parameters(), names, values); - } - - protected PostRequest(FullHttpRequest request, Map<String, List<String>> parameters, List<String> names, - List<String> values) { - super(request, parameters); - this.names = names; - this.values = values; - } - - @Override - public String getParameter(CharSequence name) { - for (int i = 0; i < names.size(); i++) { - if (name.equals(names.get(i))) { - return values.get(i); - } - } - return HttpUtil.getParameter(parameters, name); - } -} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a14cebbf/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java index c11deef..2babc73 100644 --- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java +++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java @@ -26,11 +26,11 @@ import java.util.Map; import org.apache.hyracks.http.api.IServletRequest; import org.apache.hyracks.http.api.IServletResponse; import org.apache.hyracks.http.server.BaseRequest; -import org.apache.hyracks.http.server.PostRequest; +import org.apache.hyracks.http.server.FormUrlEncodedRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaderNames; -import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; public class HttpUtil { @@ -47,6 +47,7 @@ public class HttpUtil { public static class ContentType { public static final String APPLICATION_ADM = "application/x-adm"; public static final String APPLICATION_JSON = "application/json"; + public static final String APPLICATION_X_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded"; public static final String CSV = "text/csv"; public static final String IMG_PNG = "image/png"; public static final String TEXT_HTML = "text/html"; @@ -57,7 +58,7 @@ public class HttpUtil { } public static String getParameter(Map<String, List<String>> parameters, CharSequence name) { - List<String> parameter = parameters.get(name); + List<String> parameter = parameters.get(String.valueOf(name)); if (parameter == null) { return null; } else if (parameter.size() == 1) { @@ -72,7 +73,17 @@ public class HttpUtil { } public static IServletRequest toServletRequest(FullHttpRequest request) throws IOException { - return request.method() == HttpMethod.POST ? PostRequest.create(request) : BaseRequest.create(request); + return ContentType.APPLICATION_X_WWW_FORM_URLENCODED.equals(getContentTypeOnly(request)) + ? FormUrlEncodedRequest.create(request) : BaseRequest.create(request); + } + + public static String getContentTypeOnly(IServletRequest request) { + return getContentTypeOnly(request.getHttpRequest()); + } + + public static String getContentTypeOnly(HttpRequest request) { + String contentType = request.headers().get(HttpHeaderNames.CONTENT_TYPE); + return contentType == null ? null : contentType.split(";")[0]; } public static String getRequestBody(IServletRequest request) {
