2
* Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
3
* Distributed under the terms of either:
4
* - the common development and distribution license (CDDL), v1.0; or
5
* - the GNU Lesser General Public License, v2.1 or later
9
import java.io.IOException;
10
import java.io.PrintWriter;
11
import java.io.UnsupportedEncodingException;
12
import java.io.Writer;
13
import java.text.DateFormat;
14
import java.text.SimpleDateFormat;
15
import java.util.ArrayList;
16
import java.util.Date;
17
import java.util.Iterator;
18
import java.util.List;
19
import java.util.Locale;
21
import java.util.StringTokenizer;
22
import java.util.TimeZone;
24
import javax.servlet.ServletOutputStream;
25
import javax.servlet.http.Cookie;
26
import javax.servlet.http.HttpServletResponse;
29
* Response for servlet
31
* @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
32
* @version $Id: WinstoneResponse.java,v 1.28 2005/04/19 07:33:41 rickknowles
35
public class WinstoneResponse implements HttpServletResponse {
36
private static final DateFormat HTTP_DF = new SimpleDateFormat(
37
"EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
38
private static final DateFormat VERSION0_DF = new SimpleDateFormat(
39
"EEE, dd-MMM-yy HH:mm:ss z", Locale.US);
41
HTTP_DF.setTimeZone(TimeZone.getTimeZone("GMT"));
42
VERSION0_DF.setTimeZone(TimeZone.getTimeZone("GMT"));
45
static final String CONTENT_LENGTH_HEADER = "Content-Length";
46
static final String CONTENT_TYPE_HEADER = "Content-Type";
48
// Response header constants
49
private static final String CONTENT_LANGUAGE_HEADER = "Content-Language";
50
private static final String KEEP_ALIVE_HEADER = "Connection";
51
private static final String KEEP_ALIVE_OPEN = "Keep-Alive";
52
private static final String KEEP_ALIVE_CLOSE = "Close";
53
private static final String DATE_HEADER = "Date";
54
private static final String LOCATION_HEADER = "Location";
55
private static final String OUT_COOKIE_HEADER1 = "Set-Cookie";
56
private static final String X_POWERED_BY_HEADER = "X-Powered-By";
57
private static final String X_POWERED_BY_HEADER_VALUE = Launcher.RESOURCES.getString("PoweredByHeader");
59
private int statusCode;
60
private WinstoneRequest req;
61
private WebAppConfiguration webAppConfig;
62
private WinstoneOutputStream outputStream;
63
private PrintWriter outputWriter;
66
private String explicitEncoding;
67
private String implicitEncoding;
70
private Locale locale;
71
private String protocol;
72
private String reqKeepAliveHeader;
73
private Integer errorStatusCode;
78
public WinstoneResponse() {
80
this.headers = new ArrayList();
81
this.cookies = new ArrayList();
83
this.statusCode = SC_OK;
84
this.locale = null; //Locale.getDefault();
85
this.explicitEncoding = null;
87
this.reqKeepAliveHeader = null;
91
* Resets the request to be reused
93
public void cleanUp() {
95
this.webAppConfig = null;
96
this.outputStream = null;
97
this.outputWriter = null;
100
this.protocol = null;
101
this.reqKeepAliveHeader = null;
103
this.statusCode = SC_OK;
104
this.errorStatusCode = null;
105
this.locale = null; //Locale.getDefault();
106
this.explicitEncoding = null;
107
this.implicitEncoding = null;
110
private String getEncodingFromLocale(Locale loc) {
111
String localeString = loc.getLanguage() + "_" + loc.getCountry();
112
Map encMap = this.webAppConfig.getLocaleEncodingMap();
113
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
114
"WinstoneResponse.LookForLocaleEncoding",
115
new String[] {localeString, encMap + ""});
117
String fullMatch = (String) encMap.get(localeString);
118
if (fullMatch != null) {
119
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
120
"WinstoneResponse.FoundLocaleEncoding", fullMatch);
123
localeString = loc.getLanguage();
124
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
125
"WinstoneResponse.LookForLocaleEncoding",
126
new String[] {localeString, encMap + ""});
127
String match = (String) encMap.get(localeString);
129
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
130
"WinstoneResponse.FoundLocaleEncoding", match);
136
public void setErrorStatusCode(int statusCode) {
137
this.errorStatusCode = new Integer(statusCode);
138
this.statusCode = statusCode;
141
public WinstoneOutputStream getWinstoneOutputStream() {
142
return this.outputStream;
145
public void setOutputStream(WinstoneOutputStream outData) {
146
this.outputStream = outData;
149
public void setWebAppConfig(WebAppConfiguration webAppConfig) {
150
this.webAppConfig = webAppConfig;
153
public String getProtocol() {
154
return this.protocol;
157
public void setProtocol(String protocol) {
158
this.protocol = protocol;
161
public void extractRequestKeepAliveHeader(WinstoneRequest req) {
162
this.reqKeepAliveHeader = req.getHeader(KEEP_ALIVE_HEADER);
165
public List getHeaders() {
169
public List getCookies() {
173
public WinstoneRequest getRequest() {
177
public void setRequest(WinstoneRequest req) {
181
public void startIncludeBuffer() {
182
this.outputStream.startIncludeBuffer();
185
public void finishIncludeBuffer() throws IOException {
187
if (this.outputWriter != null) {
188
this.outputWriter.flush();
190
this.outputStream.finishIncludeBuffer();
194
public void clearIncludeStackForForward() throws IOException {
195
this.outputStream.clearIncludeStackForForward();
198
protected static String getCharsetFromContentTypeHeader(String type, StringBuffer remainder) {
202
// Parse type to set encoding if needed
203
StringTokenizer st = new StringTokenizer(type, ";");
204
String localEncoding = null;
205
while (st.hasMoreTokens()) {
206
String clause = st.nextToken().trim();
207
if (clause.startsWith("charset="))
208
localEncoding = clause.substring(8);
210
if (remainder.length() > 0) {
211
remainder.append(";");
213
remainder.append(clause);
216
if ((localEncoding == null) ||
217
!localEncoding.startsWith("\"") ||
218
!localEncoding.endsWith("\"")) {
219
return localEncoding;
221
return localEncoding.substring(1, localEncoding.length() - 1);
226
* This ensures the bare minimum correct http headers are present
228
public void validateHeaders() {
229
// Need this block for WebDAV support. "Connection:close" header is ignored
230
String lengthHeader = getHeader(CONTENT_LENGTH_HEADER);
231
if ((lengthHeader == null) && (this.statusCode >= 300)) {
232
int bodyBytes = this.outputStream.getOutputStreamLength();
233
if (getBufferSize() > bodyBytes) {
234
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
235
"WinstoneResponse.ForcingContentLength", "" + bodyBytes);
236
forceHeader(CONTENT_LENGTH_HEADER, "" + bodyBytes);
237
lengthHeader = getHeader(CONTENT_LENGTH_HEADER);
241
forceHeader(KEEP_ALIVE_HEADER, !closeAfterRequest() ? KEEP_ALIVE_OPEN : KEEP_ALIVE_CLOSE);
242
String contentType = getHeader(CONTENT_TYPE_HEADER);
243
if (this.statusCode != SC_MOVED_TEMPORARILY) {
244
if (contentType == null) {
245
// Bypass normal encoding
246
forceHeader(CONTENT_TYPE_HEADER, "text/html;charset=" + getCharacterEncoding());
247
} else if (contentType.startsWith("text/")) {
248
// replace charset in content
249
StringBuffer remainder = new StringBuffer();
250
getCharsetFromContentTypeHeader(contentType, remainder);
251
forceHeader(CONTENT_TYPE_HEADER, remainder.toString() + ";charset=" + getCharacterEncoding());
254
if (getHeader(DATE_HEADER) == null) {
255
forceHeader(DATE_HEADER, formatHeaderDate(new Date()));
257
if (getHeader(X_POWERED_BY_HEADER) == null) {
258
forceHeader(X_POWERED_BY_HEADER, X_POWERED_BY_HEADER_VALUE);
260
if (this.locale != null) {
261
String lang = this.locale.getLanguage();
262
if ((this.locale.getCountry() != null) && !this.locale.getCountry().equals("")) {
263
lang = lang + "-" + this.locale.getCountry();
265
forceHeader(CONTENT_LANGUAGE_HEADER, lang);
268
// If we don't have a webappConfig, exit here, cause we definitely don't
270
if (req.getWebAppConfig() == null) {
273
// Write out the new session cookie if it's present
274
HostConfiguration hostConfig = req.getHostGroup().getHostByName(req.getServerName());
275
for (Iterator i = req.getCurrentSessionIds().keySet().iterator(); i.hasNext(); ) {
276
String prefix = (String) i.next();
277
String sessionId = (String) req.getCurrentSessionIds().get(prefix);
278
WebAppConfiguration ownerContext = hostConfig.getWebAppByURI(prefix);
279
if (ownerContext != null) {
280
WinstoneSession session = ownerContext.getSessionById(sessionId, true);
281
if ((session != null) && session.isNew()) {
282
session.setIsNew(false);
283
Cookie cookie = new Cookie(WinstoneSession.SESSION_COOKIE_NAME, session.getId());
284
cookie.setMaxAge(-1);
285
cookie.setSecure(req.isSecure());
286
cookie.setVersion(0); //req.isSecure() ? 1 : 0);
287
cookie.setPath(req.getWebAppConfig().getContextPath().equals("") ? "/"
288
: req.getWebAppConfig().getContextPath());
289
this.cookies.add(cookie); // don't call addCookie because we might be including
294
// Look for expired sessions: ie ones where the requested and current ids are different
295
for (Iterator i = req.getRequestedSessionIds().keySet().iterator(); i.hasNext(); ) {
296
String prefix = (String) i.next();
297
String sessionId = (String) req.getRequestedSessionIds().get(prefix);
298
if (!req.getCurrentSessionIds().containsKey(prefix)) {
299
Cookie cookie = new Cookie(WinstoneSession.SESSION_COOKIE_NAME, sessionId);
300
cookie.setMaxAge(0); // explicitly expire this cookie
301
cookie.setSecure(req.isSecure());
302
cookie.setVersion(0); //req.isSecure() ? 1 : 0);
303
cookie.setPath(prefix.equals("") ? "/" : prefix);
304
this.cookies.add(cookie); // don't call addCookie because we might be including
308
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.HeadersPreCommit",
313
* Writes out the http header for a single cookie
315
public String writeCookie(Cookie cookie) throws IOException {
317
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.WritingCookie", cookie + "");
318
StringBuffer out = new StringBuffer();
320
// Set-Cookie or Set-Cookie2
321
if (cookie.getVersion() >= 1)
322
out.append(OUT_COOKIE_HEADER1).append(": "); // TCK doesn't like set-cookie2
324
out.append(OUT_COOKIE_HEADER1).append(": ");
327
if (cookie.getVersion() == 0)
328
out.append(cookie.getName()).append("=").append(cookie.getValue());
330
out.append(cookie.getName()).append("=");
331
quote(cookie.getValue(), out);
334
if (cookie.getVersion() >= 1) {
335
out.append("; Version=1");
336
if (cookie.getDomain() != null) {
337
out.append("; Domain=");
338
quote(cookie.getDomain(), out);
340
if (cookie.getSecure())
341
out.append("; Secure");
343
if (cookie.getMaxAge() >= 0)
344
out.append("; Max-Age=").append(cookie.getMaxAge());
346
out.append("; Discard");
347
if (cookie.getPath() != null) {
348
out.append("; Path=");
349
quote(cookie.getPath(), out);
352
if (cookie.getDomain() != null) {
353
out.append("; Domain=");
354
out.append(cookie.getDomain());
356
if (cookie.getMaxAge() > 0) {
357
long expiryMS = System.currentTimeMillis()
358
+ (1000 * (long) cookie.getMaxAge());
359
String expiryDate = null;
360
synchronized (VERSION0_DF) {
361
expiryDate = VERSION0_DF.format(new Date(expiryMS));
363
out.append("; Expires=").append(expiryDate);
364
} else if (cookie.getMaxAge() == 0) {
365
String expiryDate = null;
366
synchronized (VERSION0_DF) {
367
expiryDate = VERSION0_DF.format(new Date(5000));
369
out.append("; Expires=").append(expiryDate);
371
if (cookie.getPath() != null)
372
out.append("; Path=").append(cookie.getPath());
373
if (cookie.getSecure())
374
out.append("; Secure");
376
return out.toString();
379
private static String formatHeaderDate(Date dateIn) {
381
synchronized (HTTP_DF) {
382
date = HTTP_DF.format(dateIn);
388
* Quotes the necessary strings in a cookie header. The quoting is only
389
* applied if the string contains special characters.
391
protected static void quote(String value, StringBuffer out) {
392
if (value.startsWith("\"") && value.endsWith("\"")) {
395
boolean containsSpecial = false;
396
for (int n = 0; n < value.length(); n++) {
397
char thisChar = value.charAt(n);
398
if ((thisChar < 32) || (thisChar >= 127)
399
|| (specialCharacters.indexOf(thisChar) != -1)) {
400
containsSpecial = true;
405
out.append('"').append(value).append('"');
411
private static final String specialCharacters = "()<>@,;:\\\"/[]?={} \t";
414
* Based on request/response headers and the protocol, determine whether or
415
* not this connection should operate in keep-alive mode.
417
public boolean closeAfterRequest() {
418
String inKeepAliveHeader = this.reqKeepAliveHeader;
419
String outKeepAliveHeader = getHeader(KEEP_ALIVE_HEADER);
420
boolean hasContentLength = (getHeader(CONTENT_LENGTH_HEADER) != null);
421
if (this.protocol.startsWith("HTTP/0"))
423
else if ((inKeepAliveHeader == null) && (outKeepAliveHeader == null))
424
return this.protocol.equals("HTTP/1.0") ? true : !hasContentLength;
425
else if (outKeepAliveHeader != null)
426
return outKeepAliveHeader.equalsIgnoreCase(KEEP_ALIVE_CLOSE) || !hasContentLength;
427
else if (inKeepAliveHeader != null)
428
return inKeepAliveHeader.equalsIgnoreCase(KEEP_ALIVE_CLOSE) || !hasContentLength;
433
// ServletResponse interface methods
434
public void flushBuffer() throws IOException {
435
if (this.outputWriter != null) {
436
this.outputWriter.flush();
439
this.outputStream.flush();
440
} catch (ClientSocketException e) {
441
// ignore this error as it's not interesting enough to log
445
public void setBufferSize(int size) {
446
this.outputStream.setBufferSize(size);
449
public int getBufferSize() {
450
return this.outputStream.getBufferSize();
453
public String getCharacterEncoding() {
454
String enc = getCurrentEncoding();
455
return (enc == null ? "ISO-8859-1" : enc);
458
public void setCharacterEncoding(String encoding) {
459
if ((this.outputWriter == null) && !isCommitted()) {
460
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.SettingEncoding", encoding);
461
this.explicitEncoding = encoding;
462
correctContentTypeHeaderEncoding(encoding);
466
private void correctContentTypeHeaderEncoding(String encoding) {
467
String contentType = getContentType();
468
if (contentType != null) {
469
StringBuffer remainderHeader = new StringBuffer();
470
getCharsetFromContentTypeHeader(contentType, remainderHeader);
471
if (remainderHeader.length() != 0) {
472
forceHeader(CONTENT_TYPE_HEADER, remainderHeader + ";charset=" + encoding);
477
public String getContentType() {
478
return getHeader(CONTENT_TYPE_HEADER);
481
public void setContentType(String type) {
482
setHeader(CONTENT_TYPE_HEADER, type);
485
public Locale getLocale() {
486
return this.locale == null ? Locale.getDefault() : this.locale;
489
private boolean isIncluding() {
490
return this.outputStream.isIncluding();
493
public void setLocale(Locale loc) {
496
} else if (isCommitted()) {
497
Logger.log(Logger.WARNING, Launcher.RESOURCES,
498
"WinstoneResponse.SetLocaleTooLate");
500
if ((this.outputWriter == null) && (this.explicitEncoding == null)) {
501
String localeEncoding = getEncodingFromLocale(loc);
502
if (localeEncoding != null) {
503
this.implicitEncoding = localeEncoding;
504
correctContentTypeHeaderEncoding(localeEncoding);
511
public ServletOutputStream getOutputStream() throws IOException {
512
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.GetOutputStream");
513
return this.outputStream;
516
public PrintWriter getWriter() throws IOException {
517
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneResponse.GetWriter");
518
if (this.outputWriter != null)
519
return this.outputWriter;
521
this.outputWriter = new WinstoneResponseWriter(this.outputStream, this);
522
return this.outputWriter;
526
public boolean isCommitted() {
527
return this.outputStream.isCommitted();
530
public void reset() {
531
if (!isIncluding()) {
533
this.statusCode = SC_OK;
534
this.headers.clear();
535
this.cookies.clear();
539
public void resetBuffer() {
540
if (!isIncluding()) {
542
throw new IllegalStateException(Launcher.RESOURCES
543
.getString("WinstoneResponse.ResponseCommitted"));
545
// Disregard any output temporarily while we flush
546
this.outputStream.setDisregardMode(true);
548
if (this.outputWriter != null) {
549
this.outputWriter.flush();
552
this.outputStream.setDisregardMode(false);
553
this.outputStream.reset();
557
public void setContentLength(int len) {
558
setIntHeader(CONTENT_LENGTH_HEADER, len);
561
// HttpServletResponse interface methods
562
public void addCookie(Cookie cookie) {
563
if (!isIncluding()) {
564
this.cookies.add(cookie);
568
public boolean containsHeader(String name) {
569
for (int n = 0; n < this.headers.size(); n++)
570
if (((String) this.headers.get(n)).startsWith(name))
575
public void addDateHeader(String name, long date) {
576
addHeader(name, formatHeaderDate(new Date(date)));
577
} // df.format(new Date(date)));}
579
public void addIntHeader(String name, int value) {
580
addHeader(name, "" + value);
583
public void addHeader(String name, String value) {
585
Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.HeaderInInclude",
586
new String[] {name, value});
587
} else if (isCommitted()) {
588
Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.HeaderAfterCommitted",
589
new String[] {name, value});
590
} else if (value != null) {
591
if (name.equals(CONTENT_TYPE_HEADER)) {
592
StringBuffer remainderHeader = new StringBuffer();
593
String headerEncoding = getCharsetFromContentTypeHeader(value, remainderHeader);
594
if (this.outputWriter != null) {
595
value = remainderHeader + ";charset=" + getCharacterEncoding();
596
} else if (headerEncoding != null) {
597
this.explicitEncoding = headerEncoding;
600
this.headers.add(name + ": " + value);
604
public void setDateHeader(String name, long date) {
605
setHeader(name, formatHeaderDate(new Date(date)));
608
public void setIntHeader(String name, int value) {
609
setHeader(name, "" + value);
612
public void setHeader(String name, String value) {
614
Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.HeaderInInclude",
615
new String[] {name, value});
616
} else if (isCommitted()) {
617
Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneResponse.HeaderAfterCommitted",
618
new String[] {name, value});
620
boolean found = false;
621
for (int n = 0; (n < this.headers.size()); n++) {
622
String header = (String) this.headers.get(n);
623
if (header.startsWith(name + ": ")) {
625
this.headers.remove(n);
628
if (name.equals(CONTENT_TYPE_HEADER)) {
630
StringBuffer remainderHeader = new StringBuffer();
631
String headerEncoding = getCharsetFromContentTypeHeader(
632
value, remainderHeader);
633
if (this.outputWriter != null) {
634
value = remainderHeader + ";charset=" + getCharacterEncoding();
635
} else if (headerEncoding != null) {
636
this.explicitEncoding = headerEncoding;
642
this.headers.set(n, name + ": " + value);
644
this.headers.remove(n);
650
addHeader(name, value);
655
private void forceHeader(String name, String value) {
656
boolean found = false;
657
for (int n = 0; (n < this.headers.size()); n++) {
658
String header = (String) this.headers.get(n);
659
if (header.startsWith(name + ": ")) {
661
this.headers.set(n, name + ": " + value);
665
this.headers.add(name + ": " + value);
669
private String getCurrentEncoding() {
670
if (this.explicitEncoding != null) {
671
return this.explicitEncoding;
672
} else if (this.implicitEncoding != null) {
673
return this.implicitEncoding;
674
} else if ((this.req != null) && (this.req.getCharacterEncoding() != null)) {
676
"0".getBytes(this.req.getCharacterEncoding());
677
return this.req.getCharacterEncoding();
678
} catch (UnsupportedEncodingException err) {
686
public String getHeader(String name) {
687
for (int n = 0; n < this.headers.size(); n++) {
688
String header = (String) this.headers.get(n);
689
if (header.startsWith(name + ": "))
690
return header.substring(name.length() + 2);
695
public String encodeRedirectURL(String url) {
699
public String encodeURL(String url) {
703
public int getStatus() {
704
return this.statusCode;
707
public Integer getErrorStatusCode() {
708
return this.errorStatusCode;
711
public void setStatus(int sc) {
712
if (!isIncluding() && (this.errorStatusCode == null)) {
713
// if (!isIncluding()) {
714
this.statusCode = sc;
715
// if (this.errorStatusCode != null) {
716
// this.errorStatusCode = new Integer(sc);
721
public void sendRedirect(String location) throws IOException {
723
Logger.log(Logger.ERROR, Launcher.RESOURCES, "IncludeResponse.Redirect",
726
} else if (isCommitted()) {
727
throw new IllegalStateException(Launcher.RESOURCES.getString("WinstoneOutputStream.AlreadyCommitted"));
732
StringBuffer fullLocation = new StringBuffer();
733
if (location.startsWith("http://") || location.startsWith("https://")) {
734
fullLocation.append(location);
736
if (location.trim().equals(".")) {
740
fullLocation.append(this.req.getScheme()).append("://");
741
fullLocation.append(this.req.getServerName());
742
if (!((this.req.getServerPort() == 80) && this.req.getScheme().equals("http"))
743
&& !((this.req.getServerPort() == 443) && this.req.getScheme().equals("https")))
744
fullLocation.append(':').append(this.req.getServerPort());
745
if (location.startsWith("/")) {
746
fullLocation.append(location);
748
fullLocation.append(this.req.getRequestURI());
749
int questionPos = fullLocation.toString().indexOf("?");
750
if (questionPos != -1) {
751
fullLocation.delete(questionPos, fullLocation.length());
754
fullLocation.toString().lastIndexOf("/") + 1,
755
fullLocation.length());
756
fullLocation.append(location);
759
if (this.req != null) {
760
this.req.discardRequestBody();
762
this.statusCode = HttpServletResponse.SC_MOVED_TEMPORARILY;
763
setHeader(LOCATION_HEADER, fullLocation.toString());
768
public void sendError(int sc) throws IOException {
772
public void sendError(int sc, String msg) throws IOException {
774
Logger.log(Logger.ERROR, Launcher.RESOURCES, "IncludeResponse.Error",
775
new String[] { "" + sc, msg });
779
Logger.log(Logger.DEBUG, Launcher.RESOURCES,
780
"WinstoneResponse.SendingError", new String[] { "" + sc, msg });
782
if ((this.webAppConfig != null) && (this.req != null)) {
784
RequestDispatcher rd = this.webAppConfig
785
.getErrorDispatcherByCode(req.getRequestURI(), sc, msg, null);
788
rd.forward(this.req, this);
790
} catch (IllegalStateException err) {
792
} catch (IOException err) {
794
} catch (Throwable err) {
795
Logger.log(Logger.WARNING, Launcher.RESOURCES,
796
"WinstoneResponse.ErrorInErrorPage", new String[] {
797
rd.getName(), sc + "" }, err);
802
// If we are here there was no webapp and/or no request object, so
803
// show the default error page
804
if (this.errorStatusCode == null) {
805
this.statusCode = sc;
807
String output = Launcher.RESOURCES.getString("WinstoneResponse.ErrorPage",
808
new String[] { sc + "", (msg == null ? "" : msg), "",
809
Launcher.RESOURCES.getString("ServerVersion"),
811
setContentLength(output.getBytes(getCharacterEncoding()).length);
812
Writer out = getWriter();
820
public String encodeRedirectUrl(String url) {
821
return encodeRedirectURL(url);
827
public String encodeUrl(String url) {
828
return encodeURL(url);
834
public void setStatus(int sc, String sm) {