/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF 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.apache.cocoon.environment.http; import java.io.IOException; import java.io.OutputStream; import java.net.MalformedURLException; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.cocoon.environment.AbstractEnvironment; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.PermanentRedirector; import org.apache.cocoon.environment.Redirector; import org.apache.cocoon.environment.Session; import org.apache.cocoon.util.NetUtils; /** * HTTP Servlet environment. * * @author <a herf="mailto:dev@cocoon.apache.org">Apache Cocoon Team</a> * @version $Id$ */ public class HttpEnvironment extends AbstractEnvironment implements Redirector, PermanentRedirector { public static final String HTTP_REQUEST_OBJECT = "httprequest"; public static final String HTTP_RESPONSE_OBJECT= "httpresponse"; public static final String HTTP_SERVLET_CONTEXT= "httpservletcontext"; /** The HttpRequest */ private HttpRequest request; /** The HttpResponse */ private HttpResponse response; /** The HttpContext */ private HttpContext webcontext; /** Cache content type as there is no getContentType() in reponse object */ private String contentType; /** Did we redirect ? */ private boolean hasRedirected = false; /** * Constructs a HttpEnvironment object from a HttpServletRequest * and HttpServletResponse objects */ public HttpEnvironment(String uri, String root, HttpServletRequest req, HttpServletResponse res, ServletContext servletContext, HttpContext context, String containerEncoding, String defaultFormEncoding) throws MalformedURLException, IOException { super(uri, null, root, null); this.request = new HttpRequest(req, this); if (req.getCharacterEncoding() == null) { // use the value from web.xml this.request.setContainerEncoding(containerEncoding != null ? containerEncoding : "ISO-8859-1"); } else { // use what we have been given this.request.setContainerEncoding(req.getCharacterEncoding()); } this.request.setCharacterEncoding(defaultFormEncoding != null ? defaultFormEncoding : "UTF-8"); this.response = new HttpResponse(res); this.webcontext = context; setView(extractView(this.request)); setAction(extractAction(this.request)); this.objectModel.put(ObjectModelHelper.REQUEST_OBJECT, this.request); this.objectModel.put(ObjectModelHelper.RESPONSE_OBJECT, this.response); this.objectModel.put(ObjectModelHelper.CONTEXT_OBJECT, this.webcontext); // This is a kind of a hack for the components that need // the real servlet objects to pass them along to other // libraries. this.objectModel.put(HTTP_REQUEST_OBJECT, req); this.objectModel.put(HTTP_RESPONSE_OBJECT, res); this.objectModel.put(HTTP_SERVLET_CONTEXT, servletContext); } public void redirect(boolean sessionmode, String newURL) throws IOException { doRedirect(sessionmode, newURL, false); } public void permanentRedirect(boolean sessionmode, String newURL) throws IOException { doRedirect(sessionmode, newURL, true); } public void sendStatus(int sc) { setStatus(sc); this.hasRedirected = true; } /** * Redirect the client to new URL with session mode */ private void doRedirect(boolean sessionmode, String newURL, boolean permanent) throws IOException { this.hasRedirected = true; // check if session mode shall be activated if (sessionmode) { String s = request.getRequestedSessionId(); if (getLogger().isDebugEnabled()) { if (s != null) { getLogger().debug("Redirect: Requested session ID <" + s + "> is " + (request.isRequestedSessionIdValid()? "valid" : "invalid")); } else { getLogger().debug("Redirect: No session found in request"); } } // Get session from request, or create new session Session session = request.getSession(); if (getLogger().isDebugEnabled()) { getLogger().debug ("Redirect: Obtained session <" + session.getId() + ">"); } } // Redirect String redirect = this.response.encodeRedirectURL(newURL); // FIXME (VG): WebSphere 4.0/4.0.1 bug if (!newURL.startsWith("/") && newURL.indexOf(':') == -1 && redirect.indexOf(':') != -1) { if (getLogger().isDebugEnabled()) { getLogger().debug("Redirect: WebSphere Bug Detected!"); } String base = NetUtils.getPath(request.getRequestURI()); if (base.startsWith("/")) { base = base.substring(1); } redirect = response.encodeRedirectURL(base + '/' + newURL); } if (getLogger().isDebugEnabled()) { getLogger().debug("Sending redirect to '" + redirect + "'"); } if (permanent) { this.response.sendPermanentRedirect(redirect); } else { this.response.sendRedirect(redirect); } } public boolean hasRedirected() { return this.hasRedirected; } /** * Set the StatusCode */ public void setStatus(int statusCode) { this.response.setStatus(statusCode); } /** * Set the ContentType */ public void setContentType(String contentType) { this.response.setContentType(contentType); this.contentType = contentType; } /** * Get the ContentType */ public String getContentType() { return this.contentType; } /** * Set the length of the generated content */ public void setContentLength(int length) { this.response.setContentLength(length); } /** * Check if the response has been modified since the same * "resource" was requested. * The caller has to test if it is really the same "resource" * which is requested. * @return true if the response is modified or if the * environment is not able to test it */ public boolean isResponseModified(long lastModified) { if (lastModified != 0) { long if_modified_since = this.request.getDateHeader("If-Modified-Since"); this.response.setDateHeader("Last-Modified", lastModified); return (if_modified_since / 1000 < lastModified / 1000); } return true; } /** * Mark the response as not modified. */ public void setResponseIsNotModified() { this.response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } /** * Reset the response if possible. This allows error handlers to have * a higher chance to produce clean output if the pipeline that raised * the error has already output some data. * * @return true if the response was successfully reset */ public boolean tryResetResponse() throws IOException { if (!super.tryResetResponse()) { try { if (!this.response.isCommitted()) { this.response.reset(); if (getLogger().isDebugEnabled()) { getLogger().debug("Response successfully reset"); } return true; } } catch (Exception e) { // Log the error, but don't transmit it getLogger().warn("Problem resetting response", e); } if (getLogger().isDebugEnabled()) { getLogger().debug("Response wasn't reset"); } return false; } return true; } /** * Get the output stream where to write the generated resource. * The returned stream is buffered by the environment. If the * buffer size is -1 then the complete output is buffered. * If the buffer size is 0, no buffering takes place. * This method replaces {@link #getOutputStream()}. */ public OutputStream getOutputStream(final int bufferSize) throws IOException { if (this.outputStream == null) { this.outputStream = this.response.getOutputStream(); } return super.getOutputStream(bufferSize); } /** * Always return <code>true</code>. */ public boolean isExternal() { return true; } }