/* This file is part of leafdigital picstory. picstory is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. picstory is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with picstory. If not, see <http://www.gnu.org/licenses/>. Copyright 2010 Samuel Marshall. */ package com.leafdigital.picstory; import java.io.*; import java.nio.charset.Charset; import javax.servlet.http.*; /** * Holds details of an HTTP request. */ public class Request { /** * Constant indicating that the length of output data is unknown. */ public final static int UNKNOWN_LENGTH = -1; private final static long ONE_YEAR = 365L * 24L * 3600L * 1000L; private HttpServletRequest request; private HttpServletResponse response; private boolean sentData; /** * @param request HTTP request * @param response HTTP response */ public Request(HttpServletRequest request, HttpServletResponse response) { this.request = request; this.response = response; } /** * @return Servlet request */ public HttpServletRequest getRequest() { return request; } /** * @return Servlet response */ public HttpServletResponse getResponse() { return response; } /** * @return True if this is a debug request (?debug parameter) */ public boolean isReload() { return request.getParameter("reload") != null; } /** * @return True if we have already sent (or started sending) data */ public boolean sentData() { return sentData; } /** * Outputs a page as XHTML if possible. * @param statusCode Status code (HttpServletResponse.SC_xx) * @param page Page content * @throws IOException Any error */ public void outputXhtml(int statusCode, String page) throws IOException { outputText(statusCode, getXhtmlMimeType(), page); } /** * @return MIME type to use for an XHTML response to this request */ private String getXhtmlMimeType() { String accept = request.getHeader("accept"); boolean xhtml = accept != null && accept.contains("application/xhtml+xml"); return xhtml ? "application/xhtml+xml" : "text/html"; } /** * Outputs a page as text (UTF-8). * @param statusCode Status code * @param contentType Content type * @param page Page content * @throws IOException Any error */ public void outputText(int statusCode, String contentType, String page) throws IOException { response.setCharacterEncoding("UTF-8"); outputBinary(statusCode, contentType, page.getBytes(Charset.forName("UTF-8"))); } /** * Outputs binary data. * @param statusCode Status code * @param contentType Content type * @param data Data * @throws IOException Any error */ public void outputBinary(int statusCode, String contentType, byte[] data) throws IOException { sentData = true; OutputStream out = outputBinaryHeaders(statusCode, contentType, data.length); out.write(data); out.close(); } /** * @param statusCode Status code * @return Output writer that you should now write the data to * @throws IOException Any error */ public PrintWriter outputXhtmlHeaders(int statusCode) throws IOException { sentData = true; response.setContentType(getXhtmlMimeType()); response.setCharacterEncoding("UTF-8"); response.setStatus(statusCode); return response.getWriter(); } /** * @param statusCode Status code * @param contentType Content type * @param length Length in bytes or UNKNOWN_LENGTH if unknown * @return Output stream that you should now write the data to * @throws IOException Any error */ public OutputStream outputBinaryHeaders(int statusCode, String contentType, int length) throws IOException { sentData = true; response.setContentType(contentType); response.setStatus(statusCode); if(length != UNKNOWN_LENGTH) { response.setContentLength(length); } return response.getOutputStream(); } /** * @param url URL for redirect * @throws IOException Any error */ public void redirect(String url) throws IOException { sentData = true; response.sendRedirect(url); } /** * Ensures that any If-Modified-Since header results in a Not Modified * response. * @return True if request includes If-Modified-Since header and a response * has been sent */ public boolean handleIfModifiedSince() { long modified = request.getDateHeader("If-Modified-Since"); if(modified != -1) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return true; } return false; } /** * Make sure result doesn't expire from cache */ public void preventExpiry() { response.addDateHeader("Expires", System.currentTimeMillis() + ONE_YEAR); } /** * @return Path to root e.g. "../" * @throws InternalException If this doesn't work for some reason */ public String getPathToRoot() throws InternalException { String requestUri = request.getRequestURI(); String baseUri = request.getContextPath(); int start = requestUri.indexOf(baseUri); if(start == -1) { throw new InternalException("Unable to figure out base URL"); } String remainingPath = requestUri.substring(start + baseUri.length()); int remainingSlashes = remainingPath.replaceAll("[^/]", "").length(); String pathToRoot = ""; for(int i=1; i<remainingSlashes; i++) { pathToRoot += "../"; } return pathToRoot; } }