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