/* * 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(); if (response.prefixContent() != null) { contentLength += response.prefixContentLength(); } if (response.suffixContent() != null) { contentLength += 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(); } } } }