/*
 * Licensed to Elastic Search and Shay Banon under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. Elastic Search 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.elasticsearch.wares;

import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.support.RestUtils;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Same as {@link NodeServlet} just uses async features.
 * <p/>
 * TODO: Needs to be properly tested, do we really use AsyncContext correctly?
 */
public class AsyncNodeServlet extends NodeServlet {

    @Override
    public void init() throws ServletException {
        super.init();
    }

    @Override
    public void destroy() {
        super.destroy();
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        final AsyncContext asyncContext = req.startAsync();
        ServletRestRequest request = new ServletRestRequest(req);
        AsyncServletRestChannel channel = new AsyncServletRestChannel(request, asyncContext);
        restController.dispatchRequest(request, channel);
    }

    static class AsyncServletRestChannel implements RestChannel {

        final RestRequest restRequest;

        final AsyncContext asyncContext;

        AsyncServletRestChannel(RestRequest restRequest, AsyncContext asyncContext) {
            this.restRequest = restRequest;
            this.asyncContext = asyncContext;
        }

        @Override
        public void sendResponse(RestResponse response) {
            HttpServletResponse resp = (HttpServletResponse) asyncContext.getResponse();
            resp.setContentType(response.contentType());
            if (RestUtils.isBrowser(restRequest.header("User-Agent"))) {
                resp.addHeader("Access-Control-Allow-Origin", "*");
                if (restRequest.method() == RestRequest.Method.OPTIONS) {
                    // also add more access control parameters
                    resp.addHeader("Access-Control-Max-Age", "1728000");
                    resp.addHeader("Access-Control-Allow-Methods", "PUT, DELETE");
                    resp.addHeader("Access-Control-Allow-Headers", "X-Requested-With");
                }
            }
            String opaque = restRequest.header("X-Opaque-Id");
            if (opaque != null) {
                resp.addHeader("X-Opaque-Id", opaque);
            }
            try {
                int contentLength = response.contentLength() + response.prefixContentLength() + response.suffixContentLength();
                resp.setContentLength(contentLength);

                ServletOutputStream out = resp.getOutputStream();
                if (response.prefixContent() != null) {
                    out.write(response.prefixContent(), 0, response.prefixContentLength());
                }
                out.write(response.content(), 0, response.contentLength());
                if (response.suffixContent() != null) {
                    out.write(response.suffixContent(), 0, response.suffixContentLength());
                }
                out.close();
            } catch (IOException e) {
                resp.setStatus(500);
            } finally {
                asyncContext.complete();
            }
        }
    }
}

@@ -3388,34 +3388,126 @@
 .contentLength()
+;%0A                if (response.prefixContent() != null) %7B%0A                    contentLength
  +
+=
  response.prefix
@@ -3521,18 +3521,128 @@
 Length()
+;%0A                %7D%0A                if (response.suffixContent() != null) %7B%0A                    contentLength
  +
+=
  respons
@@ -3658,32 +3658,50 @@
 ontentLength();%0A
+                %7D%0A
                 

update proper content length config in async node servlet as well