1   /*
2    * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/oac.hc3x/trunk/src/test/org/apache/commons/httpclient/server/SimpleHttpServerConnection.java $
3    * $Revision: 1425331 $
4    * $Date: 2012-12-22 19:29:41 +0100 (Sat, 22 Dec 2012) $
5    *
6    * ====================================================================
7    *
8    *  Licensed to the Apache Software Foundation (ASF) under one or more
9    *  contributor license agreements.  See the NOTICE file distributed with
10   *  this work for additional information regarding copyright ownership.
11   *  The ASF licenses this file to You under the Apache License, Version 2.0
12   *  (the "License"); you may not use this file except in compliance with
13   *  the License.  You may obtain a copy of the License at
14   *
15   *      http://www.apache.org/licenses/LICENSE-2.0
16   *
17   *  Unless required by applicable law or agreed to in writing, software
18   *  distributed under the License is distributed on an "AS IS" BASIS,
19   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   *  See the License for the specific language governing permissions and
21   *  limitations under the License.
22   * ====================================================================
23   *
24   * This software consists of voluntary contributions made by many
25   * individuals on behalf of the Apache Software Foundation.  For more
26   * information on the Apache Software Foundation, please see
27   * <http://www.apache.org/>.
28   *
29   */
30  
31  package org.apache.commons.httpclient.server;
32  
33  import java.io.IOException;
34  import java.io.InputStream;
35  import java.io.OutputStream;
36  import java.io.UnsupportedEncodingException;
37  import java.net.Socket;
38  import java.net.SocketException;
39  import java.util.Iterator;
40  
41  import org.apache.commons.httpclient.ChunkedOutputStream;
42  import org.apache.commons.httpclient.Header;
43  import org.apache.commons.httpclient.HttpParser;
44  import org.apache.commons.httpclient.StatusLine;
45  
46  /***
47   * A connection to the SimpleHttpServer.
48   * 
49   * @author Christian Kohlschuetter
50   * @author Oleg Kalnichevski
51   */
52  public class SimpleHttpServerConnection {
53      
54      private static final String HTTP_ELEMENT_CHARSET = "US-ASCII";
55  
56      private Socket socket = null;
57      private InputStream in = null;
58      private OutputStream out = null;
59      private boolean keepAlive = false;
60  
61      public SimpleHttpServerConnection(final Socket socket) 
62      throws IOException {
63          super();
64          if (socket == null) {
65              throw new IllegalArgumentException("Socket may not be null");
66          }
67          this.socket = socket;
68          this.socket.setSoTimeout(500);
69          this.in = socket.getInputStream();
70          this.out = socket.getOutputStream();
71      }
72  
73      public synchronized void close() {
74          try {
75              if (socket != null) {
76                  in.close();
77                  out.close();
78                  socket.close();
79                  socket = null;
80              }
81          } catch (IOException e) {
82          }
83      }
84  
85      public synchronized boolean isOpen() {
86          return this.socket != null;
87      }
88      
89      public void setKeepAlive(boolean b) {
90          this.keepAlive = b;
91      }
92  
93      public boolean isKeepAlive() {
94          return this.keepAlive;
95      }
96  
97      public InputStream getInputStream() {
98          return this.in;
99      }
100 
101     public OutputStream getOutputStream() {
102         return this.out;
103     }
104 
105     /***
106      * Returns the ResponseWriter used to write the output to the socket.
107      * 
108      * @return This connection's ResponseWriter
109      */
110     public ResponseWriter getWriter() throws UnsupportedEncodingException {
111         return new ResponseWriter(out);
112     }
113 
114     public SimpleRequest readRequest() throws IOException {
115         try {
116             String line = null;
117             do {
118                 line = HttpParser.readLine(in, HTTP_ELEMENT_CHARSET);
119             } while (line != null && line.length() == 0);
120 
121             if (line == null) {
122                 setKeepAlive(false);
123                 return null;
124             }
125             SimpleRequest request = new SimpleRequest( 
126                     RequestLine.parseLine(line),
127                     HttpParser.parseHeaders(this.in, HTTP_ELEMENT_CHARSET),
128                     this.in);
129             return request;
130         } catch (IOException e) {
131             close();
132             throw e;
133         }
134     }
135 
136     public SimpleResponse readResponse() throws IOException {
137         try {
138             String line = null;
139             do {
140                 line = HttpParser.readLine(in, HTTP_ELEMENT_CHARSET);
141             } while (line != null && line.length() == 0);
142 
143             if (line == null) {
144                 setKeepAlive(false);
145                 return null;
146             }
147             SimpleResponse response = new SimpleResponse(
148                     new StatusLine(line),
149                     HttpParser.parseHeaders(this.in, HTTP_ELEMENT_CHARSET),
150                     this.in);
151             return response;
152         } catch (IOException e) {
153             close();
154             throw e;
155         }
156     }
157 
158     public void writeRequest(final SimpleRequest request) throws IOException {
159         if (request == null) {
160             return;
161         }
162         ResponseWriter writer = new ResponseWriter(this.out, HTTP_ELEMENT_CHARSET);
163         writer.println(request.getRequestLine().toString());
164         Iterator item = request.getHeaderIterator();
165         while (item.hasNext()) {
166             Header header = (Header) item.next();
167             writer.print(header.toExternalForm());
168         }
169         writer.println();
170         writer.flush();
171         
172         OutputStream outsream = this.out;
173         InputStream content = request.getBody(); 
174         if (content != null) {
175 
176             Header transferenc = request.getFirstHeader("Transfer-Encoding");
177             if (transferenc != null) {
178                 request.removeHeaders("Content-Length");
179                 if (transferenc.getValue().indexOf("chunked") != -1) {
180                     outsream = new ChunkedOutputStream(outsream);
181                 }
182             }
183             byte[] tmp = new byte[4096];
184             int i = 0;
185             while ((i = content.read(tmp)) >= 0) {
186                 outsream.write(tmp, 0, i);
187             }        
188             if (outsream instanceof ChunkedOutputStream) {
189                 ((ChunkedOutputStream)outsream).finish();
190             }
191         }
192         outsream.flush();
193     }
194     
195     public void writeResponse(final SimpleResponse response) throws IOException {
196         if (response == null) {
197             return;
198         }
199         ResponseWriter writer = new ResponseWriter(this.out, HTTP_ELEMENT_CHARSET);
200         writer.println(response.getStatusLine());
201         Iterator item = response.getHeaderIterator();
202         while (item.hasNext()) {
203             Header header = (Header) item.next();
204             writer.print(header.toExternalForm());
205         }
206         writer.println();
207         writer.flush();
208         
209         OutputStream outsream = this.out;
210         InputStream content = response.getBody(); 
211         if (content != null) {
212 
213             Header transferenc = response.getFirstHeader("Transfer-Encoding");
214             if (transferenc != null) {
215                 response.removeHeaders("Content-Length");
216                 if (transferenc.getValue().indexOf("chunked") != -1) {
217                     outsream = new ChunkedOutputStream(outsream);
218                 }
219             }
220                         
221             byte[] tmp = new byte[1024];
222             int i = 0;
223             while ((i = content.read(tmp)) >= 0) {
224                 outsream.write(tmp, 0, i);
225             }        
226             if (outsream instanceof ChunkedOutputStream) {
227                 ((ChunkedOutputStream)outsream).finish();
228             }
229         }
230         outsream.flush();
231     }
232 
233     public int getSocketTimeout() throws SocketException {
234         return this.socket.getSoTimeout();
235     }
236     
237     public void setSocketTimeout(int timeout) throws SocketException {
238         this.socket.setSoTimeout(timeout);
239     }
240         
241 }
242