00001
package com.quadcap.http.server22;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
import java.util.Calendar;
00042
import java.util.Date;
00043
import java.util.Enumeration;
00044
import java.util.Hashtable;
00045
import java.util.Locale;
00046
import java.util.TimeZone;
00047
import java.util.Vector;
00048
00049
import java.text.DateFormat;
00050
import java.text.SimpleDateFormat;
00051
00052
import java.io.ByteArrayOutputStream;
00053
import java.io.IOException;
00054
import java.io.OutputStream;
00055
import java.io.OutputStreamWriter;
00056
import java.io.PrintWriter;
00057
00058
import javax.servlet.ServletOutputStream;
00059
import javax.servlet.http.Cookie;
00060
import javax.servlet.http.HttpServletResponse;
00061
00062
import com.quadcap.net.server.WorkerOutputStream;
00063
00064
import com.quadcap.util.Debug;
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 public class HttpResponse implements HttpServletResponse {
00075 WebWorker w;
00076 Hashtable
headers =
new Hashtable();
00077 String
protocol;
00078 int sc = SC_OK;
00079 String
sm =
"Request Completed";
00080 boolean changedCode =
false;
00081 Locale
defaultLocale = Locale.getDefault();
00082 Locale
locale =
defaultLocale;
00083
00084 int contentLength = -1;
00085 String
contentType = null;
00086 StringBuffer
headerBuf =
new StringBuffer();
00087 boolean headerBufValid =
true;
00088 boolean anyHeaders =
false;
00089 boolean keepAlive =
false;
00090 public boolean getWriterCalled =
false;
00091 public boolean getOutputStreamCalled =
false;
00092
00093 byte[]
fixedHeaders = null;
00094 ByteArrayOutputStream
fixedH =
new ByteArrayOutputStream();
00095
00096 HttpOutputStream os;
00097 PrintWriter
writer = null;
00098 JspWriter jWriter =
new JspWriter(8192,
true);
00099 boolean jWriterInit =
false;
00100
00101 Vector
cookies = null;
00102 long calbase = -1;
00103 byte[]
curTime = null;
00104
00105 static DateFormat
cookieDateFormat;
00106 static TimeZone
GMT;
00107 static SimpleDateFormat
df;
00108 static SimpleDateFormat
df2;
00109
00110
static {
00111
GMT = TimeZone.getTimeZone(
"GMT");
00112
cookieDateFormat =
new SimpleDateFormat(
"E, dd-MMM-yy HH:mm:ss 'GMT'");
00113
cookieDateFormat.setTimeZone(
GMT);
00114
df =
new SimpleDateFormat(
"'Date: 'EEE, dd MMM yyyy HH:mm:ss 'GMT\r\n'");
00115
df.setTimeZone(
GMT);
00116
df2 =
new SimpleDateFormat(
"EEE, dd MMM yyyy HH:mm:ss 'GMT'");
00117
df2.setTimeZone(
GMT);
00118 }
00119
00120
00121
00122
00123
00124
00125 public HttpResponse(
WebWorker w) {
00126
this.w = w;
00127 }
00128
00129 public void reset(
HttpOutputStream os) {
00130
this.os = os;
00131
this.
os.setResponse(
this);
00132
headers.clear();
00133
sc = SC_OK;
00134
jWriterInit =
false;
00135
sm =
"Request Completed";
00136
changedCode =
false;
00137
locale =
defaultLocale;
00138
contentLength = -1;
00139
contentType = null;
00140
headerBuf.setLength(0);
00141
headerBufValid =
true;
00142
writer = null;
00143
cookies = null;
00144
anyHeaders =
false;
00145
getWriterCalled =
false;
00146
getOutputStreamCalled =
false;
00147 }
00148
00149 void setProtocol(String p) {
00150
this.protocol = p;
00151 }
00152
00153 void setKeepAlive(
boolean v) {
00154
this.keepAlive = v;
00155 }
00156
00157 static final void write(OutputStream out, String s)
throws IOException {
00158
for (
int i = 0; i < s.length(); i++) {
00159 out.write((byte)s.charAt(i));
00160 }
00161 }
00162
00163 static final byte[]
headerSep = { (byte)
':', (byte)
' ' };
00164 static final byte[]
CRLF = { (byte)
'\r', (byte)
'\n' };
00165 static final byte[]
OKRESPONSE =
00166
" 200 Request Completed\r\n".getBytes();
00167 static final byte[]
CONTENT_TYPE =
"Content-Type: ".getBytes();
00168 static final byte[]
CONTENT_LENGTH =
"Content-Length: ".getBytes();
00169 static final byte[]
CONNECTION_KEEPALIVE =
00170
"Connection: Keep-Alive\r\n".getBytes();
00171 static final byte[]
CONNECTION_CLOSE =
00172
"Connection: Close\r\n".getBytes();
00173 static final byte[]
DEFAULT_CONTENT_TYPE =
00174
"Content-Type: text/plain\r\n".getBytes();
00175
00176 final void writeHeader(
WorkerOutputStream out, String name, String val)
00177
throws IOException
00178 {
00179
00180
if (
Trace.level() > 1) {
00181
Debug.println(
"header: " + name +
": " + val);
00182 }
00183
00184 out.write(name);
00185 out.write(
headerSep);
00186 out.write(val);
00187 out.write(
CRLF);
00188 }
00189
00190
00191
00192
00193 public void writeHeaders() throws IOException {
00194
WorkerOutputStream out =
os.
getOutputStream();
00195 out.
write(
protocol);
00196
if (
changedCode) {
00197 out.
write(
' ');
00198 out.
writeInt(
sc);
00199 out.
write(
' ');
00200 out.
write(
sm);
00201 out.
write(
CRLF);
00202 }
else {
00203 out.
write(
OKRESPONSE);
00204 }
00205
00206
if (
keepAlive) {
00207 out.
write(
CONNECTION_KEEPALIVE);
00208 }
else {
00209 out.
write(
CONNECTION_CLOSE);
00210 }
00211
00212
if (
contentType != null) {
00213 out.
write(
CONTENT_TYPE);
00214 out.
write(
contentType);
00215 out.
write(
CRLF);
00216 }
else {
00217 out.
write(
DEFAULT_CONTENT_TYPE);
00218 }
00219
00220
if (
contentLength >= 0) {
00221 out.
write(
CONTENT_LENGTH);
00222 out.
writeInt(
contentLength);
00223 out.
write(
CRLF);
00224 }
00225
if (
fixedHeaders == null) {
00226
if (
fixedH != null) {
00227
fixedHeaders =
fixedH.toByteArray();
00228
fixedH = null;
00229 }
00230 out.
write(
fixedHeaders);
00231 }
00232
00233
if (
headerBufValid) {
00234 out.
write(
headerBuf.toString());
00235 }
else if (
anyHeaders) {
00236 Enumeration hdrs =
headers.keys();
00237
while (hdrs.hasMoreElements()) {
00238 String headerName = (String)hdrs.nextElement();
00239 Object headerVal =
headers.get(headerName);
00240
if (headerVal instanceof String) {
00241 writeHeader(out, headerName, headerVal.toString());
00242 }
else {
00243 Vector v = (Vector)headerVal;
00244
for (
int i = 0; i < v.size(); i++) {
00245 writeHeader(out, headerName, v.elementAt(i).toString());
00246 }
00247 }
00248 }
00249 }
00250
00251
if (
cookies != null) {
00252
writeCookies(out);
00253 }
00254
writeDateHeader(out);
00255 out.
write(
CRLF);
00256 }
00257
00258 static byte[]
digits =
"0123456789".getBytes();
00259 static byte[]
GMTString =
" GMT\r\n".getBytes();
00260
00261 final void writeDateHeader(
WorkerOutputStream out)
throws IOException {
00262
long now = System.currentTimeMillis();
00263
long msec = now -
calbase;
00264
if (msec >= 60000) {
00265 Calendar c = Calendar.getInstance(
GMT);
00266 c.setTime(
new Date(now));
00267 c.set(Calendar.SECOND, 0);
00268 c.set(Calendar.MILLISECOND, 0);
00269 Date d = c.getTime();
00270 calbase = d.getTime();
00271
curTime =
df.format(d).getBytes();
00272 msec = now - calbase;
00273
if (msec < 0) msec = 0;
00274 }
00275
int sec = (
int)(msec / 1000);
00276
curTime[29] =
digits[sec / 10];
00277
curTime[30] = digits[sec % 10];
00278 out.write(
curTime);
00279 }
00280
00281 void writeAttr(
WorkerOutputStream out, String name, String val)
00282
throws IOException
00283 {
00284
if (val != null) {
00285 out.write(
';');
00286 out.write(name);
00287 out.write(
'=');
00288 out.write(val);
00289 }
00290 }
00291
00292
00293 private static final String
tspecials =
"()<>@,;:\\\"/[]?={} \t";
00294
00295
00296
00297
00298 private static boolean isToken (String value) {
00299
final int len = value.length();
00300
00301
for (
int i = 0; i < len; i++) {
00302
char c = value.charAt(i);
00303
if (c < 0x20 || c >= 0x7f ||
tspecials.indexOf(c) != -1)
00304
return false;
00305 }
00306
return true;
00307 }
00308
00309 private final void writeTok(
WorkerOutputStream out, String val,
int v)
00310
throws IOException
00311 {
00312
if (v == 0 || isToken(val)) {
00313 out.write(val);
00314 }
else {
00315 out.write(
'"');
00316 out.write(val);
00317 out.write(
'"');
00318 }
00319 }
00320
00321 void writeCookies(
WorkerOutputStream out)
throws IOException {
00322 out.write(
"Set-Cookie: ");
00323
for (
int i = 0; i <
cookies.size(); i++) {
00324 Cookie cookie = (Cookie)
cookies.elementAt(i);
00325
final int version = cookie.getVersion();
00326
if (i > 0) out.write(
'\t');
00327 out.write(cookie.getName());
00328 String val = cookie.getValue();
00329
if (val != null) {
00330 out.write(
'=');
00331 writeTok(out, val, version);
00332 }
00333
00334 writeAttr(out,
"Path", cookie.getPath());
00335
if (version == 0) {
00336 writeAttr(out,
"Domain", cookie.getDomain());
00337
if (cookie.getMaxAge() >= 0) {
00338 Date d =
new Date();
00339
long ms = d.getTime() + cookie.getMaxAge() * 1000;
00340 d.setTime(ms);
00341 writeAttr(out,
"Expires",
00342
cookieDateFormat.format(d));
00343 }
00344 }
else {
00345 out.write(
";Version=1");
00346 out.write(
";Domain=");
00347 writeTok(out, cookie.getDomain(), version);
00348
if (cookie.getMaxAge() >= 0) {
00349 writeAttr(out,
"Max-Age",
"" + cookie.getMaxAge());
00350 }
else {
00351 out.write(
";Discard");
00352 }
00353 writeAttr(out,
"Comment", cookie.getComment());
00354 }
00355
if (cookie.getSecure()) out.write(
";Ssecure");
00356 out.write(
CRLF);
00357 }
00358 }
00359
00360 final void setFixedHeader(String name, String val) {
00361
try {
00362 write(
fixedH, name);
00363 write(
fixedH,
": ");
00364 write(
fixedH, val);
00365
fixedH.write(
CRLF);
00366 }
catch (Exception e) {}
00367 }
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 public void setContentLength(
int len) {
00379
contentLength = len;
00380 }
00381
00382 final void maybeSetContentLength(
int len) {
00383
if (
contentLength == -1) {
00384
contentLength = len;
00385 }
00386 }
00387
00388 int getContentLength() {
return contentLength; }
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 public void setContentType(String type) {
00406
contentType = type;
00407 }
00408
00409
00410
00411
00412
00413
00414
00415
00416 public ServletOutputStream
getOutputStream() throws IOException {
00417
if (
getWriterCalled) {
00418
throw new IllegalStateException(
"getWriter() already called");
00419 }
00420
getOutputStreamCalled =
true;
00421
return os;
00422 }
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438 public PrintWriter
getWriter() throws IOException {
00439
if (
getOutputStreamCalled) {
00440
throw new
00441 IllegalStateException(
"getOutputStream() already called");
00442 }
00443
if (
writer == null) {
00444 String encoding =
getCharacterEncoding();
00445 OutputStreamWriter ww = null;
00446 OutputStream
os =
getOutputStream();
00447
if (encoding != null) {
00448 ww =
new OutputStreamWriter(os, encoding);
00449 }
else {
00450 ww =
new OutputStreamWriter(os);
00451 }
00452
writer =
new PrintWriter(ww);
00453
getWriterCalled =
true;
00454 }
00455
return writer;
00456 }
00457
00458 public JspWriter
getJspWriter(
int bufferSize,
boolean autoFlush)
00459
throws IOException
00460 {
00461
if (!
jWriterInit) {
00462
jWriterInit =
true;
00463
jWriter.
setHttpOutputStream(
os);
00464
jWriter.
setBufferSize(bufferSize);
00465
jWriter.
setAutoFlush(autoFlush);
00466 }
00467
return jWriter;
00468 }
00469
00470
00471
00472
00473
00474
00475
00476
00477 public String
getCharacterEncoding () {
00478 String s =
contentType;
00479
if (s == null)
return null;
00480
00481
int idx = s.indexOf(
';');
00482
while (idx > 0) {
00483 s = s.substring(idx+1).trim();
00484 idx = s.indexOf(
';');
00485 String c = s;
00486
if (idx > 0) {
00487 c = s.substring(0, idx).trim();
00488 }
00489
if (c.startsWith(
"charset=")) {
00490
return c.substring(8);
00491 }
00492 }
00493
return null;
00494 }
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507 public void addCookie(Cookie cookie) {
00508
00509
if (
Trace.level() > 7) {
00510
Debug.println(
"addCookie(" + cookie +
")");
00511 }
00512
00513
if (
cookies == null) {
00514
cookies =
new Vector();
00515 }
00516
cookies.addElement(cookie);
00517 }
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 public boolean containsHeader(String name) {
00528
return headers.get(name) != null;
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542 public void setStatus(
int sc, String sm) {
00543
this.changedCode =
true;
00544
this.sc = sc;
00545
this.sm = sm;
00546 }
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 public void setStatus(
int sc) {
00559
this.changedCode =
true;
00560
this.sc = sc;
00561
this.sm =
"";
00562 }
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576 public void setHeader(String name, String value) {
00577
if (name.charAt(0) ==
'C') {
00578
if (name.equals(
"Content-Type")) {
00579
contentType = value;
00580
return;
00581 }
else if (name.equals(
"Content-Length")) {
00582
contentLength = Integer.parseInt(value);
00583
return;
00584 }
00585 }
00586
if (
headerBufValid) {
00587
if (
headers.get(name) == null) {
00588
appendHeader(name, value);
00589 }
else {
00590
headerBufValid =
false;
00591 }
00592 }
00593
anyHeaders =
true;
00594
headers.put(name, value);
00595 }
00596
00597 final void appendHeader(String name, String value) {
00598
headerBuf.append(name);
00599
headerBuf.append(
": ");
00600
headerBuf.append(value);
00601
headerBuf.append(
"\r\n");
00602 }
00603
00604
00605
00606
00607
00608 public void addHeader(String name, String value) {
00609 Object obj =
headers.get(name);
00610 Vector v = null;
00611
boolean mustInsert =
true;
00612
if (obj instanceof String) {
00613 v =
new Vector();
00614 v.addElement(obj.toString());
00615 }
else if (obj == null) {
00616 v =
new Vector();
00617 }
else {
00618 v = (Vector)obj;
00619 mustInsert =
false;
00620 }
00621 v.addElement(value);
00622
if (mustInsert) {
00623
anyHeaders =
true;
00624
headers.put(name, v);
00625 }
00626 appendHeader(name, value);
00627 }
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641 public void setIntHeader(String name,
int value) {
00642 setHeader(name,
"" + value);
00643 }
00644
00645 public void addIntHeader(String name,
int value) {
00646 addHeader(name,
"" + value);
00647 }
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662 public void setDateHeader(String name,
long date) {
00663 Date d =
new Date(date);
00664 setHeader(name,
df2.format(d));
00665 }
00666
00667 public void addDateHeader(String name,
long date) {
00668 Date d =
new Date(date);
00669 addHeader(name,
df2.format(d));
00670 }
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684 public void sendError(
int scode, String msg)
throws IOException {
00685 setStatus(scode, msg);
00686
if (
os.
discard()) {
00687
writer = null;
00688 }
00689
getWriterCalled =
getOutputStreamCalled =
false;
00690 setContentType(
"text/html");
00691 PrintWriter p =
getWriter();
00692 p.println(
"<HEAD><TITLE>" + scode +
" " + msg +
"</TITLE></HEAD>");
00693 p.print(
"<BODY><H1>");
00694 p.print(msg);
00695 p.println(
"</H1>");
00696
if (scode == HttpServletResponse.SC_NOT_FOUND) {
00697 p.print(
"The requested URL was not found on this server");
00698 p.println(
"<P>");
00699 }
00700 p.println(
"</BODY>");
00701
flush();
00702 }
00703
00704
00705
00706
00707
00708
00709
00710 public void sendError(
int scode)
throws IOException {
00711
sm =
"Error " + scode;
00712 setStatus(scode);
00713
if (
os.
discard()) {
00714
writer = null;
00715 }
00716
getWriterCalled =
getOutputStreamCalled =
false;
00717 PrintWriter p =
getWriter();
00718 p.println(
"<html><head><title>" +
sm +
"</title></head>");
00719 p.println(
"<body>");
00720 p.println(
sm);
00721 p.println(
"</body></html>");
00722
flush();
00723 }
00724
00725
00726
00727
00728 void flush() throws IOException {
00729
if (
writer != null)
writer.flush();
00730
os.
flush();
00731 }
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742 public void sendRedirect(String location)
throws IOException {
00743 setHeader(
"Location", location);
00744 sendError(SC_MOVED_TEMPORARILY,
00745
"<a href=\"" + location +
"\">" + location +
"</A>");
00746 }
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764 public String
encodeUrl (String url) {
00765
return url;
00766 }
00767 public String
encodeURL(String url) {
00768
return url;
00769 }
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791 public String
encodeRedirectUrl (String url) {
00792
return url;
00793 }
00794 public String
encodeRedirectURL(String url) {
00795
return url;
00796 }
00797
00798 public void flushBuffer() throws IOException {
00799
if (
writer != null)
writer.flush();
00800
os.
flushBuffered();
00801 }
00802
00803 public void setBufferSize(
int size)
throws IllegalStateException {
00804
os.
setBufferSize(size);
00805 }
00806
00807 public int getBufferSize() {
00808
return os.
getBufferSize();
00809 }
00810
00811 public boolean isCommitted() {
00812
return os.
isCommitted();
00813 }
00814
00815 public void reset() throws IllegalStateException {
00816
os.
reset();
00817
sc = SC_OK;
00818
headers.clear();
00819
sm =
"Request Completed";
00820
changedCode =
false;
00821
locale =
defaultLocale;
00822
contentLength = -1;
00823
contentType = null;
00824
headerBuf.setLength(0);
00825
headerBufValid =
true;
00826
writer = null;
00827
cookies = null;
00828
anyHeaders =
false;
00829
getWriterCalled =
false;
00830
jWriterInit =
false;
00831
getOutputStreamCalled =
false;
00832 }
00833
00834 public void setLocale(Locale locale) {
00835
this.locale = locale;
00836
if (locale != null) {
00837 String lang = locale.getLanguage();
00838
if (lang != null) {
00839 setHeader(
"Content-Language", lang);
00840 }
00841 }
00842
00843 }
00844
00845 public Locale
getLocale() {
00846
return locale;
00847 }
00848 }