Coverage Report - org.mule.transport.http.HttpServerConnection
 
Classes in this File Line Coverage Branch Coverage Complexity
HttpServerConnection
0%
0/124
0%
0/62
3.158
 
 1  
 /*
 2  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 3  
  * The software in this package is published under the terms of the CPAL v1.0
 4  
  * license, a copy of which has been included with this distribution in the
 5  
  * LICENSE.txt file.
 6  
  */
 7  
 package org.mule.transport.http;
 8  
 
 9  
 import org.mule.RequestContext;
 10  
 import org.mule.api.transformer.TransformerException;
 11  
 import org.mule.api.transport.Connector;
 12  
 import org.mule.api.transport.OutputHandler;
 13  
 import org.mule.util.SystemUtils;
 14  
 
 15  
 import java.io.DataOutputStream;
 16  
 import java.io.IOException;
 17  
 import java.io.InputStream;
 18  
 import java.io.OutputStream;
 19  
 import java.io.UnsupportedEncodingException;
 20  
 import java.net.Socket;
 21  
 import java.net.SocketException;
 22  
 import java.util.Iterator;
 23  
 
 24  
 import org.apache.commons.httpclient.ChunkedOutputStream;
 25  
 import org.apache.commons.httpclient.Header;
 26  
 import org.apache.commons.httpclient.HttpParser;
 27  
 import org.apache.commons.httpclient.StatusLine;
 28  
 import org.apache.commons.io.IOUtils;
 29  
 import org.apache.commons.logging.Log;
 30  
 import org.apache.commons.logging.LogFactory;
 31  
 
 32  
 /** A connection to the SimpleHttpServer. */
 33  
 public class HttpServerConnection
 34  
 {
 35  0
     private static final Log logger = LogFactory.getLog(HttpServerConnection.class);
 36  
 
 37  
     private Socket socket;
 38  
     private final InputStream in;
 39  
     private final OutputStream out;
 40  
     // this should rather be isKeepSocketOpen as this is the main purpose of this flag
 41  0
     private boolean keepAlive = false;
 42  
     private final String encoding;
 43  
 
 44  
     public HttpServerConnection(final Socket socket, String encoding, HttpConnector connector) throws IOException
 45  
     {
 46  0
         super();
 47  
 
 48  0
         if (socket == null)
 49  
         {
 50  0
             throw new IllegalArgumentException("Socket may not be null");
 51  
         }
 52  
 
 53  0
         this.socket = socket;
 54  0
         setSocketTcpNoDelay(connector.isSendTcpNoDelay());
 55  0
         this.socket.setKeepAlive(connector.isKeepAlive());
 56  
         
 57  0
         if (connector.getReceiveBufferSize() != Connector.INT_VALUE_NOT_SET
 58  
             && socket.getReceiveBufferSize() != connector.getReceiveBufferSize())
 59  
         {
 60  0
             socket.setReceiveBufferSize(connector.getReceiveBufferSize());            
 61  
         }
 62  0
         if (connector.getServerSoTimeout() != Connector.INT_VALUE_NOT_SET
 63  
             && socket.getSoTimeout() != connector.getServerSoTimeout())
 64  
         {
 65  0
             socket.setSoTimeout(connector.getServerSoTimeout());
 66  
         }
 67  
         
 68  0
         this.in = socket.getInputStream();
 69  0
         this.out = new DataOutputStream(socket.getOutputStream());
 70  0
         this.encoding = encoding;
 71  0
     }
 72  
 
 73  
     private void setSocketTcpNoDelay(boolean tcpNoDelay) throws IOException
 74  
     {
 75  
         try
 76  
         {
 77  0
             socket.setTcpNoDelay(tcpNoDelay);
 78  
         }
 79  0
         catch (SocketException se)
 80  
         {
 81  0
             if (SystemUtils.IS_OS_SOLARIS || SystemUtils.IS_OS_SUN_OS)
 82  
             {
 83  
                 // this is a known Solaris bug, see
 84  
                 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6378870
 85  
                 
 86  0
                 if (logger.isDebugEnabled())
 87  
                 {
 88  0
                     logger.debug("Failed to set tcpNoDelay on socket", se);
 89  
                 }
 90  
             }
 91  
             else
 92  
             {
 93  0
                 throw se;
 94  
             }
 95  0
         }
 96  0
     }
 97  
 
 98  
     public synchronized void close()
 99  
     {
 100  
         try
 101  
         {
 102  0
             if (socket != null)
 103  
             {
 104  0
                 if (logger.isDebugEnabled())
 105  
                 {
 106  0
                     logger.debug("Closing: " + socket);
 107  
                 }
 108  
                 
 109  
                 try
 110  
                 {
 111  0
                     socket.shutdownOutput();
 112  
                 }
 113  0
                 catch (UnsupportedOperationException e)
 114  
                 {
 115  
                     //Can't shutdown in/output on SSL sockets
 116  0
                 }
 117  
                 
 118  0
                 if (in != null)
 119  
                 {
 120  0
                     in.close();
 121  
                 }
 122  0
                 if (out != null)
 123  
                 {
 124  0
                     out.close();
 125  
                 }
 126  0
                 socket.close();
 127  
             }
 128  
         }
 129  0
         catch (IOException e)
 130  
         {
 131  0
             if (logger.isDebugEnabled())
 132  
             {
 133  0
                 logger.debug("(Ignored) Error closing the socket: " + e.getMessage());
 134  
             }
 135  
         }
 136  
         finally
 137  
         {
 138  0
             socket = null;
 139  0
         }
 140  0
     }
 141  
 
 142  
     public synchronized boolean isOpen()
 143  
     {
 144  0
         return this.socket != null;
 145  
     }
 146  
 
 147  
     public void setKeepAlive(boolean b)
 148  
     {
 149  0
         this.keepAlive = b;
 150  0
     }
 151  
 
 152  
     public boolean isKeepAlive()
 153  
     {
 154  0
         return this.keepAlive;
 155  
     }
 156  
 
 157  
     public InputStream getInputStream()
 158  
     {
 159  0
         return this.in;
 160  
     }
 161  
 
 162  
     public OutputStream getOutputStream()
 163  
     {
 164  0
         return this.out;
 165  
     }
 166  
 
 167  
     /**
 168  
      * Returns the ResponseWriter used to write the output to the socket.
 169  
      *
 170  
      * @return This connection's ResponseWriter
 171  
      */
 172  
     public ResponseWriter getWriter() throws UnsupportedEncodingException
 173  
     {
 174  0
         return new ResponseWriter(out);
 175  
     }
 176  
 
 177  
     public HttpRequest readRequest() throws IOException
 178  
     {
 179  
         try
 180  
         {
 181  0
             String line = readLine();
 182  0
             if (line == null)
 183  
             {
 184  0
                 return null;
 185  
             }
 186  0
             return new HttpRequest(RequestLine.parseLine(line), HttpParser.parseHeaders(this.in, encoding), this.in, encoding);
 187  
         }
 188  0
         catch (IOException e)
 189  
         {
 190  0
             close();
 191  0
             throw e;
 192  
         }
 193  
     }
 194  
 
 195  
     public HttpResponse readResponse() throws IOException
 196  
     {
 197  
         try
 198  
         {
 199  0
             String line = readLine();
 200  0
             return new HttpResponse(new StatusLine(line), HttpParser.parseHeaders(this.in, encoding), this.in);
 201  
         }
 202  0
         catch (IOException e)
 203  
         {
 204  0
             close();
 205  0
             throw e;
 206  
         }
 207  
     }
 208  
 
 209  
     private String readLine() throws IOException
 210  
     {
 211  
         String line;
 212  
 
 213  
         do
 214  
         {
 215  0
             line = HttpParser.readLine(in, encoding);
 216  
         }
 217  0
         while (line != null && line.length() == 0);
 218  
 
 219  0
         if (line == null)
 220  
         {
 221  0
             setKeepAlive(false);
 222  0
             return null;
 223  
         }
 224  
 
 225  0
         return line;
 226  
     }
 227  
 
 228  
     public void writeRequest(final HttpRequest request) throws IOException
 229  
     {
 230  0
         if (request == null)
 231  
         {
 232  0
             return;
 233  
         }
 234  0
         ResponseWriter writer = new ResponseWriter(this.out, encoding);
 235  0
         writer.println(request.getRequestLine().toString());
 236  0
         Iterator item = request.getHeaderIterator();
 237  0
         while (item.hasNext())
 238  
         {
 239  0
             Header header = (Header) item.next();
 240  0
             writer.print(header.toExternalForm());
 241  0
         }
 242  0
         writer.println();
 243  0
         writer.flush();
 244  
 
 245  0
         OutputStream outstream = this.out;
 246  0
         InputStream content = request.getBody();
 247  0
         if (content != null)
 248  
         {
 249  0
             Header transferenc = request.getFirstHeader(HttpConstants.HEADER_TRANSFER_ENCODING);
 250  0
             if (transferenc != null)
 251  
             {
 252  0
                 request.removeHeaders(HttpConstants.HEADER_CONTENT_LENGTH);
 253  0
                 if (transferenc.getValue().indexOf(HttpConstants.TRANSFER_ENCODING_CHUNKED) != -1)
 254  
                 {
 255  0
                     outstream = new ChunkedOutputStream(outstream);
 256  
                 }
 257  
             }
 258  
 
 259  0
             IOUtils.copy(content, outstream);
 260  
 
 261  0
             if (outstream instanceof ChunkedOutputStream)
 262  
             {
 263  0
                 ((ChunkedOutputStream) outstream).finish();
 264  
             }
 265  
         }
 266  
 
 267  0
         outstream.flush();
 268  0
     }
 269  
 
 270  
     public void writeResponse(final HttpResponse response) throws IOException, TransformerException
 271  
     {
 272  0
         if (response == null)
 273  
         {
 274  0
             return;
 275  
         }
 276  
         
 277  0
         if (!response.isKeepAlive()) 
 278  
         {
 279  0
             Header header = new Header(HttpConstants.HEADER_CONNECTION, "close");
 280  0
             response.setHeader(header);
 281  
         }
 282  
         
 283  0
         setKeepAlive(response.isKeepAlive());
 284  
         
 285  0
         ResponseWriter writer = new ResponseWriter(this.out, encoding);
 286  0
         OutputStream outstream = this.out;
 287  
 
 288  0
         writer.println(response.getStatusLine());
 289  0
         Iterator item = response.getHeaderIterator();
 290  0
         while (item.hasNext())
 291  
         {
 292  0
             Header header = (Header) item.next();
 293  0
             writer.print(header.toExternalForm());
 294  0
         }
 295  0
         writer.println();
 296  0
         writer.flush();
 297  
 
 298  0
         OutputHandler content = response.getBody();
 299  0
         if (content != null)
 300  
         {
 301  0
             Header transferenc = response.getFirstHeader(HttpConstants.HEADER_TRANSFER_ENCODING);
 302  0
             if (transferenc != null)
 303  
             {
 304  0
                 response.removeHeaders(HttpConstants.HEADER_CONTENT_LENGTH);
 305  0
                 if (transferenc.getValue().indexOf(HttpConstants.TRANSFER_ENCODING_CHUNKED) != -1)
 306  
                 {
 307  0
                     outstream = new ChunkedOutputStream(outstream);
 308  
                 }
 309  
             }
 310  
 
 311  0
             content.write(RequestContext.getEvent(), outstream);
 312  
 
 313  0
             if (outstream instanceof ChunkedOutputStream)
 314  
             {
 315  0
                 ((ChunkedOutputStream) outstream).finish();
 316  
             }
 317  
         }
 318  
 
 319  0
         outstream.flush();
 320  0
     }
 321  
 
 322  
     /**
 323  
      * Returns the value of the SO_TIMEOUT for the underlying socket.
 324  
      *
 325  
      * @return The value of the SO_TIMEOUT for the underlying socket.
 326  
      * @throws SocketException If there is an error in the underlying protocol.
 327  
      */
 328  
     public int getSocketTimeout() throws SocketException
 329  
     {
 330  0
         return socket.getSoTimeout();
 331  
     }
 332  
 
 333  
     public void setSocketTimeout(int timeout) throws SocketException
 334  
     {
 335  0
         socket.setSoTimeout(timeout);
 336  0
     }
 337  
 
 338  
     /**
 339  
      * Tests if SO_KEEPALIVE is enabled in the underlying socket.
 340  
      *
 341  
      * @return a <code>boolean</code> indicating whether or not SO_KEEPALIVE is enabled.
 342  
      * @throws SocketException If there is an error in the underlying protocol.
 343  
      */
 344  
     public boolean isSocketKeepAlive() throws SocketException
 345  
     {
 346  0
         return socket.getKeepAlive();
 347  
     }
 348  
 
 349  
     /**
 350  
      * Tests if TCP_NODELAY is enabled in the underlying socket.
 351  
      *
 352  
      * @return a <code>boolean</code> indicating whether or not TCP_NODELAY is enabled.
 353  
      * @throws SocketException If there is an error in the underlying protocol.
 354  
      */
 355  
     public boolean isSocketTcpNoDelay() throws SocketException
 356  
     {
 357  0
         return socket.getTcpNoDelay();
 358  
     }
 359  
 
 360  
     /**
 361  
      * Gets the value of the SO_RCVBUF for the underlying socket.
 362  
      *
 363  
      * @return The value of the SO_RCVBUF for the underlying socket.
 364  
      * @throws SocketException If there is an error in the underlying protocol.
 365  
      */
 366  
     public int getSocketReceiveBufferSize() throws SocketException
 367  
     {
 368  0
         return socket.getReceiveBufferSize();
 369  
     }
 370  
 }