Source code: org/mortbay/http/ajp/AJP13Listener.java
1 // ========================================================================
2 // Copyright (c) 2002 Mort Bay Consulting (Australia) Pty. Ltd.
3 // $Id: AJP13Listener.java,v 1.17 2003/11/22 16:06:02 gregwilkins Exp $
4 // ========================================================================
5
6 package org.mortbay.http.ajp;
7
8
9 import java.io.IOException;
10 import java.net.InetAddress;
11 import java.net.Socket;
12
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15 import org.mortbay.http.HttpConnection;
16 import org.mortbay.http.HttpHandler;
17 import org.mortbay.http.HttpListener;
18 import org.mortbay.http.HttpMessage;
19 import org.mortbay.http.HttpRequest;
20 import org.mortbay.http.HttpServer;
21 import org.mortbay.util.InetAddrPort;
22 import org.mortbay.util.ThreadedServer;
23
24
25 /* ------------------------------------------------------------ */
26 /** AJP 1.3 Protocol Listener.
27 * This listener takes requests from the mod_jk or mod_jk2 modules
28 * used by web servers such as apache and IIS to forward requests to a
29 * servlet container.
30 * <p>
31 * This code uses the AJP13 code from tomcat3.3 as the protocol
32 * specification, but is new implementation.
33 *
34 * @version $Id: AJP13Listener.java,v 1.17 2003/11/22 16:06:02 gregwilkins Exp $
35 * @author Greg Wilkins (gregw)
36 */
37 public class AJP13Listener
38 extends ThreadedServer
39 implements HttpListener
40 {
41 private static Log log = LogFactory.getLog(AJP13Listener.class);
42
43 /* ------------------------------------------------------------------- */
44 private HttpServer _server;
45 private boolean _lastOut=false;
46 private boolean _lastLow=false;
47 private String _integralScheme=HttpMessage.__SSL_SCHEME;
48 private String _confidentialScheme=HttpMessage.__SSL_SCHEME;
49 private int _integralPort=0;
50 private int _confidentialPort=0;
51 private boolean _identifyListener=false;
52 private int _bufferSize=8192;
53 private int _bufferReserve=512;
54 private String[] _remoteServers;
55 private HttpHandler _handler;
56
57 /* ------------------------------------------------------------------- */
58 public AJP13Listener()
59 {}
60
61 /* ------------------------------------------------------------------- */
62 public AJP13Listener(InetAddrPort address)
63 {
64 super(address);
65 }
66
67 /* ------------------------------------------------------------ */
68 public void setHttpServer(HttpServer server)
69 {
70 _server=server;
71 }
72
73 /* ------------------------------------------------------------ */
74 public HttpServer getHttpServer()
75 {
76 return _server;
77 }
78
79 /* ------------------------------------------------------------ */
80 public int getBufferSize()
81 {
82 return _bufferSize;
83 }
84
85 /* ------------------------------------------------------------ */
86 public void setBufferSize(int size)
87 {
88 _bufferSize=size;
89 if (_bufferSize>8192)
90 log.warn("AJP Data buffer > 8192: "+size);
91 }
92
93 /* ------------------------------------------------------------ */
94 public int getBufferReserve()
95 {
96 return _bufferReserve;
97 }
98
99 /* ------------------------------------------------------------ */
100 public void setBufferReserve(int size)
101 {
102 _bufferReserve=size;
103 }
104
105 /* ------------------------------------------------------------ */
106 public boolean getIdentifyListener()
107 {
108 return _identifyListener;
109 }
110
111 /* ------------------------------------------------------------ */
112 /**
113 * @param identifyListener If true, the listener name is added to all
114 * requests as the org.mortbay.http.HttListener attribute
115 */
116 public void setIdentifyListener(boolean identifyListener)
117 {
118 _identifyListener = identifyListener;
119 }
120
121 /* --------------------------------------------------------------- */
122 public String getDefaultScheme()
123 {
124 return HttpMessage.__SCHEME;
125 }
126
127 /* --------------------------------------------------------------- */
128 public void start()
129 throws Exception
130 {
131 super.start();
132 log.info("Started AJP13Listener on "+getInetAddrPort());
133 log.info("NOTICE: AJP13 is not a secure protocol. Please protect the port "+
134 getInetAddrPort());
135 }
136
137 /* --------------------------------------------------------------- */
138 public void stop()
139 throws InterruptedException
140 {
141 super.stop();
142 log.info("Stopped AJP13Listener on "+getInetAddrPort());
143 }
144
145 /* ------------------------------------------------------------ */
146 /**
147 * @return Array of accepted remote server hostnames or IPs.
148 */
149 public String[] getRemoteServers()
150 {
151 return _remoteServers;
152 }
153
154 /* ------------------------------------------------------------ */
155 /** Set accepted remote servers.
156 * The AJP13 protocol is not secure and contains no authentication. If
157 * remote servers are set, then this listener will only accept
158 * connections from hosts with matching addresses or hostnames.
159 * @param servers Array of accepted remote server hostnames or IPs
160 */
161 public void setRemoteServers(String[] servers)
162 {
163 _remoteServers=servers;
164 }
165
166
167 /* ------------------------------------------------------------ */
168 /** Handle Job.
169 * Implementation of ThreadPool.handle(), calls handleConnection.
170 * @param socket A Connection.
171 */
172 public void handleConnection(Socket socket)
173 throws IOException
174 {
175 // Check acceptable remote servers
176 if (_remoteServers!=null && _remoteServers.length>0)
177 {
178 boolean match=false;
179 InetAddress inetAddress=socket.getInetAddress();
180 String hostAddr=inetAddress.getHostAddress();
181 String hostName=inetAddress.getHostName();
182 for (int i=0;i<_remoteServers.length;i++)
183 {
184 if (hostName.equals(_remoteServers[i]) ||
185 hostAddr.equals(_remoteServers[i]))
186 {
187 match=true;
188 break;
189 }
190 }
191 if (!match)
192 {
193 log.warn("AJP13 Connection from un-approved host: "+inetAddress);
194 return;
195 }
196 }
197
198 // Handle the connection
199 socket.setTcpNoDelay(true);
200 socket.setSoTimeout(getMaxIdleTimeMs());
201 AJP13Connection connection= createConnection(socket);
202 try{connection.handle();}
203 finally{connection.destroy();}
204 }
205
206 /* ------------------------------------------------------------ */
207 /** Create an AJP13Connection instance. This method can be used to
208 * override the connection instance.
209 * @param socket The underlying socket.
210 */
211 protected AJP13Connection createConnection(Socket socket)
212 throws IOException
213 {
214 return new AJP13Connection(this,
215 socket.getInputStream(),
216 socket.getOutputStream(),
217 socket,
218 getBufferSize());
219 }
220
221 /* ------------------------------------------------------------ */
222 /** Customize the request from connection.
223 * This method extracts the socket from the connection and calls
224 * the customizeRequest(Socket,HttpRequest) method.
225 * @param request
226 */
227 public void customizeRequest(HttpConnection connection,
228 HttpRequest request)
229 {
230 if (_identifyListener)
231 request.setAttribute(HttpListener.ATTRIBUTE,getName());
232
233 Socket socket=(Socket)(connection.getConnection());
234 customizeRequest(socket,request);
235 }
236
237 /* ------------------------------------------------------------ */
238 /** Customize request from socket.
239 * Derived versions of SocketListener may specialize this method
240 * to customize the request with attributes of the socket used (eg
241 * SSL session ids).
242 * @param request
243 */
244 protected void customizeRequest(Socket socket,
245 HttpRequest request)
246 {
247 }
248
249 /* ------------------------------------------------------------ */
250 /** Persist the connection.
251 * @param connection
252 */
253 public void persistConnection(HttpConnection connection)
254 {
255 }
256
257 /* ------------------------------------------------------------ */
258 /**
259 * @return True if low on idle threads.
260 */
261 public boolean isLowOnResources()
262 {
263 boolean low =
264 getThreads()==getMaxThreads() &&
265 getIdleThreads()<getMinThreads();
266 if (low && !_lastLow)
267 log.info("LOW ON THREADS: "+this);
268 else if (!low && _lastLow)
269 {
270 log.info("OK on threads: "+this);
271 _lastOut=false;
272 }
273 _lastLow=low;
274 return low;
275 }
276
277 /* ------------------------------------------------------------ */
278 /**
279 * @return True if out of resources.
280 */
281 public boolean isOutOfResources()
282 {
283 boolean out =
284 getThreads()==getMaxThreads() &&
285 getIdleThreads()==0;
286 if (out && !_lastOut)
287 log.warn("OUT OF THREADS: "+this);
288
289 _lastOut=out;
290 return out;
291 }
292
293 /* ------------------------------------------------------------ */
294 public boolean isIntegral(HttpConnection connection)
295 {
296 return ((AJP13Connection)connection).isSSL();
297 }
298
299 /* ------------------------------------------------------------ */
300 public boolean isConfidential(HttpConnection connection)
301 {
302 return ((AJP13Connection)connection).isSSL();
303 }
304
305 /* ------------------------------------------------------------ */
306 public String getIntegralScheme()
307 {
308 return _integralScheme;
309 }
310
311 /* ------------------------------------------------------------ */
312 public void setIntegralScheme(String integralScheme)
313 {
314 _integralScheme = integralScheme;
315 }
316
317 /* ------------------------------------------------------------ */
318 public int getIntegralPort()
319 {
320 return _integralPort;
321 }
322
323 /* ------------------------------------------------------------ */
324 public void setIntegralPort(int integralPort)
325 {
326 _integralPort = integralPort;
327 }
328
329 /* ------------------------------------------------------------ */
330 public String getConfidentialScheme()
331 {
332 return _confidentialScheme;
333 }
334
335 /* ------------------------------------------------------------ */
336 public void setConfidentialScheme(String confidentialScheme)
337 {
338 _confidentialScheme = confidentialScheme;
339 }
340
341 /* ------------------------------------------------------------ */
342 public int getConfidentialPort()
343 {
344 return _confidentialPort;
345 }
346
347 /* ------------------------------------------------------------ */
348 public void setConfidentialPort(int confidentialPort)
349 {
350 _confidentialPort = confidentialPort;
351 }
352
353 /* ------------------------------------------------------------ */
354 public HttpHandler getHttpHandler()
355 {
356 return _handler;
357 }
358
359 /* ------------------------------------------------------------ */
360 public void setHttpHandler(HttpHandler handler)
361 {
362 _handler=handler;
363 }
364 }