1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
|
|
15 |
|
|
16 |
|
package org.apache.xmlrpc.webserver; |
17 |
|
|
18 |
|
import java.io.IOException; |
19 |
|
import java.io.OutputStream; |
20 |
|
import java.io.OutputStreamWriter; |
21 |
|
import java.io.PrintWriter; |
22 |
|
import java.net.Socket; |
23 |
|
import java.util.ArrayList; |
24 |
|
import java.util.HashMap; |
25 |
|
import java.util.Iterator; |
26 |
|
import java.util.List; |
27 |
|
import java.util.Locale; |
28 |
|
import java.util.Map; |
29 |
|
import java.util.StringTokenizer; |
30 |
|
|
31 |
|
import javax.servlet.ServletOutputStream; |
32 |
|
import javax.servlet.http.Cookie; |
33 |
|
import javax.servlet.http.HttpServletResponse; |
34 |
|
|
35 |
|
|
36 |
|
|
37 |
|
|
38 |
|
|
39 |
|
|
40 |
|
|
41 |
|
public class HttpServletResponseImpl implements HttpServletResponse { |
42 |
|
static final int BUFFER_SIZE = 8192; |
43 |
|
private final Socket socket; |
44 |
|
private final OutputStream ostream; |
45 |
70 |
private final Map headers = new HashMap(); |
46 |
70 |
private int status = HttpServletResponse.SC_OK; |
47 |
70 |
private String message = getStatusMessage(status); |
48 |
|
private Locale locale; |
49 |
|
private String charEncoding; |
50 |
|
private PrintWriter writer; |
51 |
|
private ServletOutputStreamImpl soStream; |
52 |
|
|
53 |
|
|
54 |
|
|
55 |
|
|
56 |
|
|
57 |
70 |
public HttpServletResponseImpl(Socket pSocket) throws IOException { |
58 |
70 |
socket = pSocket; |
59 |
70 |
ostream = socket.getOutputStream(); |
60 |
70 |
} |
61 |
|
|
62 |
0 |
public void addCookie(Cookie pCookie) { throw new IllegalStateException("Not implemented"); } |
63 |
|
|
64 |
0 |
public void addDateHeader(String pHeader, long pDate) { throw new IllegalStateException("Not implemented"); } |
65 |
|
|
66 |
|
public void addHeader(String pHeader, String pValue) { |
67 |
140 |
String key = pHeader.toLowerCase(); |
68 |
140 |
Object o = headers.get(key); |
69 |
140 |
if (o == null) { |
70 |
140 |
headers.put(key, pValue); |
71 |
|
} else { |
72 |
|
List list; |
73 |
0 |
if (o instanceof String) { |
74 |
0 |
list = new ArrayList(); |
75 |
0 |
headers.put(key, list); |
76 |
0 |
list.add(o); |
77 |
|
} else { |
78 |
0 |
list = (List) o; |
79 |
|
} |
80 |
0 |
list.add(pValue); |
81 |
|
} |
82 |
140 |
} |
83 |
|
|
84 |
|
private String getHeader(String pHeader) { |
85 |
70 |
String key = pHeader.toLowerCase(); |
86 |
70 |
Object o = headers.get(key); |
87 |
70 |
if (o == null) { |
88 |
0 |
return null; |
89 |
70 |
} else if (o instanceof String) { |
90 |
70 |
return (String) o; |
91 |
|
} else { |
92 |
0 |
List list = (List) o; |
93 |
0 |
if (list.size() == 0) { |
94 |
0 |
return null; |
95 |
|
} else { |
96 |
0 |
return (String) list.get(0); |
97 |
|
} |
98 |
|
} |
99 |
|
} |
100 |
|
|
101 |
|
public void addIntHeader(String pHeader, int pValue) { |
102 |
0 |
addHeader(pHeader, Integer.toString(pValue)); |
103 |
0 |
} |
104 |
|
|
105 |
|
public boolean containsHeader(String pHeader) { |
106 |
0 |
return headers.containsKey(pHeader.toLowerCase()); |
107 |
|
} |
108 |
|
|
109 |
0 |
public String encodeRedirectURL(String pURL) { throw new IllegalStateException("Not implemented"); } |
110 |
|
|
111 |
0 |
public String encodeRedirectUrl(String pURL) { return encodeRedirectURL(pURL); } |
112 |
|
|
113 |
0 |
public String encodeURL(String pURL) { throw new IllegalStateException("Not implemented"); } |
114 |
|
|
115 |
0 |
public String encodeUrl(String pURL) { return encodeUrl(pURL); } |
116 |
|
|
117 |
|
public void sendError(int pStatusCode) throws IOException { |
118 |
0 |
sendError(pStatusCode, getStatusMessage(pStatusCode)); |
119 |
0 |
} |
120 |
|
|
121 |
|
public void sendError(int pStatusCode, String pMessage) throws IOException { |
122 |
0 |
sendError(pStatusCode, pMessage, null); |
123 |
0 |
} |
124 |
|
|
125 |
|
protected void sendError(int pStatusCode, String pMessage, String pDescription) |
126 |
|
throws IOException { |
127 |
0 |
if (isCommitted()) { |
128 |
0 |
throw new IllegalStateException("Can't send an error message, if the response has already been committed."); |
129 |
|
} |
130 |
0 |
headers.clear(); |
131 |
0 |
setContentType("text/html"); |
132 |
0 |
setStatus(pStatusCode, pMessage); |
133 |
0 |
if (soStream == null) { |
134 |
0 |
soStream = new ServletOutputStreamImpl(ostream, this); |
135 |
|
} else { |
136 |
0 |
soStream.reset(); |
137 |
|
} |
138 |
0 |
OutputStreamWriter osw = new OutputStreamWriter(soStream, getCharacterEncoding()); |
139 |
0 |
osw.write("<html><head><title>" + pStatusCode + " " + pMessage + "</title></head>\r\n"); |
140 |
0 |
osw.write("<body><h1>" + pStatusCode + " " + pMessage + "</h1>\r\n"); |
141 |
0 |
if (pDescription != null) { |
142 |
0 |
osw.write("<p>" + pDescription + "</p>\r\n"); |
143 |
|
} |
144 |
0 |
osw.write("</body></html>\r\n"); |
145 |
0 |
osw.close(); |
146 |
0 |
} |
147 |
|
|
148 |
0 |
public void sendRedirect(String arg0) throws IOException { throw new IllegalStateException("Not implemented"); } |
149 |
|
|
150 |
0 |
public void setDateHeader(String arg0, long arg1) { throw new IllegalStateException("Not implemented"); } |
151 |
|
|
152 |
|
public void setHeader(String pHeader, String pValue) { |
153 |
140 |
headers.remove(pHeader.toLowerCase()); |
154 |
140 |
addHeader(pHeader, pValue); |
155 |
140 |
} |
156 |
|
|
157 |
|
public void setIntHeader(String pHeader, int pValue) { |
158 |
70 |
setHeader(pHeader, Integer.toString(pValue)); |
159 |
70 |
} |
160 |
|
|
161 |
|
public void setStatus(int pStatusCode) { |
162 |
0 |
setStatus(pStatusCode, getStatusMessage(pStatusCode)); |
163 |
0 |
} |
164 |
|
|
165 |
|
public void setStatus(int pStatusCode, String pMessage) { |
166 |
0 |
status = pStatusCode; |
167 |
0 |
message = pMessage; |
168 |
0 |
} |
169 |
|
|
170 |
|
public void flushBuffer() throws IOException { |
171 |
0 |
ostream.flush(); |
172 |
0 |
} |
173 |
|
|
174 |
0 |
public int getBufferSize() { return BUFFER_SIZE; } |
175 |
|
|
176 |
|
|
177 |
|
|
178 |
|
|
179 |
|
|
180 |
|
|
181 |
|
|
182 |
|
|
183 |
|
|
184 |
|
|
185 |
|
|
186 |
|
|
187 |
|
|
188 |
|
|
189 |
|
|
190 |
|
|
191 |
|
|
192 |
|
|
193 |
|
|
194 |
|
|
195 |
|
|
196 |
|
|
197 |
|
|
198 |
|
|
199 |
|
|
200 |
|
public void setCharacterEncoding(String pCharset) { |
201 |
0 |
charEncoding = pCharset; |
202 |
0 |
} |
203 |
|
|
204 |
|
public String getCharacterEncoding() { |
205 |
70 |
if (charEncoding == null) { |
206 |
70 |
return "ISO-8859-1"; |
207 |
|
} else { |
208 |
0 |
return charEncoding; |
209 |
|
} |
210 |
|
} |
211 |
|
|
212 |
0 |
public Locale getLocale() { return locale; } |
213 |
|
|
214 |
|
public ServletOutputStream getOutputStream() throws IOException { |
215 |
140 |
if (writer != null) { |
216 |
0 |
throw new IllegalStateException("You may call either getWriter() or getOutputStream(), but not both."); |
217 |
|
} else { |
218 |
140 |
if (soStream == null) { |
219 |
70 |
soStream = new ServletOutputStreamImpl(ostream, this); |
220 |
|
} |
221 |
140 |
return soStream; |
222 |
|
} |
223 |
|
} |
224 |
|
|
225 |
|
public PrintWriter getWriter() throws IOException { |
226 |
0 |
if (writer != null) { |
227 |
0 |
return writer; |
228 |
0 |
} else if (soStream != null) { |
229 |
0 |
throw new IllegalStateException("You may call either getWriter() or getOutputStream(), but not both."); |
230 |
|
} else { |
231 |
0 |
writer = new PrintWriter(new OutputStreamWriter(getOutputStream(), getCharacterEncoding())); |
232 |
0 |
return writer; |
233 |
|
} |
234 |
|
} |
235 |
|
|
236 |
|
public boolean isCommitted() { |
237 |
0 |
return soStream != null && soStream.isCommitted(); |
238 |
|
} |
239 |
|
|
240 |
|
public void reset() { |
241 |
0 |
resetBuffer(); |
242 |
0 |
setStatus(HttpServletResponse.SC_OK); |
243 |
0 |
headers.clear(); |
244 |
0 |
charEncoding = null; |
245 |
0 |
locale = null; |
246 |
0 |
} |
247 |
|
|
248 |
|
public void resetBuffer() { |
249 |
0 |
if (isCommitted()) { |
250 |
0 |
throw new IllegalStateException("The ServletOutputStream is already committed. A reset is no longer possible."); |
251 |
|
} |
252 |
0 |
if (soStream != null) { |
253 |
0 |
soStream.reset(); |
254 |
|
} |
255 |
0 |
} |
256 |
|
|
257 |
0 |
public void setBufferSize(int pBufferSize) { throw new IllegalStateException("Not implemented"); } |
258 |
|
|
259 |
|
public void setContentLength(int pContentLength) { |
260 |
70 |
if (pContentLength == -1) { |
261 |
0 |
headers.remove("content-length"); |
262 |
|
} else { |
263 |
70 |
setIntHeader("content-length", pContentLength); |
264 |
|
} |
265 |
70 |
} |
266 |
|
|
267 |
|
|
268 |
|
|
269 |
|
|
270 |
|
|
271 |
|
|
272 |
|
|
273 |
|
|
274 |
|
|
275 |
|
|
276 |
|
|
277 |
|
|
278 |
|
|
279 |
|
|
280 |
|
|
281 |
|
public String getContentType() { |
282 |
70 |
String s = getHeader("content-type"); |
283 |
70 |
if (s != null && s.toLowerCase().startsWith("text/")) { |
284 |
70 |
String enc = getCharacterEncoding(); |
285 |
70 |
if (enc != null) { |
286 |
70 |
s += "; charset=" + enc; |
287 |
|
} |
288 |
|
} |
289 |
70 |
return s; |
290 |
|
} |
291 |
|
|
292 |
|
|
293 |
|
public void setContentType(String pType) { |
294 |
70 |
if (pType != null) { |
295 |
70 |
boolean charSetFound = false; |
296 |
70 |
StringBuffer sb = new StringBuffer(); |
297 |
210 |
for (StringTokenizer st = new StringTokenizer(pType, ";"); st.hasMoreTokens(); ) { |
298 |
70 |
String t = st.nextToken(); |
299 |
70 |
if (t.toLowerCase().startsWith("charset=")) { |
300 |
0 |
charSetFound = true; |
301 |
0 |
setCharacterEncoding(t.substring("charset=".length()).trim()); |
302 |
|
} else { |
303 |
70 |
if (sb.length() > 0) { |
304 |
0 |
sb.append("; "); |
305 |
|
} |
306 |
70 |
sb.append(t); |
307 |
|
} |
308 |
|
} |
309 |
70 |
if (charSetFound) { |
310 |
0 |
pType = sb.toString(); |
311 |
|
} |
312 |
|
} |
313 |
70 |
setHeader("content-type", pType); |
314 |
70 |
} |
315 |
|
|
316 |
0 |
public void setLocale(Locale pLocale) { locale = pLocale; } |
317 |
|
|
318 |
|
|
319 |
|
|
320 |
|
|
321 |
|
|
322 |
|
public static String getStatusMessage(int pStatusCode) { |
323 |
70 |
switch (pStatusCode) { |
324 |
|
case HttpServletResponse.SC_OK: |
325 |
70 |
return ("OK"); |
326 |
|
case HttpServletResponse.SC_ACCEPTED: |
327 |
0 |
return ("Accepted"); |
328 |
|
case HttpServletResponse.SC_BAD_GATEWAY: |
329 |
0 |
return ("Bad Gateway"); |
330 |
|
case HttpServletResponse.SC_BAD_REQUEST: |
331 |
0 |
return ("Bad Request"); |
332 |
|
case HttpServletResponse.SC_CONFLICT: |
333 |
0 |
return ("Conflict"); |
334 |
|
case HttpServletResponse.SC_CONTINUE: |
335 |
0 |
return ("Continue"); |
336 |
|
case HttpServletResponse.SC_CREATED: |
337 |
0 |
return ("Created"); |
338 |
|
case HttpServletResponse.SC_EXPECTATION_FAILED: |
339 |
0 |
return ("Expectation Failed"); |
340 |
|
case HttpServletResponse.SC_FORBIDDEN: |
341 |
0 |
return ("Forbidden"); |
342 |
|
case HttpServletResponse.SC_GATEWAY_TIMEOUT: |
343 |
0 |
return ("Gateway Timeout"); |
344 |
|
case HttpServletResponse.SC_GONE: |
345 |
0 |
return ("Gone"); |
346 |
|
case HttpServletResponse.SC_HTTP_VERSION_NOT_SUPPORTED: |
347 |
0 |
return ("HTTP Version Not Supported"); |
348 |
|
case HttpServletResponse.SC_INTERNAL_SERVER_ERROR: |
349 |
0 |
return ("Internal Server Error"); |
350 |
|
case HttpServletResponse.SC_LENGTH_REQUIRED: |
351 |
0 |
return ("Length Required"); |
352 |
|
case HttpServletResponse.SC_METHOD_NOT_ALLOWED: |
353 |
0 |
return ("Method Not Allowed"); |
354 |
|
case HttpServletResponse.SC_MOVED_PERMANENTLY: |
355 |
0 |
return ("Moved Permanently"); |
356 |
|
case HttpServletResponse.SC_MOVED_TEMPORARILY: |
357 |
0 |
return ("Moved Temporarily"); |
358 |
|
case HttpServletResponse.SC_MULTIPLE_CHOICES: |
359 |
0 |
return ("Multiple Choices"); |
360 |
|
case HttpServletResponse.SC_NO_CONTENT: |
361 |
0 |
return ("No Content"); |
362 |
|
case HttpServletResponse.SC_NON_AUTHORITATIVE_INFORMATION: |
363 |
0 |
return ("Non-Authoritative Information"); |
364 |
|
case HttpServletResponse.SC_NOT_ACCEPTABLE: |
365 |
0 |
return ("Not Acceptable"); |
366 |
|
case HttpServletResponse.SC_NOT_FOUND: |
367 |
0 |
return ("Not Found"); |
368 |
|
case HttpServletResponse.SC_NOT_IMPLEMENTED: |
369 |
0 |
return ("Not Implemented"); |
370 |
|
case HttpServletResponse.SC_NOT_MODIFIED: |
371 |
0 |
return ("Not Modified"); |
372 |
|
case HttpServletResponse.SC_PARTIAL_CONTENT: |
373 |
0 |
return ("Partial Content"); |
374 |
|
case HttpServletResponse.SC_PAYMENT_REQUIRED: |
375 |
0 |
return ("Payment Required"); |
376 |
|
case HttpServletResponse.SC_PRECONDITION_FAILED: |
377 |
0 |
return ("Precondition Failed"); |
378 |
|
case HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED: |
379 |
0 |
return ("Proxy Authentication Required"); |
380 |
|
case HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE: |
381 |
0 |
return ("Request Entity Too Large"); |
382 |
|
case HttpServletResponse.SC_REQUEST_TIMEOUT: |
383 |
0 |
return ("Request Timeout"); |
384 |
|
case HttpServletResponse.SC_REQUEST_URI_TOO_LONG: |
385 |
0 |
return ("Request URI Too Long"); |
386 |
|
case HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE: |
387 |
0 |
return ("Requested Range Not Satisfiable"); |
388 |
|
case HttpServletResponse.SC_RESET_CONTENT: |
389 |
0 |
return ("Reset Content"); |
390 |
|
case HttpServletResponse.SC_SEE_OTHER: |
391 |
0 |
return ("See Other"); |
392 |
|
case HttpServletResponse.SC_SERVICE_UNAVAILABLE: |
393 |
0 |
return ("Service Unavailable"); |
394 |
|
case HttpServletResponse.SC_SWITCHING_PROTOCOLS: |
395 |
0 |
return ("Switching Protocols"); |
396 |
|
case HttpServletResponse.SC_UNAUTHORIZED: |
397 |
0 |
return ("Unauthorized"); |
398 |
|
case HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE: |
399 |
0 |
return ("Unsupported Media Type"); |
400 |
|
case HttpServletResponse.SC_USE_PROXY: |
401 |
0 |
return ("Use Proxy"); |
402 |
|
case 207: |
403 |
0 |
return ("Multi-Status"); |
404 |
|
case 422: |
405 |
0 |
return ("Unprocessable Entity"); |
406 |
|
case 423: |
407 |
0 |
return ("Locked"); |
408 |
|
case 507: |
409 |
0 |
return ("Insufficient Storage"); |
410 |
|
default: |
411 |
0 |
return ("HTTP Response Status " + pStatusCode); |
412 |
|
} |
413 |
|
} |
414 |
|
|
415 |
|
String getHttpHeaders(Integer pContentLength) throws IOException { |
416 |
70 |
StringBuffer sb = new StringBuffer(); |
417 |
70 |
sb.append("HTTP/1.0 "); |
418 |
70 |
sb.append(status); |
419 |
70 |
sb.append(' '); |
420 |
70 |
sb.append(message); |
421 |
70 |
sb.append("\r\n"); |
422 |
70 |
String contentType = getContentType(); |
423 |
70 |
if (contentType != null) { |
424 |
70 |
sb.append("Content-Type: "); |
425 |
70 |
sb.append(contentType); |
426 |
70 |
sb.append("\r\n"); |
427 |
|
} |
428 |
70 |
boolean contentLengthSeen = false; |
429 |
280 |
for (Iterator iter = headers.entrySet().iterator(); iter.hasNext(); ) { |
430 |
140 |
Map.Entry entry = (Map.Entry) iter.next(); |
431 |
140 |
String header = (String) entry.getKey(); |
432 |
140 |
if ("content-type".equalsIgnoreCase(header)) { |
433 |
70 |
continue; |
434 |
|
} |
435 |
70 |
Object o = entry.getValue(); |
436 |
70 |
if (o == null) { |
437 |
0 |
continue; |
438 |
|
} |
439 |
70 |
if ("content-length".equalsIgnoreCase(header)) { |
440 |
70 |
contentLengthSeen = true; |
441 |
|
} |
442 |
70 |
if (o instanceof String) { |
443 |
70 |
sb.append(header); |
444 |
70 |
sb.append(": "); |
445 |
70 |
sb.append(o); |
446 |
70 |
sb.append("\r\n"); |
447 |
|
} else { |
448 |
0 |
List list = (List) o; |
449 |
0 |
for (int i = 0; i < list.size(); i++) { |
450 |
0 |
sb.append(header); |
451 |
0 |
sb.append(": "); |
452 |
0 |
sb.append(list.get(i)); |
453 |
0 |
sb.append("\r\n"); |
454 |
|
} |
455 |
|
} |
456 |
|
} |
457 |
70 |
if (pContentLength != null && !contentLengthSeen) { |
458 |
0 |
sb.append("Content-Length: "); |
459 |
0 |
sb.append(pContentLength); |
460 |
0 |
sb.append("\r\n"); |
461 |
|
} |
462 |
70 |
sb.append("\r\n"); |
463 |
70 |
return sb.toString(); |
464 |
|
} |
465 |
|
} |