asterixdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From amo...@apache.org
Subject [1/2] asterixdb git commit: Use Chunked Http Response
Date Thu, 02 Feb 2017 00:28:26 GMT
Repository: asterixdb
Updated Branches:
  refs/heads/master c7a8fa5cd -> 088991c51


http://git-wip-us.apache.org/repos/asf/asterixdb/blob/088991c5/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 f7f55bd..302e5f3 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
@@ -23,12 +23,19 @@ import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import org.apache.hyracks.http.api.IServlet;
+
 import io.netty.bootstrap.ServerBootstrap;
 import io.netty.channel.Channel;
+import io.netty.channel.ChannelOption;
 import io.netty.channel.EventLoopGroup;
+import io.netty.channel.WriteBufferWaterMark;
 import io.netty.channel.socket.nio.NioServerSocketChannel;
 import io.netty.handler.codec.http.FullHttpRequest;
 import io.netty.handler.logging.LogLevel;
@@ -36,6 +43,8 @@ import io.netty.handler.logging.LoggingHandler;
 
 public class HttpServer {
     // Constants
+    private static final int LOW_WRITE_BUFFER_WATER_MARK = 8 * 1024;
+    private static final int HIGH_WRITE_BUFFER_WATER_MARK = 32 * 1024;
     private static final Logger LOGGER = Logger.getLogger(HttpServer.class.getName());
     private static final int FAILED = -1;
     private static final int STOPPED = 0;
@@ -44,23 +53,26 @@ public class HttpServer {
     private static final int STOPPING = 3;
     // Final members
     private final Object lock = new Object();
+    private final AtomicInteger threadId = new AtomicInteger();
     private final ConcurrentMap<String, Object> ctx;
     private final List<IServlet> lets;
     private final EventLoopGroup bossGroup;
     private final EventLoopGroup workerGroup;
     private final int port;
+    private final ExecutorService executor;
     // Mutable members
     private volatile int state = STOPPED;
     private Channel channel;
     private Throwable cause;
 
-    public HttpServer(EventLoopGroup bossGroup, EventLoopGroup workerGroup,
-            int port) {
+    public HttpServer(EventLoopGroup bossGroup, EventLoopGroup workerGroup, int port) {
         this.bossGroup = bossGroup;
         this.workerGroup = workerGroup;
         this.port = port;
         ctx = new ConcurrentHashMap<>();
         lets = new ArrayList<>();
+        executor = Executors.newFixedThreadPool(16,
+                runnable -> new Thread(runnable, "HttpExecutor(port:" + port + ")-" +
threadId.getAndIncrement()));
     }
 
     public final void start() throws Exception { // NOSONAR
@@ -158,7 +170,6 @@ public class HttpServer {
         lets.add(let);
     }
 
-
     protected void doStart() throws InterruptedException {
         /*
          * This is a hacky way to ensure that ILets with more specific paths are checked
first.
@@ -172,14 +183,13 @@ public class HttpServer {
          */
         Collections.sort(lets, (l1, l2) -> l2.getPaths()[0].length() - l1.getPaths()[0].length());
         ServerBootstrap b = new ServerBootstrap();
-        b.group(bossGroup, workerGroup)
-                .channel(NioServerSocketChannel.class)
-                .handler(new LoggingHandler(LogLevel.INFO))
-                .childHandler(new HttpServerInitializer(this));
+        b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
+                .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK,
+                        new WriteBufferWaterMark(LOW_WRITE_BUFFER_WATER_MARK, HIGH_WRITE_BUFFER_WATER_MARK))
+                .handler(new LoggingHandler(LogLevel.INFO)).childHandler(new HttpServerInitializer(this));
         channel = b.bind(port).sync().channel();
     }
 
-
     protected void doStop() throws InterruptedException {
         channel.close();
         channel.closeFuture().sync();
@@ -212,14 +222,18 @@ public class HttpServer {
                 return true;
             }
         } else if (c == '*') {
-            return path.regionMatches(path.length() - pathSpec.length() + 1,
-                    pathSpec, 1, pathSpec.length() - 1);
+            return path.regionMatches(path.length() - pathSpec.length() + 1, pathSpec, 1,
pathSpec.length() - 1);
         }
         return false;
     }
+
     private static boolean isPathWildcardMatch(String pathSpec, String path) {
         int cpl = pathSpec.length() - 2;
         return (pathSpec.endsWith("/*") && path.regionMatches(0, pathSpec, 0, cpl))
                 && (path.length() == cpl || '/' == path.charAt(cpl));
     }
+
+    public ExecutorService getExecutor() {
+        return executor;
+    }
 }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/088991c5/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
index c8ed937..2268c2c 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
@@ -18,13 +18,12 @@
  */
 package org.apache.hyracks.http.server;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import io.netty.channel.ChannelFuture;
+import org.apache.hyracks.http.api.IServlet;
+import org.apache.hyracks.http.server.util.ServletUtils;
+
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.SimpleChannelInboundHandler;
@@ -32,21 +31,17 @@ import io.netty.handler.codec.http.DefaultHttpResponse;
 import io.netty.handler.codec.http.FullHttpRequest;
 import io.netty.handler.codec.http.HttpMethod;
 import io.netty.handler.codec.http.HttpResponseStatus;
-import io.netty.handler.codec.http.HttpUtil;
-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.InterfaceHttpData.HttpDataType;
-import io.netty.handler.codec.http.multipart.MixedAttribute;
 
 public class HttpServerHandler extends SimpleChannelInboundHandler<Object> {
 
     private static final Logger LOGGER = Logger.getLogger(HttpServerHandler.class.getName());
     protected final HttpServer server;
+    protected final int chunkSize;
+    protected HttpRequestHandler handler;
 
-    public HttpServerHandler(HttpServer server) {
+    public HttpServerHandler(HttpServer server, int chunkSize) {
         this.server = server;
+        this.chunkSize = chunkSize;
     }
 
     @Override
@@ -55,35 +50,29 @@ public class HttpServerHandler extends SimpleChannelInboundHandler<Object>
{
     }
 
     @Override
+    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
+        if (ctx.channel().isWritable()) {
+            handler.notifyChannelWritable();
+        }
+        super.channelWritabilityChanged(ctx);
+    }
+
+    @Override
     protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
         try {
-            FullHttpRequest http = (FullHttpRequest) msg;
-            IServlet servlet = server.getServlet(http);
+            FullHttpRequest request = (FullHttpRequest) msg;
+            IServlet servlet = server.getServlet(request);
             if (servlet == null) {
-                DefaultHttpResponse response = new DefaultHttpResponse(http.protocolVersion(),
-                        HttpResponseStatus.NOT_FOUND);
-                ctx.write(response).addListener(ChannelFutureListener.CLOSE);
+                DefaultHttpResponse notFound =
+                        new DefaultHttpResponse(request.protocolVersion(), HttpResponseStatus.NOT_FOUND);
+                ctx.write(notFound).addListener(ChannelFutureListener.CLOSE);
+            } else if (request.method() != HttpMethod.GET && request.method() !=
HttpMethod.POST) {
+                DefaultHttpResponse notAllowed =
+                        new DefaultHttpResponse(request.protocolVersion(), HttpResponseStatus.METHOD_NOT_ALLOWED);
+                ctx.write(notAllowed).addListener(ChannelFutureListener.CLOSE);
             } else {
-                if (http.method() != HttpMethod.GET && http.method() != HttpMethod.POST)
{
-                    DefaultHttpResponse response = new DefaultHttpResponse(http.protocolVersion(),
-                            HttpResponseStatus.METHOD_NOT_ALLOWED);
-                    ctx.write(response).addListener(ChannelFutureListener.CLOSE);
-                    return;
-                }
-                IServletRequest request = http.method() == HttpMethod.GET ? get(http) : post(http);
-                IServletResponse response = new FullResponse(ctx, http);
-                try {
-                    servlet.handle(request, response);
-                } catch (Throwable th) { // NOSONAR
-                    LOGGER.log(Level.WARNING, "Failure during handling of an IServLetRequest",
th);
-                    response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
-                } finally {
-                    response.close();
-                }
-                ChannelFuture lastContentFuture = response.future();
-                if (!HttpUtil.isKeepAlive(http)) {
-                    lastContentFuture.addListener(ChannelFutureListener.CLOSE);
-                }
+                handler = new HttpRequestHandler(ctx, servlet, ServletUtils.toServletRequest(request),
chunkSize);
+                server.getExecutor().submit(handler);
             }
         } catch (Exception e) {
             LOGGER.log(Level.SEVERE, "Failure handling HTTP Request", e);
@@ -91,38 +80,6 @@ public class HttpServerHandler extends SimpleChannelInboundHandler<Object>
{
         }
     }
 
-    public static IServletRequest post(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(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);
-    }
-
-    public static IServletRequest get(FullHttpRequest request) throws IOException {
-        return new GetRequest(request, new QueryStringDecoder(request.uri()).parameters());
-    }
-
     @Override
     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
         LOGGER.log(Level.SEVERE, "Failure handling HTTP Request", cause);

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/088991c5/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
index 3b32ee6..bc67865 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
@@ -27,9 +27,10 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
 
 public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
 
-    private static final int MAX_CHUNK_SIZE = 262144;
-    private static final int MAX_HEADER_SIZE = 262144;
-    private static final int MAX_INITIAL_LINE_LENGTH = 131072;
+    private static final int MAX_REQUEST_CHUNK_SIZE = 262144;
+    private static final int MAX_REQUEST_HEADER_SIZE = 262144;
+    private static final int MAX_REQUEST_INITIAL_LINE_LENGTH = 131072;
+    private static final int RESPONSE_CHUNK_SIZE = 4096;
     private HttpServer server;
 
     public HttpServerInitializer(HttpServer server) {
@@ -39,9 +40,10 @@ public class HttpServerInitializer extends ChannelInitializer<SocketChannel>
{
     @Override
     public void initChannel(SocketChannel ch) {
         ChannelPipeline p = ch.pipeline();
-        p.addLast(new HttpRequestDecoder(MAX_INITIAL_LINE_LENGTH, MAX_HEADER_SIZE, MAX_CHUNK_SIZE));
+        p.addLast(new HttpRequestDecoder(MAX_REQUEST_INITIAL_LINE_LENGTH, MAX_REQUEST_HEADER_SIZE,
+                MAX_REQUEST_CHUNK_SIZE));
         p.addLast(new HttpResponseEncoder());
         p.addLast(new HttpObjectAggregator(Integer.MAX_VALUE));
-        p.addLast(new HttpServerHandler(server));
+        p.addLast(new HttpServerHandler(server, RESPONSE_CHUNK_SIZE));
     }
 }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/088991c5/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServlet.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServlet.java
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServlet.java
deleted file mode 100644
index 5691fd9..0000000
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServlet.java
+++ /dev/null
@@ -1,92 +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.util.concurrent.ConcurrentMap;
-
-/**
- * Represents a component that handles IServLet requests
- */
-public interface IServlet {
-
-    public class Encoding {
-        public static final String UTF8 = "utf-8";
-
-        private Encoding() {
-        }
-    }
-
-    public class ContentType {
-        public static final String APPLICATION_ADM = "application/x-adm";
-        public static final String APPLICATION_JSON = "application/json";
-        public static final String CSV = "text/csv";
-        public static final String IMG_PNG = "image/png";
-        public static final String TEXT_HTML = "text/html";
-        public static final String TEXT_PLAIN = "text/plain";
-
-        private ContentType() {
-        }
-
-        /**
-         * Get the mime string representation from the extension
-         * @param extension
-         * @return
-         */
-        public static String mime(String extension) {
-            switch (extension) {
-                case ".png":
-                    return "image/png";
-                case ".eot":
-                    return "application/vnd.ms-fontobject";
-                case ".svg":
-                    return "image/svg+xml\t";
-                case ".ttf":
-                    return "application/x-font-ttf";
-                case ".woff":
-                case ".woff2":
-                    return "application/x-font-woff";
-                case ".html":
-                    return "text/html";
-                case ".css":
-                    return "text/css";
-                case ".js":
-                    return "application/javascript";
-                default:
-                    return null;
-            }
-        }
-    }
-
-    /**
-     * @return an array of paths associated with this IServLet
-     */
-    String[] getPaths();
-
-    /**
-     * @return the context associated with this IServlet
-     */
-    ConcurrentMap<String, Object> ctx();
-
-    /**
-     * handle the IServLetRequest writing the response in the passed IServLetResponse
-     * @param request
-     * @param response
-     */
-    void handle(IServletRequest request, IServletResponse response);
-}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/088991c5/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletRequest.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletRequest.java
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletRequest.java
deleted file mode 100644
index 8aebd07..0000000
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletRequest.java
+++ /dev/null
@@ -1,63 +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.util.List;
-import java.util.Map;
-
-import io.netty.handler.codec.http.FullHttpRequest;
-
-/**
- * An Http Request instance
- */
-public interface IServletRequest {
-    /**
-     * @return the full http request
-     */
-    FullHttpRequest getHttpRequest();
-
-    /**
-     * Get a request parameter
-     * @param name
-     * @return the parameter or null if not found
-     */
-    String getParameter(CharSequence name);
-
-    /**
-     * Get a request header
-     * @param name
-     * @return the header or null if not found
-     */
-    String getHeader(CharSequence name);
-
-    static String getParameter(Map<String, List<String>> parameters, CharSequence
name) {
-        List<String> parameter = parameters.get(name);
-        if (parameter == null) {
-            return null;
-        } else if (parameter.size() == 1) {
-            return parameter.get(0);
-        } else {
-            StringBuilder aString = new StringBuilder(parameter.get(0));
-            for (int i = 1; i < parameter.size(); i++) {
-                aString.append(",").append(parameter.get(i));
-            }
-            return aString.toString();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/088991c5/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletResponse.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletResponse.java
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletResponse.java
deleted file mode 100644
index 342e643..0000000
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletResponse.java
+++ /dev/null
@@ -1,77 +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.Closeable;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-
-import io.netty.channel.ChannelFuture;
-import io.netty.handler.codec.http.HttpHeaderNames;
-import io.netty.handler.codec.http.HttpResponseStatus;
-
-/**
- * A response to an instance of IServLetRequest
- */
-public interface IServletResponse extends Closeable {
-
-    /**
-     * Set a response header
-     * @param name
-     * @param value
-     * @return
-     * @throws Exception
-     */
-    IServletResponse setHeader(CharSequence name, Object value) throws IOException;
-
-    /**
-     * Get the output writer for the response
-     * @return
-     * @throws Exception
-     */
-    PrintWriter writer();
-
-    /**
-     * Send the last http response if any and return the future
-     * @return
-     * @throws Exception
-     */
-    ChannelFuture future() throws IOException;
-
-    /**
-     * Set the status of the http response
-     * @param status
-     */
-    void setStatus(HttpResponseStatus status);
-
-    /**
-     * Get the output stream for the response
-     * @return
-     */
-    OutputStream outputStream();
-
-    public static void setContentType(IServletResponse response, String type, String charset)
throws IOException {
-        response.setHeader(HttpHeaderNames.CONTENT_TYPE, type + "; charset=" + charset);
-    }
-
-    public static void setContentType(IServletResponse response, String type) throws IOException
{
-        response.setHeader(HttpHeaderNames.CONTENT_TYPE, type);
-    }
-}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/088991c5/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
index 99f338c..338ef40 100644
--- 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
@@ -21,6 +21,9 @@ package org.apache.hyracks.http.server;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.hyracks.http.api.IServletRequest;
+import org.apache.hyracks.http.server.util.ServletUtils;
+
 import io.netty.handler.codec.http.FullHttpRequest;
 
 public class PostRequest implements IServletRequest {
@@ -49,7 +52,7 @@ public class PostRequest implements IServletRequest {
                 return values.get(i);
             }
         }
-        return IServletRequest.getParameter(parameters, name);
+        return ServletUtils.getParameter(parameters, name);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/088991c5/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/util/ServletUtils.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/util/ServletUtils.java
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/util/ServletUtils.java
new file mode 100644
index 0000000..1ffab6d
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/util/ServletUtils.java
@@ -0,0 +1,107 @@
+/*
+ * 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.util;
+
+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.api.IServletResponse;
+import org.apache.hyracks.http.server.GetRequest;
+import org.apache.hyracks.http.server.PostRequest;
+
+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.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.InterfaceHttpData.HttpDataType;
+import io.netty.handler.codec.http.multipart.MixedAttribute;
+
+public class ServletUtils {
+    private static final Logger LOGGER = Logger.getLogger(ServletUtils.class.getName());
+
+    private ServletUtils() {
+    }
+
+    public static String getParameter(Map<String, List<String>> parameters, CharSequence
name) {
+        List<String> parameter = parameters.get(name);
+        if (parameter == null) {
+            return null;
+        } else if (parameter.size() == 1) {
+            return parameter.get(0);
+        } else {
+            StringBuilder aString = new StringBuilder(parameter.get(0));
+            for (int i = 1; i < parameter.size(); i++) {
+                aString.append(",").append(parameter.get(i));
+            }
+            return aString.toString();
+        }
+    }
+
+    public static IServletRequest post(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(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);
+    }
+
+    public static IServletRequest get(FullHttpRequest request) throws IOException {
+        return new GetRequest(request, new QueryStringDecoder(request.uri()).parameters());
+    }
+
+    public static IServletRequest toServletRequest(FullHttpRequest request) throws IOException
{
+        return request.method() == HttpMethod.GET ? ServletUtils.get(request) : ServletUtils.post(request);
+    }
+
+    public static void setContentType(IServletResponse response, String type, String charset)
throws IOException {
+        response.setHeader(HttpHeaderNames.CONTENT_TYPE, type + "; charset=" + charset);
+    }
+
+    public static void setContentType(IServletResponse response, String type) throws IOException
{
+        response.setHeader(HttpHeaderNames.CONTENT_TYPE, type);
+    }
+}


Mime
View raw message