1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/server/SimpleHttpServerConnection.java,v 1.20 2004/11/13 22:38:27 mbecke Exp $
3    * $Revision: 1.20 $
4    * $Date: 2004/11/13 22:38:27 $
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.util.Iterator;
38  
39  import org.apache.commons.httpclient.ChunkedOutputStream;
40  import org.apache.commons.httpclient.Header;
41  import org.apache.commons.httpclient.HttpParser;
42  import org.apache.commons.httpclient.StatusLine;
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
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 Log LOG = LogFactory.getLog(SimpleHttpServerConnection.class);
55      
56      private static final String HTTP_ELEMENT_CHARSET = "US-ASCII";
57  
58      private Socket socket = null;
59      private InputStream in = null;
60      private OutputStream out = null;
61      private boolean keepAlive = false;
62  
63      public SimpleHttpServerConnection(final Socket socket) 
64      throws IOException {
65          super();
66          if (socket == null) {
67              throw new IllegalArgumentException("Socket may not be null");
68          }
69          this.socket = socket;
70          this.socket.setSoTimeout(500);
71          this.in = socket.getInputStream();
72          this.out = socket.getOutputStream();
73      }
74  
75      public synchronized void close() {
76          try {
77              if (socket != null) {
78                  in.close();
79                  out.close();
80                  socket.close();
81                  socket = null;
82              }
83          } catch (IOException e) {
84          }
85      }
86  
87      public synchronized boolean isOpen() {
88          return this.socket != null;
89      }
90      
91      public void setKeepAlive(boolean b) {
92          this.keepAlive = b;
93      }
94  
95      public boolean isKeepAlive() {
96          return this.keepAlive;
97      }
98  
99      public InputStream getInputStream() {
100         return this.in;
101     }
102 
103     public OutputStream getOutputStream() {
104         return this.out;
105     }
106 
107     /***
108      * Returns the ResponseWriter used to write the output to the socket.
109      * 
110      * @return This connection's ResponseWriter
111      */
112     public ResponseWriter getWriter() throws UnsupportedEncodingException {
113         return new ResponseWriter(out);
114     }
115 
116     public SimpleRequest readRequest() throws IOException {
117         try {
118             String line = null;
119             do {
120                 line = HttpParser.readLine(in, HTTP_ELEMENT_CHARSET);
121             } while (line != null && line.length() == 0);
122 
123             if (line == null) {
124                 setKeepAlive(false);
125                 return null;
126             }
127             SimpleRequest request = new SimpleRequest( 
128                     RequestLine.parseLine(line),
129                     HttpParser.parseHeaders(this.in, HTTP_ELEMENT_CHARSET),
130                     this.in);
131             return request;
132         } catch (IOException e) {
133             close();
134             throw e;
135         }
136     }
137 
138     public SimpleResponse readResponse() throws IOException {
139         try {
140             String line = null;
141             do {
142                 line = HttpParser.readLine(in, HTTP_ELEMENT_CHARSET);
143             } while (line != null && line.length() == 0);
144 
145             if (line == null) {
146                 setKeepAlive(false);
147                 return null;
148             }
149             SimpleResponse response = new SimpleResponse(
150                     new StatusLine(line),
151                     HttpParser.parseHeaders(this.in, HTTP_ELEMENT_CHARSET),
152                     this.in);
153             return response;
154         } catch (IOException e) {
155             close();
156             throw e;
157         }
158     }
159 
160     public void writeRequest(final SimpleRequest request) throws IOException {
161         if (request == null) {
162             return;
163         }
164         ResponseWriter writer = new ResponseWriter(this.out, HTTP_ELEMENT_CHARSET);
165         writer.println(request.getRequestLine().toString());
166         Iterator item = request.getHeaderIterator();
167         while (item.hasNext()) {
168             Header header = (Header) item.next();
169             writer.print(header.toExternalForm());
170         }
171         writer.println();
172         writer.flush();
173         
174         OutputStream outsream = this.out;
175         InputStream content = request.getBody(); 
176         if (content != null) {
177 
178             Header transferenc = request.getFirstHeader("Transfer-Encoding");
179             if (transferenc != null) {
180                 request.removeHeaders("Content-Length");
181                 if (transferenc.getValue().indexOf("chunked") != -1) {
182                     outsream = new ChunkedOutputStream(outsream);
183                 }
184             }
185             byte[] tmp = new byte[4096];
186             int i = 0;
187             while ((i = content.read(tmp)) >= 0) {
188                 outsream.write(tmp, 0, i);
189             }        
190             if (outsream instanceof ChunkedOutputStream) {
191                 ((ChunkedOutputStream)outsream).finish();
192             }
193         }
194         outsream.flush();
195     }
196     
197     public void writeResponse(final SimpleResponse response) throws IOException {
198         if (response == null) {
199             return;
200         }
201         ResponseWriter writer = new ResponseWriter(this.out, HTTP_ELEMENT_CHARSET);
202         writer.println(response.getStatusLine());
203         Iterator item = response.getHeaderIterator();
204         while (item.hasNext()) {
205             Header header = (Header) item.next();
206             writer.print(header.toExternalForm());
207         }
208         writer.println();
209         writer.flush();
210         
211         OutputStream outsream = this.out;
212         InputStream content = response.getBody(); 
213         if (content != null) {
214 
215             Header transferenc = response.getFirstHeader("Transfer-Encoding");
216             if (transferenc != null) {
217                 response.removeHeaders("Content-Length");
218                 if (transferenc.getValue().indexOf("chunked") != -1) {
219                     outsream = new ChunkedOutputStream(outsream);
220                 }
221             }
222                         
223             byte[] tmp = new byte[1024];
224             int i = 0;
225             while ((i = content.read(tmp)) >= 0) {
226                 outsream.write(tmp, 0, i);
227             }        
228             if (outsream instanceof ChunkedOutputStream) {
229                 ((ChunkedOutputStream)outsream).finish();
230             }
231         }
232         outsream.flush();
233     }
234 
235 }
236