1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/server/SimpleHttpServerConnection.java,v 1.1.2.5 2004/02/22 18:21:18 olegk Exp $
3    * $Revision: 1.1.2.5 $
4    * $Date: 2004/02/22 18:21:18 $
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   * [Additional notices, if required by prior licensing conditions]
29   *
30   */
31  
32  package org.apache.commons.httpclient.server;
33  
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.io.OutputStream;
37  import java.io.UnsupportedEncodingException;
38  import java.net.Socket;
39  import java.net.SocketException;
40  
41  import org.apache.commons.httpclient.Header;
42  import org.apache.commons.httpclient.HttpParser;
43  import org.apache.commons.httpclient.HttpStatus;
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   */
52  public class SimpleHttpServerConnection implements Runnable {
53      
54      private static final Log LOG = LogFactory.getLog(SimpleHttpServerConnection.class);
55      
56      private SimpleHttpServer server;
57      private Socket socket;
58      private InputStream in;
59      private OutputStream out;
60  
61      private int requestNo = 0;
62      
63      private boolean keepAlive = false;
64  
65  	private RequestLine requestLine;
66  
67  	private Header[] headers;
68  
69      public SimpleHttpServerConnection(SimpleHttpServer server, Socket socket) throws IOException {
70          this.server = server;
71          this.socket = socket;
72          this.in = socket.getInputStream();
73          this.out = socket.getOutputStream();
74      }
75  
76      public void destroy() {
77          try {
78              if(socket != null) {
79                  in.close();
80                  out.close();
81                  socket.close();
82                  socket = null;
83              } 
84          } catch(IOException e) {
85              // fail("Unexpected exception: " + e);
86          }
87          server.removeConnection(this);
88      }
89  
90      public void run() {
91          requestNo = 0;
92          try {
93              do {
94                  keepAlive = false;
95                  
96                  ++this.requestNo;
97                  readRequest();
98              } while(keepAlive);
99          } catch (SocketException ignore) {
100         } catch (IOException e) {
101             LOG.error("ServerConnection read error", e);
102             throw new RuntimeException(e.getMessage());
103         } finally {
104             destroy();
105         }
106     }
107     
108     /***
109      * Requests to close connection after processing this request.
110      */
111     public void connectionClose() {
112         keepAlive = false;
113     }
114 
115     /***
116      * Requests to keep the connection alive after processing this request
117      * (must be re-issued for every request if permanent keep-alive is desired).
118      * 
119      */
120     public void connectionKeepAlive() {
121         keepAlive = true;
122     }
123     
124     /***
125      * Returns the ResponseWriter used to write the output to the socket.
126      * 
127      * @return  This connection's ResponseWriter
128      */
129     public ResponseWriter getWriter() {
130         try {
131 			return new ResponseWriter(out);
132 		} catch (UnsupportedEncodingException e) {
133 			throw new RuntimeException(e.toString());
134 		}
135     }
136     
137     /***
138      * Returns the number of requests processed (including the current one)
139      * for this connection.
140      * 
141      * @return
142      */
143     public int getRequestNumber() {
144         return requestNo;
145     }
146             
147     private void readRequest() throws IOException {
148         String line;
149         do {
150             line = HttpParser.readLine(in);
151         } while(line != null && line.length() == 0);
152         
153         if(line == null) {
154             connectionClose();
155             return;
156         }
157 
158         try {
159             requestLine = RequestLine.parseLine(line);
160             headers = HttpParser.parseHeaders(in);
161         } catch(IOException e) {
162             connectionClose();
163             ErrorResponse.getInstance().getResponse(HttpStatus.SC_BAD_REQUEST).processRequest(this);
164             return;     
165         }
166         server.processRequest(this);
167         out.flush();
168     }
169     
170     public Header[] getHeaders() {
171     	Header[] copy = new Header[headers.length];
172     	System.arraycopy(headers, 0, copy, 0, headers.length);
173     	return copy;
174     }
175     
176     public RequestLine getRequestLine() {
177     	return requestLine;
178     }
179 
180 	public InputStream getInputStream() {
181 		return in;
182 	}
183 
184 	public OutputStream getOutputStream() {
185 		return out;
186 	}
187 }