You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2015/07/07 19:58:36 UTC
[5/5] incubator-calcite git commit: [CALCITE-780] HTTP error 413 when
sending a long string to the Avatica server
[CALCITE-780] HTTP error 413 when sending a long string to the Avatica server
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/03111d2b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/03111d2b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/03111d2b
Branch: refs/heads/master
Commit: 03111d2b680c4f4eb4886d60cab9beebd1c7bdcb
Parents: 40c55fd
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Jul 7 00:20:48 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jul 7 00:20:48 2015 -0700
----------------------------------------------------------------------
.../calcite/avatica/server/AvaticaHandler.java | 13 ++++-
.../calcite/avatica/remote/RemoteMetaTest.java | 51 +++++++++++++++++++-
.../apache/calcite/avatica/AvaticaUtils.java | 17 +++++++
.../calcite/avatica/remote/RemoteService.java | 28 ++++++-----
4 files changed, 94 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
index fa0e1ac..2ada444 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
@@ -16,6 +16,7 @@
*/
package org.apache.calcite.avatica.server;
+import org.apache.calcite.avatica.AvaticaUtils;
import org.apache.calcite.avatica.remote.JsonHandler;
import org.apache.calcite.avatica.remote.Service;
@@ -27,6 +28,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
import java.io.IOException;
import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -48,9 +50,16 @@ public class AvaticaHandler extends AbstractHandler {
response.setContentType("application/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
if (request.getMethod().equals("POST")) {
+ // First look for a request in the header, then look in the body.
+ // The latter allows very large requests without hitting HTTP 413.
+ String rawRequest = request.getHeader("request");
+ if (rawRequest == null) {
+ try (ServletInputStream inputStream = request.getInputStream()) {
+ rawRequest = AvaticaUtils.readFully(inputStream);
+ }
+ }
final String jsonRequest =
- new String(request.getHeader("request").getBytes("ISO-8859-1"),
- "UTF-8");
+ new String(rawRequest.getBytes("ISO-8859-1"), "UTF-8");
if (LOG.isTraceEnabled()) {
LOG.trace("request: " + jsonRequest);
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
index 2439ac3..27dcfa4 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
@@ -41,8 +41,10 @@ import java.sql.Statement;
import java.util.List;
import java.util.Map;
+import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/** Tests covering {@link RemoteMeta}. */
@@ -98,7 +100,7 @@ public class RemoteMetaTest {
Method m = AvaticaConnection.class.getDeclaredMethod("prepareAndExecuteInternal",
AvaticaStatement.class, String.class, int.class);
m.setAccessible(true);
- return (Meta.ExecuteResult) m.invoke(conn, statement, sql, new Integer(maxRowCount));
+ return (Meta.ExecuteResult) m.invoke(conn, statement, sql, maxRowCount);
}
private static Connection getConnection(JdbcMeta m, String id) throws Exception {
@@ -128,6 +130,53 @@ public class RemoteMetaTest {
}
}
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-780">[CALCITE-780]
+ * HTTP error 413 when sending a long string to the Avatica server</a>. */
+ @Test public void testRemoteExecuteVeryLargeQuery() throws Exception {
+ // Before the bug was fixed, a value over 7998 caused an HTTP 413.
+ // 16K bytes, I guess.
+ checkLargeQuery(8);
+ checkLargeQuery(240);
+ checkLargeQuery(8000);
+ checkLargeQuery(240000);
+ }
+
+ private void checkLargeQuery(int n) throws Exception {
+ try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
+ final AvaticaStatement statement = conn.createStatement();
+ final String frenchDisko = "It said human existence is pointless\n"
+ + "As acts of rebellious solidarity\n"
+ + "Can bring sense in this world\n"
+ + "La resistance!\n";
+ final String sql = "select '"
+ + longString(frenchDisko, n)
+ + "' as s from (values 'x')";
+ prepareAndExecuteInternal(conn, statement, sql, -1);
+ ResultSet rs = statement.getResultSet();
+ int count = 0;
+ while (rs.next()) {
+ count++;
+ }
+ assertThat(count, is(1));
+ rs.close();
+ statement.close();
+ conn.close();
+ }
+ }
+
+ /** Creates a string of exactly {@code length} characters by concatenating
+ * {@code fragment}. */
+ private static String longString(String fragment, int length) {
+ assert fragment.length() > 0;
+ final StringBuilder buf = new StringBuilder();
+ while (buf.length() < length) {
+ buf.append(fragment);
+ }
+ buf.setLength(length);
+ return buf.toString();
+ }
+
@Test public void testRemoteConnectionProperties() throws Exception {
try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
String id = conn.id;
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
index 5ca5245..0ee030d 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
@@ -16,6 +16,9 @@
*/
package org.apache.calcite.avatica;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.AbstractList;
import java.util.HashMap;
@@ -165,6 +168,20 @@ public class AvaticaUtils {
+ "' not valid for plugin type " + pluginClass.getName(), e);
}
}
+
+ /** Reads the contents of an input stream and returns as a string. */
+ public static String readFully(InputStream inputStream) throws IOException {
+ final byte[] bytes = new byte[4096];
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ for (;;) {
+ int count = inputStream.read(bytes, 0, bytes.length);
+ if (count < 0) {
+ break;
+ }
+ baos.write(bytes, 0, count);
+ }
+ return baos.toString();
+ }
}
// End AvaticaUtils.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
index 7cbdcf0..a5896f2 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
@@ -16,7 +16,9 @@
*/
package org.apache.calcite.avatica.remote;
-import java.io.ByteArrayOutputStream;
+import org.apache.calcite.avatica.AvaticaUtils;
+
+import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
@@ -39,22 +41,24 @@ public class RemoteService extends JsonService {
final HttpURLConnection connection =
(HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
- connection.setRequestProperty("request", request);
+ connection.setDoInput(true);
+ connection.setDoOutput(true);
+ if (request.length() < 256) {
+ connection.setRequestProperty("request", request);
+ } else {
+ try (DataOutputStream wr
+ = new DataOutputStream(connection.getOutputStream())) {
+ wr.writeBytes(request);
+ wr.flush();
+ wr.close();
+ }
+ }
final int responseCode = connection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
throw new RuntimeException("response code " + responseCode);
}
final InputStream inputStream = connection.getInputStream();
- final byte[] bytes = new byte[4096];
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- for (;;) {
- int count = inputStream.read(bytes, 0, bytes.length);
- if (count < 0) {
- break;
- }
- baos.write(bytes, 0, count);
- }
- return baos.toString();
+ return AvaticaUtils.readFully(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}