PageRenderTime 52ms CodeModel.GetById 1ms app.highlight 46ms RepoModel.GetById 2ms app.codeStats 0ms

/src/kilim/http/HttpResponse.java

http://github.com/kilim/kilim
Java | 242 lines | 188 code | 34 blank | 20 comment | 19 complexity | f69aa7cffeb2017b723e03de43c6703f MD5 | raw file
  1/* Copyright (c) 2006, Sriram Srinivasan
  2 *
  3 * You may distribute this software under the terms of the license 
  4 * specified in the file "License"
  5 */
  6
  7package kilim.http;
  8
  9import java.io.DataOutputStream;
 10import java.io.IOException;
 11import java.io.OutputStream;
 12import java.nio.ByteBuffer;
 13import java.text.SimpleDateFormat;
 14import java.util.ArrayList;
 15import java.util.Date;
 16import java.util.TimeZone;
 17import java.util.concurrent.ConcurrentHashMap;
 18
 19import kilim.Constants;
 20import kilim.Pausable;
 21import kilim.nio.EndPoint;
 22import kilim.nio.ExposedBaos;
 23
 24/**
 25 * The response object encapsulates the header and often, but not always, the content. The caller must set all the
 26 * fields, except for the protocol, server and date. The body of the response (the content) is written to a stream
 27 * obtained from {@link #getOutputStream()}.
 28 */
 29public class HttpResponse extends HttpMsg {
 30    // Status codes
 31    public static final byte[]                      ST_CONTINUE                      = "100 Continue\r\n".getBytes();
 32    public static final byte[]                      ST_SWITCHING_PROTOCOLS           = "101 Switching Protocols\r\n"
 33                                                                                             .getBytes();
 34
 35    // Successful status codes
 36
 37    public static final byte[]                      ST_OK                            = "200 OK\r\n".getBytes();
 38    public static final byte[]                      ST_CREATED                       = "201 Created\r\n".getBytes();
 39    public static final byte[]                      ST_ACCEPTED                      = "202 Accepted\r\n".getBytes();
 40    public static final byte[]                      ST_NON_AUTHORITATIVE             = "203 Non-Authoritative Information\r\n"
 41                                                                                             .getBytes();
 42    public static final byte[]                      ST_NO_CONTENT                    = "204 No Content\r\n".getBytes();
 43    public static final byte[]                      ST_RESET_CONTENT                 = "205 Reset Content\r\n"
 44                                                                                             .getBytes();
 45    public static final byte[]                      ST_PARTIAL_CONTENT               = "206 Partial Content\r\n"
 46                                                                                             .getBytes();
 47
 48    // Redirection status codes
 49
 50    public static final byte[]                      ST_MULTIPLE_CHOICES              = "300 Multiple Choices\r\n"
 51                                                                                             .getBytes();
 52    public static final byte[]                      ST_MOVED_PERMANENTLY             = "301 Moved Permanently\r\n"
 53                                                                                             .getBytes();
 54    public static final byte[]                      ST_FOUND                         = "302 Found\r\n".getBytes();
 55    public static final byte[]                      ST_SEE_OTHER                     = "303 See Other\r\n".getBytes();
 56    public static final byte[]                      ST_NOT_MODIFIED                  = "304 Not Modified\r\n"
 57                                                                                             .getBytes();
 58    public static final byte[]                      ST_USE_PROXY                     = "305 Use Proxy\r\n".getBytes();
 59    public static final byte[]                      ST_TEMPORARY_REDIRECT            = "307 Temporary Redirect\r\n"
 60                                                                                             .getBytes();
 61
 62    // Client error codes
 63
 64    public static final byte[]                      ST_BAD_REQUEST                   = "400 Bad Request\r\n".getBytes();
 65    public static final byte[]                      ST_UNAUTHORIZED                  = "401 Unauthorized\r\n"
 66                                                                                             .getBytes();
 67    public static final byte[]                      ST_PAYMENT_REQUIRED              = "402 Payment Required\r\n"
 68                                                                                             .getBytes();
 69    public static final byte[]                      ST_FORBIDDEN                     = "403 Forbidden\r\n".getBytes();
 70    public static final byte[]                      ST_NOT_FOUND                     = "404 Not Found\r\n".getBytes();
 71    public static final byte[]                      ST_METHOD_NOT_ALLOWED            = "405 Method Not Allowed\r\n"
 72                                                                                             .getBytes();
 73    public static final byte[]                      ST_NOT_ACCEPTABLE                = "406 Not Acceptable\r\n"
 74                                                                                             .getBytes();
 75    public static final byte[]                      ST_PROXY_AUTHENTICATION_REQUIRED = "407 Proxy Authentication Required\r\n"
 76                                                                                             .getBytes();
 77    public static final byte[]                      ST_REQUEST_TIMEOUT               = "408 Request Time-out\r\n"
 78                                                                                             .getBytes();
 79    public static final byte[]                      ST_CONFLICT                      = "409 Conflict\r\n".getBytes();
 80    public static final byte[]                      ST_GONE                          = "410 Gone\r\n".getBytes();
 81    public static final byte[]                      ST_LENGTH_REQUIRED               = "411 Length Required\r\n"
 82                                                                                             .getBytes();
 83    public static final byte[]                      ST_PRECONDITION_FAILED           = "412 Precondition Failed\r\n"
 84                                                                                             .getBytes();
 85    public static final byte[]                      ST_REQUEST_ENTITY_TOO_LARGE      = "413 Request Entity Too Large\r\n"
 86                                                                                             .getBytes();
 87    public static final byte[]                      ST_REQUEST_URI_TOO_LONG          = "414 Request-URI Too Large\r\n"
 88                                                                                             .getBytes();
 89    public static final byte[]                      ST_UNSUPPORTED_MEDIA_TYPE        = "415 Unsupported Media Type\r\n"
 90                                                                                             .getBytes();
 91    public static final byte[]                      ST_REQUEST_RANGE_NOT_SATISFIABLE = "416 Requested range not satisfiable\r\n"
 92                                                                                             .getBytes();
 93    public static final byte[]                      ST_EXPECTATION_FAILED            = "417 Expectation Failed\r\n"
 94                                                                                             .getBytes();
 95    public static final byte[]                      ST_TEAPOT                        = "418 I'm a Teapot\r\n"
 96                                                                                             .getBytes();
 97
 98    // Server error codes
 99
100    public static final byte[]                      ST_INTERNAL_SERVER_ERROR         = "500 Internal Server Error\r\n"
101                                                                                             .getBytes();
102    public static final byte[]                      ST_NOT_IMPLEMENTED               = "501 Not Implemented\r\n"
103                                                                                             .getBytes();
104    public static final byte[]                      ST_BAD_GATEWAY                   = "502 Bad Gateway\r\n".getBytes();
105    public static final byte[]                      ST_SERVICE_UNAVAILABLE           = "503 Service Unavailable\r\n"
106                                                                                             .getBytes();
107    public static final byte[]                      ST_GATEWAY_TIMEOUT               = "504 Gateway Time-out\r\n"
108                                                                                             .getBytes();
109    public static final byte[]                      ST_HTTP_VERSION_NOT_SUPPORTED    = "505 HTTP Version not supported\r\n"
110                                                                                             .getBytes();
111
112    // Http response components
113    public static final byte[]                      PROTOCOL                         = "HTTP/1.1 ".getBytes();
114    public static final byte[]                      F_SERVER                         = ("Server: kilim "
115                                                                                             + Constants.KILIM_VERSION + "\r\n")
116                                                                                             .getBytes();
117    public static final byte[]                      F_DATE                           = "Date: ".getBytes();
118    public static final byte[]                      CRLF                             = "\r\n".getBytes();
119    public static final byte[]                      FIELD_SEP                        = ": ".getBytes();
120
121    public static ConcurrentHashMap<String, byte[]> byteCache                        = new ConcurrentHashMap<String, byte[]>();
122
123    /**
124     * The status line for the response. Can use any of the predefined strings in HttpResponse.ST_*.
125     */
126    public byte[]                                   status;
127    public ArrayList<String>                        keys                             = new ArrayList<String>();
128    public ArrayList<String>                        values                           = new ArrayList<String>();
129    public ExposedBaos                              bodyStream;
130
131    public static final SimpleDateFormat            gmtdf;
132
133    static {
134        gmtdf = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss");
135        gmtdf.setTimeZone(TimeZone.getTimeZone("GMT:00"));
136    }
137
138    public HttpResponse() {
139        this(ST_OK);
140    }
141
142    public HttpResponse(byte[] statusb) {
143        status = statusb;
144    }
145
146    public void reuse() {
147        status = ST_OK;
148        keys.clear();
149        values.clear();
150        if (bodyStream != null) {
151            bodyStream.reset();
152        }
153        if (buffer != null) {
154            buffer.clear();
155        }
156    }
157
158    public void setStatus(String statusMsg) {
159        if (!statusMsg.endsWith("\r\n")) {
160            statusMsg = statusMsg + "\r\n";
161        }
162        this.status = statusMsg.getBytes();
163    }
164
165    public HttpResponse(String statusMsg) {
166        this();
167        setStatus(statusMsg);
168    }
169
170    public HttpResponse addField(String key, String value) {
171        keys.add(key);
172        values.add(value);
173        return this;
174    }
175
176    public String getHeaderValue(String key) {
177        int nfields = keys.size();
178        for (int i = 0; i < nfields; i++) {
179          if (key.equals(keys.get(i))) return values.get(i);
180        }
181        return null;
182    }
183
184    public void writeHeader(OutputStream os) throws IOException {
185        DataOutputStream dos = new DataOutputStream(os);
186        dos.write(PROTOCOL);
187        dos.write(status);
188
189        dos.write(F_DATE);
190        byte[] date = gmtdf.format(new Date()).getBytes();
191        dos.write(date);
192        dos.write(CRLF);
193
194        dos.write(F_SERVER);
195
196        if (bodyStream != null && getHeaderValue("Content-Length") == null) {
197            setContentLength(bodyStream.size());
198        }
199
200        // Fields.
201        int nfields = keys.size();
202        for (int i = 0; i < nfields; i++) {
203            String key = keys.get(i);
204            byte[] keyb = byteCache.get(key);
205            if (keyb == null) {
206                keyb = key.getBytes();
207                byteCache.put(key, keyb);
208            }
209            dos.write(keyb);
210            dos.write(FIELD_SEP);
211            dos.write(values.get(i).getBytes());
212            dos.write(CRLF);
213        }
214        dos.write(CRLF);
215    }
216
217    public OutputStream getOutputStream() {
218        if (bodyStream == null)
219            bodyStream = new ExposedBaos(2048);
220        return bodyStream;
221    }
222
223    public void writeTo(EndPoint endpoint) throws IOException, Pausable {
224        ExposedBaos headerStream = new ExposedBaos();
225        writeHeader(headerStream);
226        ByteBuffer bb = headerStream.toByteBuffer();
227        endpoint.write(bb);
228        if (bodyStream != null && bodyStream.size() > 0) {
229            bb = bodyStream.toByteBuffer();
230            endpoint.write(bb);
231        }
232    }
233
234    public void setContentLength(long length) {
235        addField("Content-Length", Long.toString(length));
236    }
237
238    public void setContentType(String contentType) {
239        addField("Content-Type", contentType);
240    }
241}
242