Coverage Report - org.apache.xmlrpc.webserver.HttpServletRequestImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
HttpServletRequestImpl
29% 
44% 
2,538
 
 1  70
 /*
 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.BufferedInputStream;
 19  
 import java.io.BufferedReader;
 20  
 import java.io.IOException;
 21  
 import java.io.InputStream;
 22  
 import java.io.InputStreamReader;
 23  
 import java.io.Reader;
 24  
 import java.io.UnsupportedEncodingException;
 25  
 import java.lang.reflect.UndeclaredThrowableException;
 26  
 import java.net.Socket;
 27  
 import java.net.URLDecoder;
 28  
 import java.security.Principal;
 29  
 import java.util.ArrayList;
 30  
 import java.util.Collections;
 31  
 import java.util.Enumeration;
 32  
 import java.util.HashMap;
 33  
 import java.util.Iterator;
 34  
 import java.util.List;
 35  
 import java.util.Locale;
 36  
 import java.util.Map;
 37  
 import java.util.StringTokenizer;
 38  
 
 39  
 import javax.servlet.RequestDispatcher;
 40  
 import javax.servlet.ServletInputStream;
 41  
 import javax.servlet.http.Cookie;
 42  
 import javax.servlet.http.HttpServletRequest;
 43  
 import javax.servlet.http.HttpSession;
 44  
 
 45  
 import org.apache.xmlrpc.common.XmlRpcStreamConfig;
 46  
 import org.apache.xmlrpc.util.HttpUtil;
 47  
 
 48  
 
 49  
 /** Stub implementation of a {@link javax.servlet.http.HttpServletRequest}
 50  
  * with lots of unimplemented methods. I implemented only those, which
 51  
  * are required for testing the {@link org.apache.xmlrpc.webserver.XmlRpcServlet}.
 52  
  * Perhaps someone else is adding more at a later time?
 53  
  */
 54  
 public class HttpServletRequestImpl implements HttpServletRequest {
 55  
         private final Socket socket;
 56  
         private final ServletInputStream istream;
 57  
         private ServletInputStream sistream;
 58  
         private BufferedReader reader;
 59  
         private boolean postParametersParsed;
 60  
         private final String method;
 61  
         private final String protocol;
 62  
         private final String uri;
 63  
         private final String queryString;
 64  
         private final String httpVersion;
 65  70
         private final Map headers = new HashMap();
 66  70
         private final Map attributes = new HashMap();
 67  
         private Map parameters;
 68  
         private String characterEncoding;
 69  113242
         private int contentBytesRemaining = -1;
 70  
 
 71  
         /** Creates a new instance, which reads input from the given
 72  
          * socket.
 73  
          * @param pSocket The socket, to which the client is connected.
 74  
          * @throws IOException Accessing the sockets input stream failed.
 75  
          */
 76  70
         public HttpServletRequestImpl(Socket pSocket) throws IOException {
 77  70
                 socket = pSocket;
 78  70
                 final InputStream bis = new BufferedInputStream(socket.getInputStream()){
 79  
                     /** It may happen, that the XML parser invokes close().
 80  
                      * Closing the input stream must not occur, because
 81  
                      * that would close the whole socket. So we suppress it.
 82  
                      */
 83  
                 public void close() throws IOException {
 84  0
                 }
 85  
         };
 86  70
                 istream = new ServletInputStream(){
 87  
                         public int read() throws IOException {
 88  37814
                                 if (contentBytesRemaining == 0) {
 89  140
                                         return -1;
 90  
                                 }
 91  37674
                                 int c = bis.read();
 92  37674
                                 if (c != -1  &&  contentBytesRemaining > 0) {
 93  18842
                                         --contentBytesRemaining;
 94  
                                 }
 95  37674
                                 return c;
 96  
                         }
 97  
                 };
 98  
 
 99  
         /** Read the header lines, one by one. Note, that the size of
 100  
          * the buffer is a limitation of the maximum header length!
 101  
          */
 102  70
         byte[] buffer = new byte[2048];
 103  70
         String line = readLine(buffer);
 104  
         
 105  70
         StringTokenizer tokens = new StringTokenizer(line);
 106  70
         if (!tokens.hasMoreTokens()) {
 107  0
                 throw new ServletWebServer.Exception(400, "Bad Request",
 108  0
                                                                                          "Unable to parse requests first line (should"
 109  
                                                                                           + " be 'METHOD uri HTTP/version', was empty.");
 110  
         }
 111  70
         method = tokens.nextToken();
 112  70
                 if (!"POST".equalsIgnoreCase(method)) {
 113  0
                         throw new ServletWebServer.Exception(400, "Bad Request",
 114  0
                                                                                                  "Expected 'POST' method, got " + method);
 115  
                 }
 116  70
                 if (!tokens.hasMoreTokens()) {
 117  0
                 throw new ServletWebServer.Exception(400, "Bad Request",
 118  0
                                                                                          "Unable to parse requests first line (should"
 119  0
                                                                                                    + " be 'METHOD uri HTTP/version', was: " + line);
 120  
                 }
 121  70
                 String u = tokens.nextToken();
 122  70
                 int offset = u.indexOf('?');
 123  70
                 if (offset >= 0) {
 124  0
                         uri = u.substring(0, offset);
 125  0
                         queryString = u.substring(offset+1);
 126  
                 } else {
 127  70
                         uri = u;
 128  70
                         queryString = null;
 129  
                 }
 130  70
                 if (tokens.hasMoreTokens()) {
 131  70
                         String v = tokens.nextToken().toUpperCase();
 132  70
                         if (tokens.hasMoreTokens()) {
 133  0
                         throw new ServletWebServer.Exception(400, "Bad Request",
 134  0
                                                                                                  "Unable to parse requests first line (should"
 135  0
                                                                                                            + " be 'METHOD uri HTTP/version', was: " + line);
 136  
                         } else {
 137  70
                                 int index = v.indexOf('/');
 138  70
                                 if (index == -1) {
 139  0
                                 throw new ServletWebServer.Exception(400, "Bad Request",
 140  0
                                                                                                          "Unable to parse requests first line (should"
 141  0
                                                                                                                     + " be 'METHOD uri HTTP/version', was: " + line);
 142  
                                 }
 143  70
                                 protocol = v.substring(0, index).toUpperCase();
 144  70
                                 httpVersion = v.substring(index+1);
 145  
                         }
 146  
                 } else {
 147  0
                         httpVersion = "1.0";
 148  0
                         protocol = "HTTP";
 149  
                 }
 150  
 
 151  560
                 for (;;) {
 152  630
                         line = HttpUtil.readLine(istream, buffer);
 153  630
                         if (line == null  ||  line.length() == 0) {
 154  70
                                 break;
 155  
                         }
 156  560
                         int off = line.indexOf(':');
 157  560
                         if (off > 0) {
 158  560
                                 addHeader(line.substring(0, off), line.substring(off+1).trim());
 159  
                         } else {
 160  0
                                 throw new ServletWebServer.Exception(400, "Bad Request", "Unable to parse header line: " + line);
 161  
                         }
 162  
                 }
 163  70
                 contentBytesRemaining = getIntHeader("content-length");
 164  70
         }
 165  
 
 166  
         protected String readLine(byte[] pBuffer) throws IOException {
 167  70
                 int res = istream.readLine(pBuffer, 0, pBuffer.length);
 168  70
                 if (res == -1) {
 169  0
                         return null;
 170  
                 }
 171  70
                 if (res == pBuffer.length  &&  pBuffer[pBuffer.length] != '\n') {
 172  0
                         throw new ServletWebServer.Exception(400, "Bad Request",
 173  0
                                                                                                  "Maximum header size of " + pBuffer.length +
 174  0
                                                                                                  " characters exceeded.");
 175  
                 }
 176  70
                 return new String(pBuffer, 0, res, "US-ASCII");
 177  
         }
 178  
 
 179  
         protected void addHeader(String pHeader, String pValue) {
 180  560
                 String key = pHeader.toLowerCase();
 181  560
                 addParameter(headers, key, pValue);
 182  560
         }
 183  
 
 184  
         public String getAuthType() {
 185  0
                 String s = getHeader("Authorization");
 186  0
                 if (s == null) {
 187  0
                         return null;
 188  
                 }
 189  0
                 StringTokenizer st = new StringTokenizer(s);
 190  0
                 if (st.hasMoreTokens()) {
 191  0
                         return st.nextToken().toUpperCase();
 192  
                 } else {
 193  0
                         return null;
 194  
                 }
 195  
         }
 196  
 
 197  0
         public String getContextPath() { return ""; }
 198  
 
 199  0
         public Cookie[] getCookies() { throw new IllegalStateException("Not implemented"); }
 200  0
         public long getDateHeader(String arg0) { throw new IllegalStateException("Not implemented"); }
 201  
 
 202  
         public String getHeader(String pHeader) {
 203  280
                 String key = pHeader.toLowerCase();
 204  280
                 Object o = headers.get(key);
 205  280
                 if (o instanceof List) {
 206  0
                         o = ((List) o).get(0);
 207  
                 }
 208  280
                 return (String) o;
 209  
         }
 210  
 
 211  
         public Enumeration getHeaderNames() {
 212  0
                 return Collections.enumeration(headers.keySet());
 213  
         }
 214  
 
 215  
         public Enumeration getHeaders(String pHeader) {
 216  70
                 String key = pHeader.toLowerCase();
 217  70
                 Object o = headers.get(key);
 218  
                 List list;
 219  70
                 if (o instanceof List) {
 220  0
                         list = (List) o;
 221  
                 } else {
 222  70
                         list = Collections.singletonList(o);
 223  
                 }
 224  70
                 return Collections.enumeration(list);
 225  
         }
 226  
 
 227  
         public int getIntHeader(String pHeader) {
 228  70
                 String s = getHeader(pHeader);
 229  70
                 return s == null ? -1 : Integer.parseInt(s);
 230  
         }
 231  
 
 232  70
         public String getMethod() { return method; }
 233  
 
 234  0
         public String getPathInfo() { return null; }
 235  
 
 236  0
         public String getPathTranslated() { return null; }
 237  
 
 238  0
         public String getQueryString() { return queryString; }
 239  
 
 240  0
         public String getRemoteUser() { throw new IllegalStateException("Not implemented"); }
 241  
 
 242  0
         public String getRequestURI() { return uri; }
 243  
 
 244  
         public StringBuffer getRequestURL() {
 245  0
                 String scheme = getScheme().toLowerCase();
 246  0
                 StringBuffer sb = new StringBuffer(scheme);
 247  0
                 sb.append("://");
 248  0
                 String host = getHeader("host");
 249  0
                 if (host == null) {
 250  0
                         host = getLocalName();
 251  0
                         if (host == null) {
 252  0
                                 host = getLocalAddr();
 253  
                         }
 254  
                 }
 255  0
                 int port = getLocalPort();
 256  0
                 int offset = host.indexOf(':');
 257  0
                 if (offset != -1) {
 258  0
                         host = host.substring(0, offset);
 259  
                         try {
 260  0
                                 port = Integer.parseInt(host.substring(offset+1));
 261  0
                         } catch (Exception e) {
 262  
                         }
 263  
                 }
 264  
                 boolean isDefaultPort;
 265  0
                 if ("http".equalsIgnoreCase(scheme)) {
 266  0
                         isDefaultPort = port == 80;
 267  0
                 } else if ("https".equalsIgnoreCase(scheme)) {
 268  0
                         isDefaultPort = port == 443;
 269  
                 } else {
 270  0
                         isDefaultPort = false;
 271  
                 }
 272  0
                 if (!isDefaultPort) {
 273  0
                         sb.append(':');
 274  0
                         sb.append(port);
 275  
                 }
 276  0
                 sb.append(getRequestURI());
 277  0
                 return sb;
 278  
         }
 279  
 
 280  0
         public String getRequestedSessionId() { throw new IllegalStateException("Not implemented"); }
 281  
 
 282  0
         public String getServletPath() { return uri; }
 283  
 
 284  0
         public HttpSession getSession() { throw new IllegalStateException("Not implemented"); }
 285  
 
 286  0
         public HttpSession getSession(boolean pCreate) { throw new IllegalStateException("Not implemented"); }
 287  
 
 288  0
         public Principal getUserPrincipal() { throw new IllegalStateException("Not implemented"); }
 289  
 
 290  0
         public boolean isRequestedSessionIdFromCookie() { throw new IllegalStateException("Not implemented"); }
 291  
 
 292  0
         public boolean isRequestedSessionIdFromURL() { throw new IllegalStateException("Not implemented"); }
 293  
 
 294  0
         public boolean isRequestedSessionIdFromUrl() { throw new IllegalStateException("Not implemented"); }
 295  
 
 296  0
         public boolean isRequestedSessionIdValid() { throw new IllegalStateException("Not implemented"); }
 297  
 
 298  0
         public boolean isUserInRole(String pRole) { throw new IllegalStateException("Not implemented"); }
 299  
 
 300  0
         public Object getAttribute(String pKey) { return attributes.get(pKey); }
 301  
 
 302  0
         public Enumeration getAttributeNames() { return Collections.enumeration(attributes.keySet()); }
 303  
 
 304  
         public String getCharacterEncoding() {
 305  70
                 if (characterEncoding == null) {
 306  70
                         String contentType = getHeader("content-type");
 307  70
                         if (contentType != null) {
 308  210
                                 for (StringTokenizer st = new StringTokenizer(contentType, ";");  st.hasMoreTokens();  ) {
 309  70
                                         String s = st.nextToken().trim();
 310  70
                                         if (s.toLowerCase().startsWith("charset=")) {
 311  0
                                                 return s.substring("charset=".length()).trim();
 312  
                                         }
 313  
                                 }
 314  
                         }
 315  70
                         return null;
 316  
                 } else {
 317  0
                         return characterEncoding;
 318  
                 }
 319  
         }
 320  
 
 321  0
         public void setCharacterEncoding(String pEncoding) { characterEncoding = pEncoding; }
 322  
 
 323  
         public int getContentLength() {
 324  
                 try {
 325  0
                         return getIntHeader("content-length");
 326  0
                 } catch (NumberFormatException e) {
 327  0
                         return -1;
 328  
                 }
 329  
         }
 330  
 
 331  0
         public String getContentType() { return getHeader("content-type"); }
 332  
 
 333  
         public ServletInputStream getInputStream() throws IOException {
 334  70
                 if (reader == null) {
 335  70
                         if (sistream == null) {
 336  70
                                 if (postParametersParsed) {
 337  0
                                         throw new IllegalStateException("The method getInputStream() must not be called, after POST parameters have been parsed.");
 338  
                                 }
 339  70
                                 sistream = istream;
 340  
                         }
 341  70
                         return sistream;
 342  
                 } else {
 343  0
                         throw new IllegalStateException("The method getReader() has already been invoked.");
 344  
                 }
 345  
         }
 346  
 
 347  0
         public Locale getLocale() { throw new IllegalStateException("Not implemented"); }
 348  
 
 349  0
         public Enumeration getLocales() { throw new IllegalStateException("Not implemented"); }
 350  
 
 351  
         private void addParameter(Map pParams, String pKey, String pValue) {
 352  560
                 Object o = pParams.get(pKey);
 353  560
                 if (o == null) {
 354  560
                         pParams.put(pKey, pValue);
 355  
                 } else {
 356  
                         List list;
 357  0
                         if (o instanceof String) {
 358  0
                                 list = new ArrayList();
 359  0
                                 list.add(o);
 360  0
                                 pParams.put(pKey, list);
 361  
                         } else {
 362  0
                                 list = (List) o;
 363  
                         }
 364  0
                         list.add(pParams);
 365  
                 }
 366  560
         }
 367  
 
 368  
         private void parseQueryString(Map pParams, String pQueryString, String pEncoding) throws UnsupportedEncodingException {
 369  0
                 for (StringTokenizer st = new StringTokenizer(pQueryString, "&");  st.hasMoreTokens();  ) {
 370  0
                         String s = st.nextToken();
 371  0
                         parseParameter(pParams, s, pEncoding);
 372  
                 }
 373  0
         }
 374  
 
 375  
         private void parseParameter(Map pParams, String pParam, String pEncoding) throws UnsupportedEncodingException {
 376  0
                 if (pParam.length() == 0) {
 377  0
                         return;
 378  
                 }
 379  0
                 int offset = pParam.indexOf('=');
 380  
                 final String name, value;
 381  0
                 if (offset == -1) {
 382  0
                         name = pParam;
 383  0
                         value = "";
 384  
                 } else {
 385  0
                         name = pParam.substring(0, offset);
 386  0
                         value = pParam.substring(offset+1);
 387  
                 }
 388  0
                 addParameter(pParams, URLDecoder.decode(name, pEncoding), URLDecoder.decode(value, pEncoding));
 389  0
         }
 390  
 
 391  
         private void parsePostData(Map pParams, InputStream pStream, String pEncoding) throws IOException {
 392  0
                 Reader r = new InputStreamReader(pStream, "US-ASCII");
 393  0
                 StringBuffer sb = new StringBuffer();
 394  0
                 for (;;) {
 395  0
                         int c = r.read();
 396  0
                         if (c == -1  ||  c == '&') {
 397  0
                                 parseParameter(pParams, sb.toString(), pEncoding);
 398  0
                                 if (c == -1) {
 399  0
                                         break;
 400  
                                 } else {
 401  0
                                         sb.setLength(0);
 402  
                                 }
 403  
                         } else {
 404  0
                                 sb.append((char) c);
 405  
                         }
 406  
                 }
 407  0
         }
 408  
 
 409  
         protected void parseParameters() {
 410  0
                 if (parameters != null) {
 411  0
                         return;
 412  
                 }
 413  0
                 String encoding = getCharacterEncoding();
 414  0
                 if (encoding == null) {
 415  0
                         encoding = XmlRpcStreamConfig.UTF8_ENCODING;
 416  
                 }
 417  0
                 Map params = new HashMap();
 418  0
                 String s = getQueryString();
 419  0
                 if (s != null) {
 420  
                         try {
 421  0
                                 parseQueryString(params, s, encoding);
 422  0
                         } catch (IOException e) {
 423  0
                                 throw new UndeclaredThrowableException(e);
 424  
                         }
 425  
                 }
 426  0
                 if ("POST".equals(getMethod())  &&
 427  0
                         "application/x-www-form-urlencoded".equals(getContentType())) {
 428  0
                         if (sistream != null  ||  reader != null) {
 429  0
                                 throw new IllegalStateException("POST parameters cannot be parsed, after"
 430  
                                                                                                 + " getInputStream(), or getReader(),"
 431  
                                                                                                 + " have been called.");
 432  
                         }
 433  0
                         postParametersParsed = true;
 434  
                         try {
 435  0
                                 parsePostData(params, istream, encoding);
 436  0
                         } catch (IOException e) {
 437  0
                                 throw new UndeclaredThrowableException(e);
 438  
                         }
 439  
                 }
 440  0
                 parameters = params;
 441  0
         }
 442  
 
 443  
         public String getParameter(String pName) {
 444  0
                 parseParameters();
 445  0
                 Object o = parameters.get(pName);
 446  0
                 if (o instanceof List) {
 447  0
                         o = ((List) o).get(0);
 448  
                 }
 449  0
                 return (String) o;
 450  
         }
 451  
 
 452  
         public Map getParameterMap() {
 453  0
                 parseParameters();
 454  0
                 final Map result = new HashMap();
 455  0
                 for (final Iterator iter = parameters.entrySet().iterator();  iter.hasNext();  ) {
 456  0
                         final Map.Entry entry = (Map.Entry) iter.next();
 457  0
                         final String name = (String) entry.getKey();
 458  0
                         final Object o = entry.getValue();
 459  
                         final String[] array;
 460  0
                         if (o instanceof String) {
 461  0
                                 array = new String[]{(String) o};
 462  0
                         } else if (o instanceof List) {
 463  0
                                 final List list = (List) o;
 464  0
                                 array = (String[]) list.toArray(new String[list.size()]);
 465  
                         } else {
 466  0
                                 throw new IllegalStateException("Invalid object: " + o.getClass().getName());
 467  
                         }
 468  0
                         result.put(name, array);
 469  
                 }
 470  0
                 return Collections.unmodifiableMap(result);
 471  
         }
 472  
 
 473  
         public Enumeration getParameterNames() {
 474  0
                 parseParameters();
 475  0
                 return Collections.enumeration(parameters.keySet());
 476  
         }
 477  
 
 478  
         public String[] getParameterValues(String pName) {
 479  0
                 parseParameters();
 480  0
                 Object o = parameters.get(pName);
 481  0
                 if (o instanceof String) {
 482  0
                         return new String[]{(String) o};
 483  
                 } else {
 484  0
                         List list = (List) o;
 485  0
                         return (String[]) list.toArray(new String[list.size()]);
 486  
                 }
 487  
         }
 488  
 
 489  0
         public String getProtocol() { return protocol; }
 490  
 
 491  
         public BufferedReader getReader() throws IOException {
 492  0
                 if (sistream == null) {
 493  0
                         if (reader == null) {
 494  0
                                 if (postParametersParsed) {
 495  0
                                         throw new IllegalStateException("The method getReader() must not be called, after POST parameters have been parsed.");
 496  
                                 }
 497  0
                                 String encoding = getCharacterEncoding();
 498  0
                                 if (encoding == null) {
 499  0
                                         encoding = "UTF8";
 500  
                                 }
 501  0
                                 reader = new BufferedReader(new InputStreamReader(istream, encoding));
 502  
                         }
 503  0
                         return reader;
 504  
                 } else {
 505  0
                         throw new IllegalStateException("The methods getInputStream(), and getReader(), are mutually exclusive.");
 506  
                 }
 507  
         }
 508  
 
 509  0
         public String getRealPath(String pPath) { throw new IllegalStateException("Not implemented."); }
 510  
 
 511  0
         public String getLocalAddr() { return socket.getLocalAddress().getHostAddress(); }
 512  
 
 513  0
         public String getLocalName() { return socket.getLocalAddress().getHostName(); }
 514  
 
 515  0
         public int getLocalPort() { return socket.getLocalPort(); }
 516  
 
 517  0
         public String getRemoteAddr() { return socket.getInetAddress().getHostAddress(); }
 518  
 
 519  0
         public String getRemoteHost() { return socket.getInetAddress().getHostName(); }
 520  
 
 521  0
         public int getRemotePort() { return socket.getPort(); }
 522  
 
 523  
         public RequestDispatcher getRequestDispatcher(String pUri) {
 524  0
                 throw new IllegalStateException("Not implemented");
 525  
         }
 526  
 
 527  0
         public String getScheme() { return "http"; }
 528  
 
 529  0
         public String getServerName() { return socket.getLocalAddress().getHostName(); }
 530  
 
 531  0
         public int getServerPort() { return socket.getLocalPort(); }
 532  
 
 533  0
         public boolean isSecure() { return false; }
 534  
 
 535  
         public void removeAttribute(String pKey) {
 536  0
                 attributes.remove(pKey);
 537  0
         }
 538  
 
 539  
         public void setAttribute(String pKey, Object pValue) {
 540  0
                 attributes.put(pKey, pValue);
 541  0
         }
 542  
 
 543  0
         protected String getHttpVersion() { return httpVersion; }
 544  
 }