/* * Copyright 2008-2011 the original author or authors. * * 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 com.nominanuda.web.http; import static com.nominanuda.zen.oio.OioUtils.IO; import java.io.IOException; import java.io.InputStream; import java.net.HttpCookie; import java.util.Enumeration; import java.util.List; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.InputStreamBody; import org.apache.http.message.BasicHttpEntityEnclosingRequest; import org.apache.http.message.BasicHttpRequest; import org.eclipse.jetty.util.IO; import com.nominanuda.zen.common.Check; import com.nominanuda.zen.obj.Stru; import com.nominanuda.zen.stereotype.CodeConstants; @ThreadSafe public class ServletHelper implements CodeConstants { public final static ServletHelper SERVLET = new ServletHelper(); /** * @param request * @param stripContextPath * @return the raw uri as in the request line (verbatim unescaped) */ public String getRequestLineURI(HttpServletRequest request, boolean stripContextPath) { String query = request.getQueryString(); String path = request.getRequestURI(); if(stripContextPath) { path = path.substring(Check.ifNull(request.getContextPath(), "").length()); } return query == null ? path : path + "?" + query; } /** * @param servletRequest * @return an InputStream that contains at least one byte or null if underlying stream is null or empty * @throws IOException if thrown while accessing the underlying ServletInputStream */ public @Nullable InputStream getServletRequestBody(HttpServletRequest servletRequest) throws IOException { ServletInputStream sis = servletRequest.getInputStream(); if (servletRequest.getContentLength() > 0) { return sis; } else { return null; } } public @Nullable String getCharacterEncoding(HttpServletRequest servletRequest) { return servletRequest.getCharacterEncoding(); } public @Nullable String getContentEncoding(HttpServletRequest servletRequest) { return servletRequest.getHeader("Content-Encoding"); } public void copyResponse(HttpResponse response, HttpServletResponse servletResponse) throws IOException { servletResponse.setStatus(response.getStatusLine().getStatusCode()); for (Header h : response.getAllHeaders()) { if ("Set-Cookie".equals(h.getName()) || "Set-Cookie2".equals(h.getName())) { for (HttpCookie c : HttpCookie.parse(h.getValue())) { servletResponse.addCookie(servletCookie(c)); } } else { servletResponse.setHeader(h.getName(), h.getValue()); } } HttpEntity entity = response.getEntity(); if (entity != null) { Header ct = entity.getContentType(); if (ct != null) { servletResponse.setContentType(ct.getValue()); } Header ce = entity.getContentEncoding(); if (ce != null) { servletResponse.setHeader(ce.getName(), ce.getValue()); } long len = entity.getContentLength(); if (len >= 0) { servletResponse.setContentLength((int)len); } IO.pipe(entity.getContent(), servletResponse.getOutputStream(), true, false); } } public Cookie servletCookie(HttpCookie c) { Cookie _c = new Cookie(c.getName(), c.getValue()); if (c.getComment() != null) { _c.setComment(c.getComment()); } if (c.getDomain() != null) { _c.setDomain(c.getDomain()); } if (c.getPath() != null) { _c.setPath(c.getPath()); } _c.setSecure(c.getSecure()); _c.setVersion(c.getVersion()); _c.setHttpOnly(c.getDiscard()); _c.setMaxAge((int)c.getMaxAge()); return _c; } public HttpRequest copyRequest(HttpServletRequest servletRequest, boolean stripContextPath) throws IOException { final InputStream is = getServletRequestBody(servletRequest); String method = servletRequest.getMethod(); String uri = getRequestLineURI(servletRequest, stripContextPath); String ct = servletRequest.getContentType(); @SuppressWarnings("unused") String charenc = getCharacterEncoding(servletRequest); String cenc = getContentEncoding(servletRequest); long contentLength = servletRequest.getContentLength(); HttpRequest req; if (is == null) { req = new BasicHttpRequest(method, uri); } else { req = new BasicHttpEntityEnclosingRequest(method, uri); HttpEntity entity = buildEntity(servletRequest, is, contentLength, ct, cenc); if(entity != null) { ((BasicHttpEntityEnclosingRequest)req).setEntity(entity); } } Enumeration<?> names = servletRequest.getHeaderNames(); while (names.hasMoreElements()) { String name = (String)names.nextElement(); Enumeration<?> vals = servletRequest.getHeaders(name); while (vals.hasMoreElements()) { String value = (String)vals.nextElement(); req.addHeader(name, value); } } return req; } private HttpEntity buildEntity(HttpServletRequest servletRequest, final InputStream is, long contentLength, String ct, String cenc) throws IOException { if (ServletFileUpload.isMultipartContent(servletRequest)) { FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); List<FileItem> items; try { items = upload.parseRequest(new HttpServletRequestWrapper(servletRequest) { public ServletInputStream getInputStream() throws IOException { return new ServletInputStream() { public int read() throws IOException { return is.read(); } public int read(byte[] arg0) throws IOException { return is.read(arg0); } public int read(byte[] b, int off, int len) throws IOException { return is.read(b, off, len); } //@Override public boolean isFinished() { Check.illegalstate.fail(NOT_IMPLEMENTED); return false; } //@Override public boolean isReady() { Check.illegalstate.fail(NOT_IMPLEMENTED); return false; } //@Override public void setReadListener(ReadListener arg0) { Check.illegalstate.fail(NOT_IMPLEMENTED); } }; } }); } catch (FileUploadException e) { throw new IOException(e); } MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE); for (FileItem i : items) { multipartEntity.addPart(i.getFieldName(), new InputStreamBody(i.getInputStream(), i.getName())); } return multipartEntity; } else { InputStreamEntity entity = new InputStreamEntity(is, contentLength); entity.setContentType(ct); if(cenc != null) { entity.setContentEncoding(cenc); } return entity; } } public HttpRequest getOrCreateRequest(HttpServletRequest servletRequest, boolean stripContextPath) throws IOException { HttpRequest req = (HttpRequest)servletRequest.getAttribute("__HttpRequest__"); if (req == null) { req = copyRequest(servletRequest, stripContextPath); servletRequest.setAttribute("__HttpRequest__", req); } return req; } public void storeCommand(HttpServletRequest servletRequest, Stru command) throws IOException { servletRequest.setAttribute("__command__", command); } public @Nullable Stru getCommand(HttpServletRequest servletRequest) throws IOException { return (Stru)servletRequest.getAttribute("__command__"); } public void storeHandlerOutput(HttpServletRequest servletRequest, Object handlerOutput) { servletRequest.setAttribute("__handlerOutput__", handlerOutput); } public @Nullable Object getHandlerOutput(HttpServletRequest servletRequest) throws IOException { return servletRequest.getAttribute("__handlerOutput__"); } public void storeResponse(HttpServletRequest servletRequest, HttpResponse response) { servletRequest.setAttribute("__HttpResponse__", response); } public @Nullable HttpResponse getResponse(HttpServletRequest servletRequest) throws IOException { return (HttpResponse)servletRequest.getAttribute("__HttpResponse__"); } }