/* * Copyright 2013 eXo Platform SAS * * Licensed 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 juzu.impl.bridge.spi.servlet; import juzu.asset.AssetLocation; import juzu.impl.bridge.spi.web.HttpStream; import juzu.impl.bridge.spi.web.WebRequestContext; import juzu.impl.common.FormURLEncodedParser; import juzu.impl.common.JUL; import juzu.impl.common.Lexers; import juzu.impl.common.Logger; import juzu.impl.common.Name; import juzu.impl.common.RunMode; import juzu.impl.common.Spliterator; import juzu.impl.common.Tools; import juzu.impl.io.BinaryOutputStream; import juzu.io.Stream; import juzu.request.RequestParameter; import javax.servlet.AsyncContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.Charset; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** @author Julien Viet */ public class ServletRequestContext extends WebRequestContext { /** The request logger. */ static final Logger log = JUL.getLogger(ServletRequestContext.class.getName()); /** . */ final HttpServletRequest req; /** . */ final HttpServletResponse resp; /** . */ final String path; /** . */ final String requestPath; /** . */ final Map<String, RequestParameter> requestParameters; /** . */ final Charset defaultEncoding; /** . */ private AsyncContext context; /** . */ private final String prefix; /** . */ private final RunMode runMode; public ServletRequestContext( Name application, Charset defaultEncoding, HttpServletRequest req, HttpServletResponse resp, String path, RunMode runMode) { // Map<String, RequestParameter> requestParameters = Collections.emptyMap(); String query = req.getQueryString(); if (query != null) { for (Iterator<RequestParameter> i = Lexers.queryParser(query);i.hasNext();) { if (requestParameters.isEmpty()) { requestParameters = new HashMap<String, RequestParameter>(); } RequestParameter parameter = i.next(); parameter.appendTo(requestParameters); } } // if ("POST".equals(req.getMethod())) { String contentType = req.getContentType(); if (contentType != null && contentType.length() > 0) { Spliterator i = new Spliterator(contentType, ';'); if ("application/x-www-form-urlencoded".equals(i.next().trim())) { Charset charset = defaultEncoding; while (i.hasNext()) { String v = i.next().trim(); if (v.startsWith("charset=")) { charset = Charset.forName(v.substring("charset=".length())); } } try { byte[] bytes = Tools.copy(req.getInputStream(), new ByteArrayOutputStream()).toByteArray(); String form = new String(bytes, charset); FormURLEncodedParser parser = new FormURLEncodedParser(defaultEncoding, form, 0, form.length()); for (RequestParameter parameter : parser) { if (requestParameters.isEmpty()) { requestParameters = new HashMap<String, RequestParameter>(); } parameter.appendTo(requestParameters); } } catch (IOException e) { log.error("Cannot parse form post", e); } } } } // StringBuilder prefix = new StringBuilder(); for (String atom : application) { prefix.append('/').append(atom); } prefix.append("/assets/"); // this.defaultEncoding = defaultEncoding; this.requestPath = req.getRequestURI().substring(req.getContextPath().length()); this.requestParameters = requestParameters; this.req = req; this.path = path; this.resp = resp; this.prefix = prefix.toString(); this.runMode = runMode; } @Override public RunMode getRunMode() { return runMode; } public Map<String, RequestParameter> getParameters() { return requestParameters; } public String getRequestPath() { return requestPath; } public String getPath() { return path; } public String getRequestURI() { return req.getRequestURI(); } synchronized void endAsync() { if (context != null) { log.trace("Completing async"); context.complete(); } } /** * Begin or reuse an async context from the servlet. * * @return the async context */ synchronized AsyncContext beginAsync() { if (req.isAsyncStarted()) { context = req.getAsyncContext(); } else { log.trace("Starting async mode"); context = req.startAsync(); } return context; } @Override public HttpStream getStream(int status) { return new ServletStream(status, defaultEncoding); } public class ServletStream extends HttpStream { /** . */ private Stream dataStream; ServletStream(int status, Charset encoding) { super(ServletRequestContext.this, status, encoding); } @Override public void setStatusCode(int status) { resp.setStatus(status); } @Override protected Stream getDataStream(boolean create) { if (dataStream == null && create) { try { dataStream = new BinaryOutputStream(encoding, resp.getOutputStream()); } catch (IOException e) { throw new UnsupportedOperationException("Handle me gracefully", e); } } return dataStream; } @Override protected void beginAsync() { ServletRequestContext.this.beginAsync(); } @Override protected void endAsync() { ServletRequestContext.this.endAsync(); } } @Override public void setHeaders(Iterable<Map.Entry<String, String[]>> headers) { for (Map.Entry<String, String[]> header : headers) { resp.setHeader(header.getKey(), header.getValue()[0]); } } public void sendRedirect(String location) throws IOException { resp.sendRedirect(location); } public void setContentType(String mimeType, Charset charset) { String name = charset.name(); resp.setCharacterEncoding(name); resp.setContentType(mimeType); } public void setStatus(int status) { resp.setStatus(status); } public void renderAssetURL(AssetLocation location, String uri, Appendable appendable) throws IOException { switch (location) { case SERVER: if (!uri.startsWith("/")) { appendable.append(req.getContextPath()); appendable.append('/'); } appendable.append(uri); break; case APPLICATION: appendable.append(req.getContextPath()).append("/assets"); if (location == AssetLocation.APPLICATION && !uri.startsWith("/")) { appendable.append(prefix); } appendable.append(uri); break; case URL: appendable.append(uri); break; default: throw new AssertionError(); } } }