
net.lightbody.bmp.proxy.jetty.http.HttpResponse Maven / Gradle / Ivy
// ========================================================================
// $Id: HttpResponse.java,v 1.61 2005/10/26 08:10:14 gregwilkins Exp $
// Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// 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 net.lightbody.bmp.proxy.jetty.http;
import net.lightbody.bmp.proxy.jetty.util.LogSupport;
import net.lightbody.bmp.proxy.jetty.util.StringUtil;
import net.lightbody.bmp.proxy.jetty.util.TypeUtil;
import net.lightbody.bmp.proxy.jetty.util.UrlEncoded;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.Cookie;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
/**
* HTTP Response. This class manages the headers, trailers and content streams of a HTTP response.
* It can be used for receiving or generating requests.
*
* This class is not synchronized. It should be explicitly synchronized if it is used by multiple threads.
*
* @author Greg Wilkins (gregw)
* @version $Id: HttpResponse.java,v 1.61 2005/10/26 08:10:14 gregwilkins Exp $
* @see HttpRequest
*/
public class HttpResponse extends HttpMessage {
public static final int
__100_Continue = 100,
__101_Switching_Protocols = 101,
__102_Processing = 102,
__200_OK = 200,
__201_Created = 201,
__202_Accepted = 202,
__203_Non_Authoritative_Information = 203,
__204_No_Content = 204,
__205_Reset_Content = 205,
__206_Partial_Content = 206,
__207_Multi_Status = 207,
__300_Multiple_Choices = 300,
__301_Moved_Permanently = 301,
__302_Moved_Temporarily = 302,
__302_Found = 302,
__303_See_Other = 303,
__304_Not_Modified = 304,
__305_Use_Proxy = 305,
__400_Bad_Request = 400,
__401_Unauthorized = 401,
__402_Payment_Required = 402,
__403_Forbidden = 403,
__404_Not_Found = 404,
__405_Method_Not_Allowed = 405,
__406_Not_Acceptable = 406,
__407_Proxy_Authentication_Required = 407,
__408_Request_Timeout = 408,
__409_Conflict = 409,
__410_Gone = 410,
__411_Length_Required = 411,
__412_Precondition_Failed = 412,
__413_Request_Entity_Too_Large = 413,
__414_Request_URI_Too_Large = 414,
__415_Unsupported_Media_Type = 415,
__416_Requested_Range_Not_Satisfiable = 416,
__417_Expectation_Failed = 417,
__422_Unprocessable_Entity = 422,
__423_Locked = 423,
__424_Failed_Dependency = 424,
__500_Internal_Server_Error = 500,
__501_Not_Implemented = 501,
__502_Bad_Gateway = 502,
__503_Service_Unavailable = 503,
__504_Gateway_Timeout = 504,
__505_HTTP_Version_Not_Supported = 505,
__507_Insufficient_Storage = 507;
public final static HashMap __statusMsg = new HashMap();
static byte[] __Continue;
private static final Logger log = LoggerFactory.getLogger(HttpResponse.class);
static {
// Build error code map using reflection
try {
Field[] fields = net.lightbody.bmp.proxy.jetty.http.HttpResponse.class.getDeclaredFields();
for (int f = fields.length; f-- > 0; ) {
int m = fields[f].getModifiers();
String name = fields[f].getName();
if (Modifier.isFinal(m) && Modifier.isStatic(m)
&& fields[f].getType().equals(Integer.TYPE) && name.startsWith("__")
&& Character.isDigit(name.charAt(2))) {
String message = name.substring(6);
message = message.replace('_', ' ');
__statusMsg.put(fields[f].get(null), message);
}
}
} catch (Exception e) {
log.warn(LogSupport.EXCEPTION, e);
}
}
static {
try {
__Continue = "HTTP/1.1 100 Continue\015\012\015\012".getBytes(StringUtil.__ISO_8859_1);
} catch (Exception e) {
log.error(e.getMessage(), e);
System.exit(1);
}
}
private int _status = __200_OK;
private String _reason;
private HttpContext _httpContext;
/**
* Constructor.
*/
public HttpResponse() {
_version = __HTTP_1_1;
_dotVersion = 1;
_state = __MSG_EDITABLE;
}
/**
* Constructor.
*
* @param connection
*/
public HttpResponse(HttpConnection connection) {
super(connection);
_version = __HTTP_1_1;
_dotVersion = 1;
_state = __MSG_EDITABLE;
}
/**
* Get the HttpContext handling this response.
*
* @return The HttpContext that is handling this request.
*/
public HttpContext getHttpContext() {
return _httpContext;
}
/**
* Set the HttpContext handling this response.
*
* @param context The HttpContext handling this response.
*/
public void setHttpContext(HttpContext context) {
_httpContext = context;
}
/**
* @return true if the message has been modified.
*/
public boolean isDirty() {
return _status != __200_OK || super.isDirty();
}
/**
* Reset the response.
* Clears any data that exists in the buffer as well as the status code. If the response has been committed,
* this method throws an IllegalStateException
.
*
* @throws IllegalStateException if the response has already been committed
*/
public void reset() {
if (isCommitted()) {
throw new IllegalStateException("Already committed");
}
try {
((HttpOutputStream) getOutputStream()).resetBuffer();
_status = __200_OK;
_reason = null;
super.reset();
setField(HttpFields.__Date, getRequest().getTimeStampStr());
if (!Version.isParanoid()) {
setField(HttpFields.__Server, Version.getDetail());
}
} catch (Exception e) {
log.warn(LogSupport.EXCEPTION, e);
throw new IllegalStateException(e.toString());
}
}
/**
* @deprecated use getHttpRequest()
*/
public HttpRequest getRequest() {
return getHttpRequest();
}
/**
* Get the HTTP Request. Get the HTTP Request associated with this response.
*
* @return associated request
*/
public HttpRequest getHttpRequest() {
if (_connection == null) {
return null;
}
return _connection.getRequest();
}
/**
* Not Implemented.
*
* @param in
*/
public void readHeader(HttpInputStream in) {
_state = __MSG_BAD;
log.warn(LogSupport.NOT_IMPLEMENTED);
}
public void writeHeader(Writer writer) throws IOException {
if (_state != __MSG_EDITABLE) {
throw new IllegalStateException(__state[_state] + " is not EDITABLE");
}
if (_header == null) {
throw new IllegalStateException("Response is destroyed");
}
if (getHttpRequest().getDotVersion() >= 0) {
_state = __MSG_BAD;
writer.write(_version);
writer.write(' ');
writer.write('0' + ((_status / 100) % 10));
writer.write('0' + ((_status / 10) % 10));
writer.write('0' + (_status % 10));
writer.write(' ');
writer.write(getReason());
writer.write(HttpFields.__CRLF);
_header.write(writer);
}
_state = __MSG_SENDING;
}
public int getStatus() {
return _status;
}
public void setStatus(int status) {
_status = status;
}
public String getReason() {
if (_reason != null) {
return _reason;
}
_reason = (String) __statusMsg.get(TypeUtil.newInteger(_status));
if (_reason == null) {
_reason = "unknown";
}
return _reason;
}
public void setReason(String reason) {
_reason = reason;
}
public void setStatus(int code, String message) {
setStatus(code);
Integer code_integer = TypeUtil.newInteger(code);
if (message == null) {
message = (String) __statusMsg.get(code_integer);
if (message == null) {
message = "" + code;
}
setReason(message);
} else {
setReason(UrlEncoded.encodeString(message));
}
}
/**
* Send Error Response.
*/
public void sendError(int code, String message) throws IOException {
setStatus(code, message);
// Generate normal error page.
HttpRequest request = getHttpRequest();
// If we are allowed to have a body
if (code != __204_No_Content && code != __304_Not_Modified && code != __206_Partial_Content && code >= 200) {
if (getHttpContext() != null) {
Object o = getHttpContext().getAttribute(HttpContext.__ErrorHandler);
if (o != null && o instanceof HttpHandler) {
((HttpHandler) o).handle(request.getPath(), null, request, this);
}
}
} else {
if (code != __206_Partial_Content) {
_header.remove(HttpFields.__ContentType);
_header.remove(HttpFields.__ContentLength);
_characterEncoding = null;
_mimeType = null;
}
}
commit();
}
/**
* Sends an error response to the client using the specified status code and no default message.
*
* @param code the status code
* @throws IOException If an I/O error has occurred.
*/
public void sendError(int code) throws IOException {
sendError(code, null);
}
/**
* Sends a redirect response to the client using the specified redirect location URL.
*
* @param location the redirect location URL
* @throws IOException If an I/O error has occurred.
*/
public void sendRedirect(String location) throws IOException {
if (isCommitted()) {
throw new IllegalStateException("Commited");
}
_header.put(HttpFields.__Location, location);
setStatus(__302_Moved_Temporarily);
commit();
}
/**
* Add a Set-Cookie field.
*/
public void addSetCookie(String name, String value) {
_header.addSetCookie(new Cookie(name, value));
}
/**
* Add a Set-Cookie field.
*/
public void addSetCookie(Cookie cookie) {
_header.addSetCookie(cookie);
}
public void completing() {
getHttpConnection().completing();
}
/**
* @throws IOException
*/
public void commit() throws IOException {
if (!isCommitted()) {
getOutputStream().flush();
}
getHttpConnection().commit();
}
/**
* Recycle the response.
*/
void recycle(HttpConnection connection) {
super.recycle(connection);
_status = __200_OK;
_reason = null;
_httpContext = null;
}
/**
* Destroy the response.
* Help the garbage collector by null everything that we can.
*/
public void destroy() {
_reason = null;
super.destroy();
}
}