Source code: raining/protocol/http/HttpOKResponse.java
1 /*
2 * $Author: rahul_kumar $
3 * $Id: HttpOKResponse.java,v 1.1 2003/10/20 18:09:56 rahul_kumar Exp rahul $
4 */
5
6 package raining.protocol.http;
7 import raining.core.*;
8 import raining.util.*;
9 import java.util.*;
10 import java.text.SimpleDateFormat;
11
12 /**
13 * Interface for Response, including response header creation.
14 * TODO:Remember that headers need to cached as does data.
15 * I suggest if not found in cache, we can store these contents using
16 * getContent. Else we just send the content as a whole without coming
17 * here.
18 * What about when file is updated. We need the header to be generated.
19 *
20 * Acco to RFC 2616 a server SHOULD send a "Date:" header, with the
21 * closest approximation of the time. THis means we have to keep
22 * updating this header and store it separately. However, the RFC states
23 * that if we cant give an accurate time, then we SHOULD not. XXX
24 *
25 * XXX i have begun passing in the request object, for logging etc.
26 * However, when the cacher precreates a header, or updates it there
27 * wont be a request. so logging cant really happen here.
28 */
29
30 public class HttpOKResponse implements Response {
31
32 ///// static variables ////////////////////////////////
33 static byte[] header = null;
34 static String sheader = null;
35
36 public final static String HTTP_VERSION = "HTTP/1.1";
37 public final static String CRLF = "\r\n";
38 public final static String CRLF2 = "\r\n\r\n";
39 public final static String contentType = "text/html";
40 public final static int LAST_MODIFIED_HEADER_SIZE = "Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT".length();
41 public final static byte[] LAST_MODIFIED = "Last-Modified: ".getBytes();
42 public final static int DATE_SIZE = 29; // fixed size of date as per RFC 822
43
44 static {
45 sheader = HTTP_VERSION + " 200 OK"+ CRLF +
46 "Content-Type: "+ contentType + CRLF +
47 "Connection: close"+ CRLF +
48 "Content-Length: ";
49 header = sheader.getBytes();
50 }
51 ///// instance variables ////////////////////////////////
52 byte[] content = null;
53 StringBuffer sb = null;
54 /** constructor taking a byte array. This would be the preferred
55 * constructor.
56 * <pre>next line takes 263ms for 100,000 iterations
57 byte[] blen = new byte[]{(byte)'1',(byte)'6'};
58 * next line takes 1020ms for 100,000 iterations
59 byte[] blen = (Integer.toString(incoming.length)).getBytes();
60 * next line takes 285ms for 100,000 iterations
61 byte[] blen = int2byte (incoming.length);
62 </pre>
63 */
64 public HttpOKResponse (Request request, byte[] incoming, long fileupdatetime){
65 // Need to find a more decent way of doing this withuot
66 // getting into Strings and other voracious objects.
67 // NEXT LINE IS VERY FAST, THE INTEGER THING SLOWS IT DOWN
68 //byte[] blen = new byte[]{(byte)'1',(byte)'6'};
69 //byte[] blen = (Integer.toString(incoming.length)).getBytes();
70 byte[] blen = NioUtil.int2byte (incoming.length);
71
72 // 8 for 4 CRLFs
73 this.content = new byte[incoming.length+header.length+8+blen.length+ 2 + LAST_MODIFIED_HEADER_SIZE];
74 System.arraycopy(header, 0, content, 0, header.length);
75
76 // print length of document
77 int j = header.length;
78 for( int i = 0; i < blen.length; i++ , j++){
79 content[j]=blen[i];
80
81 }
82 content[j++] = (byte)'\r';
83 content[j++] = (byte)'\n';
84
85 System.arraycopy(LAST_MODIFIED, 0, content, j, LAST_MODIFIED.length);
86 j+= LAST_MODIFIED.length;
87
88 SimpleDateFormat fo =
89 new SimpleDateFormat ("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
90 fo.setTimeZone(TimeZone.getTimeZone("GMT"));
91
92 byte[] tmpdate = (fo.format(new java.util.Date(fileupdatetime))).getBytes();
93 System.arraycopy(tmpdate, 0, content, j, DATE_SIZE);
94 j+= DATE_SIZE;
95
96 // header is over
97 content[j++] = (byte)'\r';
98 content[j++] = (byte)'\n';
99 content[j++] = (byte)'\r';
100 content[j++] = (byte)'\n';
101 System.arraycopy(incoming, 0, content, j, incoming.length);
102 j+= incoming.length;
103 content[j++] = (byte)'\r';
104 content[j++] = (byte)'\n';
105 content[j++] = (byte)'\r';
106 content[j++] = (byte)'\n';
107
108 }
109 public HttpOKResponse (Request request, String incoming){
110 sb = new StringBuffer(sheader).append(incoming.length())
111 .append(CRLF2).append(incoming).append(CRLF2);
112 //this.content = new byte[incoming.length()+header.length+8+10];
113 //System.arraycopy(header, 0, content, 0, header.length);
114 //System.arraycopy(sb.toString().getBytes(), 0, content, header.length , sb.length());
115 }
116
117 /** return as a stream of bytes.
118 * preferred since we can use bytes
119 * throughout and avoid costly string to byte conversions.
120 */
121 public byte[] getBytes(){
122 if (this.content == null)
123 this.content = sb.toString().getBytes();
124 return this.content;
125 }
126 /** return content as a String.
127 * to start with we use this. this does a conversion 3 times, so
128 * avoid. */
129 public String getString(){
130 if (sb == null)
131 return new String(content);
132 return sb.toString();
133 }
134 public static final String P="HttpOKResponse";
135
136 public static void main (String args[]){
137
138 System.out.println( "--string cons--------");
139 HttpOKResponse ok = new HttpOKResponse(null, "Hello There Boys");
140 System.out.println( ok.getString());
141 String s1 = ok.getString();
142 System.out.println( "-As Bytes:");
143 System.out.println( ok.getBytes());
144 byte[] b1 = ok.getBytes();
145 System.out.println( "----------");
146 System.out.println( "-- byte cons--------");
147 ok = new HttpOKResponse(null, "Hello There Boys".getBytes(), 0);
148 System.out.println( ok.getString());
149 String s2 = ok.getString();
150 System.out.println( "-As Bytes:");
151 System.out.println( ok.getBytes());
152 byte[] b2 = ok.getBytes();
153 System.out.println( "s2 eq s1:"+s2.equals(s1));
154 System.out.println( "Length:"+s1.length()+","+s2.length());
155 System.out.println( "BLength:"+b1.length+","+b2.length);
156 if (!s2.equals(s1)){
157 System.out.println( ">>>>:"+s2.compareTo(s1));
158 for( int i = 0; i < s1.length(); i++ ){
159 if (s1.charAt(i) != s2.charAt(i)){ System.out.print( i+" not equal!");
160 System.out.println( "["+s1.charAt(i) + "]:["+ s2.charAt(i)+ "]" );
161 }
162 }
163 System.out.println( "---");
164
165 }
166 for( int i = 0; i < s1.length(); i++ ){
167 if (b1[i] != b2[i]) System.out.println( i+" not equal!");
168 }
169 long start = System.currentTimeMillis();
170 for( int j = 0; j < 100000; j++ ){
171 ok = new HttpOKResponse(null, "Hello There Boys");
172 }
173 long finish = System.currentTimeMillis();
174 System.out.println( "time:"+ (finish-start));
175
176 start = System.currentTimeMillis();
177 byte b3[] = "Hello There Boys".getBytes();
178 for( int j = 0; j < 100000; j++ ){
179 ok = new HttpOKResponse(null, b3, 0);
180 }
181 finish = System.currentTimeMillis();
182 System.out.println( "time:"+ (finish-start));
183
184 }
185
186
187 } // end of class