/* * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net> * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package javax.winstone.servlet.http; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Serializable; import java.io.UnsupportedEncodingException; import javax.winstone.servlet.ServletException; import javax.winstone.servlet.ServletOutputStream; import javax.winstone.servlet.ServletRequest; import javax.winstone.servlet.ServletResponse; /** * Base class for http servlets * * @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a> */ public abstract class HttpServlet extends javax.winstone.servlet.GenericServlet implements Serializable { static final String METHOD_DELETE = "DELETE"; static final String METHOD_HEAD = "HEAD"; static final String METHOD_GET = "GET"; static final String METHOD_OPTIONS = "OPTIONS"; static final String METHOD_POST = "POST"; static final String METHOD_PUT = "PUT"; static final String METHOD_TRACE = "TRACE"; static final String HEADER_IFMODSINCE = "If-Modified-Since"; static final String HEADER_LASTMOD = "Last-Modified"; public HttpServlet() { super(); } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse)) service((HttpServletRequest) request, (HttpServletResponse) response); else throw new IllegalArgumentException( "Not an Http servlet request - invalid types"); } private void notAcceptedMethod(HttpServletRequest request, HttpServletResponse response, String method) throws ServletException, IOException { if (request.getProtocol().endsWith("1.1")) response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, method + " not allowed"); else response.sendError(HttpServletResponse.SC_BAD_REQUEST, method + " not allowed"); } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "GET"); } protected long getLastModified(HttpServletRequest req) { return -1; } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "POST"); } protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "PUT"); } protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "DELETE"); } protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "OPTIONS"); } protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { notAcceptedMethod(req, resp, "TRACE"); } protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method = request.getMethod(); if (method.equals(METHOD_GET)) { long lastModified = getLastModified(request); if (lastModified == -1) doGet(request, response); else { long ifModifiedSince = request.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < (lastModified / 1000 * 1000)) { if (!response.containsHeader(HEADER_LASTMOD) && (lastModified >= 0)) response.setDateHeader(HEADER_LASTMOD, lastModified); doGet(request, response); } else response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(request); if (!response.containsHeader(HEADER_LASTMOD) && (lastModified >= 0)) response.setDateHeader(HEADER_LASTMOD, lastModified); doHead(request, response); } else if (method.equals(METHOD_POST)) doPost(request, response); else if (method.equals(METHOD_PUT)) doPut(request, response); else if (method.equals(METHOD_DELETE)) doDelete(request, response); else if (method.equals(METHOD_OPTIONS)) doOptions(request, response); else if (method.equals(METHOD_TRACE)) doTrace(request, response); else notAcceptedMethod(request, response, method); } protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { NoBodyResponse response = new NoBodyResponse(resp); doGet(req, response); response.setContentLength(); } class NoBodyResponse extends HttpServletResponseWrapper { private NoBodyOutputStream noBody; private PrintWriter writer; private boolean contentLengthSet; NoBodyResponse(HttpServletResponse mainResponse) { super(mainResponse); this.noBody = new NoBodyOutputStream(); } void setContentLength() { if (!contentLengthSet) setContentLength(this.noBody.getContentLength()); } public void setContentLength(int length) { super.setContentLength(length); this.contentLengthSet = true; } public void setContentType(String type) { getResponse().setContentType(type); } public ServletOutputStream getOutputStream() throws IOException { return noBody; } public String getCharacterEncoding() { return getResponse().getCharacterEncoding(); } public PrintWriter getWriter() throws UnsupportedEncodingException { if (writer == null) writer = new PrintWriter(new OutputStreamWriter(noBody, getCharacterEncoding())); return writer; } } class NoBodyOutputStream extends ServletOutputStream { private int contentLength = 0; NoBodyOutputStream() { } int getContentLength() { return contentLength; } public void write(int b) throws IOException { contentLength++; } public void write(byte buf[], int offset, int len) throws IOException { contentLength += len; } } }