Coverage Report - org.apache.xmlrpc.webserver.HttpServletResponseImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
HttpServletResponseImpl
37% 
67% 
4,595
 
 1  
 /*
 2  
  * Copyright 1999,2005 The Apache Software Foundation.
 3  
  * 
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  * 
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  * 
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 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  
 /** Stub implementation of a {@link javax.servlet.http.HttpServletResponse}
 37  
  * with lots of unimplemented methods. I implemented only those, which
 38  
  * are required for testing the {@link org.apache.xmlrpc.webserver.XmlRpcServlet}.
 39  
  * Perhaps someone else is adding more at a later time?
 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  
         /** Creates a new instance.
 54  
          * @param pSocket The clients socket.
 55  
          * @throws IOException Accessing the sockets output stream failed.
 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  
         /** <p>Sets the character encoding (MIME charset) of the response being sent
 177  
          * to the client, for example, to UTF-8. If the character encoding has
 178  
          * already been set by setContentType(java.lang.String) or
 179  
          * setLocale(java.util.Locale), this method overrides it.
 180  
          * Calling setContentType(java.lang.String) with the String
 181  
          * of text/html and calling this method with the String of UTF-8
 182  
          * is equivalent with calling setContentType with the String of
 183  
          * text/html; charset=UTF-8.</p>
 184  
          * <p>This method can be called repeatedly to change the character
 185  
          * encoding. This method has no effect if it is called after getWriter
 186  
          * has been called or after the response has been committed.</p>
 187  
          * <p>Containers must communicate the character encoding used for
 188  
          * the servlet response's writer to the client if the protocol
 189  
          * provides a way for doing so. In the case of HTTP, the character
 190  
          * encoding is communicated as part of the Content-Type header for
 191  
          * text media types. Note that the character encoding cannot be
 192  
          * communicated via HTTP headers if the servlet does not specify
 193  
          * a content type; however, it is still used to encode text written
 194  
          * via the servlet response's writer.</p>
 195  
          * @param pCharset A String specifying only the character set defined
 196  
          * by IANA Character Sets (http://www.iana.org/assignments/character-sets)
 197  
          * @since Servlet API 2.4
 198  
          * @see #setLocale(Locale)
 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  
         /** <p>Returns the content type used for the MIME body sent in this
 268  
          * response. The content type proper must have been specified
 269  
          * using setContentType(java.lang.String) before the response is
 270  
          * committed. If no content type has been specified, this method
 271  
          * returns null. If a content type has been specified and a
 272  
          * character encoding has been explicitly or implicitly specified
 273  
          * as described in getCharacterEncoding(), the charset parameter
 274  
          * is included in the string returned. If no character encoding
 275  
          * has been specified, the charset parameter is omitted.</p>
 276  
          * @return A String specifying the content type, for example,
 277  
          * text/html; charset=UTF-8, or null
 278  
          * @since Servlet API 2.4
 279  
          * @see #setContentType(String)
 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  
         /** Returns a default message for a given HTTP status code.
 319  
          * @param pStatusCode The status code being queried.
 320  
          * @return The default message.
 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:       // WebDAV
 403  0
                                 return ("Multi-Status");
 404  
                         case 422:       // WebDAV
 405  0
                                 return ("Unprocessable Entity");
 406  
                         case 423:       // WebDAV
 407  0
                                 return ("Locked");
 408  
                         case 507:       // WebDAV
 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  
 }