View Javadoc

1   /*
2    * Copyright 2004,2005 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.eviware.soapui.impl.wsdl.monitor;
18  
19  import java.io.InputStream;
20  import java.io.OutputStream;
21  import java.io.PrintWriter;
22  import java.io.StringWriter;
23  import java.net.Socket;
24  import java.net.URL;
25  
26  import com.eviware.soapui.SoapUI;
27  
28  /***
29   * a connection listens to a single current connection
30   */
31  class Connection extends Thread
32  {
33  
34  	private SoapMonitor monitor;
35  	private boolean active;
36  
37  	private Socket inSocket = null;
38  	private Socket outSocket = null;
39  
40  	private SocketRR rr1 = null;
41  	private SocketRR rr2 = null;
42  
43  	private InputStream inputStream = null;
44  
45  	private String httpProxyHost = null;
46  	private int httpProxyPort = 80;
47  	private SlowLinkSimulator slowLink;
48  
49  	/***
50  	 * Constructor Connection
51  	 * 
52  	 * @param l
53  	 */
54  	public Connection( String name, SoapMonitor l, SlowLinkSimulator slowLink )
55  	{
56  		super( name );
57  		monitor = l;
58  		httpProxyHost = l.getHttpProxyHost();
59  		httpProxyPort = l.getHttpProxyPort();
60  		this.slowLink = slowLink;
61  	}
62  
63  	/***
64  	 * Constructor Connection
65  	 * 
66  	 * @param l
67  	 * @param s
68  	 */
69  	public Connection( String name, SoapMonitor l, Socket s, SlowLinkSimulator slowLink )
70  	{
71  		this( name, l, slowLink );
72  		inSocket = s;
73  		start();
74  	}
75  
76  	/***
77  	 * Constructor Connection
78  	 * 
79  	 * @param l
80  	 * @param in
81  	 */
82  	public Connection( String name, SoapMonitor l, InputStream in, SlowLinkSimulator slowLink )
83  	{
84  		this( name, l, slowLink );
85  		inputStream = in;
86  		start();
87  	}
88  
89  	/***
90  	 * Method run
91  	 */
92  	public void run()
93  	{
94  		setContextClassLoader( SoapUI.getSoapUICore().getExtensionClassLoader() );
95  
96  		try
97  		{
98  			active = true;
99  			httpProxyHost = System.getProperty( "http.proxyHost" );
100 			if( ( httpProxyHost != null ) && httpProxyHost.equals( "" ) )
101 			{
102 				httpProxyHost = null;
103 			}
104 			if( httpProxyHost != null )
105 			{
106 				String tmp = System.getProperty( "http.proxyPort" );
107 				if( ( tmp != null ) && tmp.equals( "" ) )
108 				{
109 					tmp = null;
110 				}
111 				if( tmp == null )
112 				{
113 					httpProxyPort = 80;
114 				}
115 				else
116 				{
117 					httpProxyPort = Integer.parseInt( tmp );
118 				}
119 			}
120 
121 			String fromHost = "";
122 			if( inSocket != null )
123 			{
124 				fromHost = ( inSocket.getInetAddress() ).getHostName();
125 			}
126 
127 			String targetHost = monitor.getTargetHost();
128 			int targetPort = monitor.getTargetPort();
129 			int listenPort = monitor.getLocalPort();
130 			InputStream tmpIn1 = inputStream;
131 			OutputStream tmpOut1 = null;
132 			InputStream tmpIn2 = null;
133 			OutputStream tmpOut2 = null;
134 			if( tmpIn1 == null )
135 			{
136 				tmpIn1 = inSocket.getInputStream();
137 			}
138 			if( inSocket != null )
139 			{
140 				tmpOut1 = inSocket.getOutputStream();
141 			}
142 
143 			CaptureInputStream requestCapture = new CaptureInputStream( tmpIn1 );
144 			tmpIn1 = requestCapture;
145 
146 			String bufferedData = null;
147 			StringBuffer buf = null;
148 
149 			TcpMonWsdlMonitorMessageExchange exchange = new TcpMonWsdlMonitorMessageExchange( monitor.getProject() );
150 			exchange.setRequestHost( fromHost );
151 
152 			// this is just temp, this class will be removed soon.
153 			// boolean isProxy = monitor.isProxy();
154 			boolean isProxy = true;
155 			URL targetUrl = isProxy ? null : new URL( monitor.getTargetEndpoint() );
156 
157 			if( isProxy || ( httpProxyHost != null ) )
158 			{
159 				// Check if we're a proxy
160 				byte[] b = new byte[1];
161 				buf = new StringBuffer();
162 				String s;
163 				for( ;; )
164 				{
165 					int len;
166 					len = tmpIn1.read( b, 0, 1 );
167 					if( len == -1 )
168 					{
169 						break;
170 					}
171 					s = new String( b );
172 					buf.append( s );
173 					if( b[0] != '\n' )
174 					{
175 						continue;
176 					}
177 					break;
178 				}
179 				bufferedData = buf.toString();
180 				if( bufferedData.startsWith( "GET " ) || bufferedData.startsWith( "POST " )
181 						|| bufferedData.startsWith( "PUT " ) || bufferedData.startsWith( "DELETE " ) )
182 				{
183 					int start, end;
184 
185 					start = bufferedData.indexOf( ' ' ) + 1;
186 					while( bufferedData.charAt( start ) == ' ' )
187 					{
188 						start++ ;
189 					}
190 					end = bufferedData.indexOf( ' ', start );
191 					String urlString = bufferedData.substring( start, end );
192 					if( urlString.charAt( 0 ) == '/' )
193 					{
194 						urlString = urlString.substring( 1 );
195 					}
196 					if( isProxy )
197 					{
198 						targetUrl = new URL( urlString );
199 						targetHost = targetUrl.getHost();
200 						targetPort = targetUrl.getPort();
201 						if( targetPort == -1 )
202 						{
203 							targetPort = 80;
204 						}
205 
206 						bufferedData = bufferedData.substring( 0, start ) + targetUrl.getFile()
207 								+ bufferedData.substring( end );
208 						bufferedData += "Connection: close\r\n";
209 					}
210 					else
211 					{
212 						targetUrl = new URL( "http://" + targetHost + ":" + targetPort + "/" + urlString );
213 						bufferedData = bufferedData.substring( 0, start ) + targetUrl.toExternalForm()
214 								+ bufferedData.substring( end );
215 						targetHost = httpProxyHost;
216 						targetPort = httpProxyPort;
217 					}
218 				}
219 			}
220 			else
221 			{
222 				// 
223 				// Change Host: header to point to correct host
224 				// 
225 				byte[] b1 = new byte[1];
226 				buf = new StringBuffer();
227 				String s1;
228 				String lastLine = null;
229 				for( ;; )
230 				{
231 					int len;
232 					len = tmpIn1.read( b1, 0, 1 );
233 					if( len == -1 )
234 					{
235 						break;
236 					}
237 					s1 = new String( b1 );
238 					buf.append( s1 );
239 					if( b1[0] != '\n' )
240 					{
241 						continue;
242 					}
243 
244 					// we have a complete line
245 					String line = buf.toString();
246 					buf.setLength( 0 );
247 
248 					// check to see if we have found Host: header
249 					if( line.startsWith( "Host: " ) )
250 					{
251 						// we need to update the hostname to target host
252 						String newHost = "Host: " + targetHost + ":" + listenPort + "\r\n";
253 						bufferedData = bufferedData.concat( newHost );
254 						bufferedData += "Connection: close\r\n";
255 						break;
256 					}
257 
258 					// failsafe
259 					if( line.equals( "\r\n" ) || ( "\n".equals( lastLine ) && line.equals( "\n" ) ) )
260 					{
261 						bufferedData += "Connection: close" + line;
262 						break;
263 					}
264 
265 					// add it to our headers so far
266 					if( bufferedData == null )
267 					{
268 						bufferedData = line;
269 					}
270 					else
271 					{
272 						bufferedData = bufferedData.concat( line );
273 					}
274 
275 					lastLine = line;
276 				}
277 
278 				// if( bufferedData != null )
279 				// {
280 				// int idx = ( bufferedData.length() < 50 ) ? bufferedData.length()
281 				// : 50;
282 				// s1 = bufferedData.substring( 0, idx );
283 				// int i = s1.indexOf( '\n' );
284 				// if( i > 0 )
285 				// {
286 				// s1 = s1.substring( 0, i - 1 );
287 				// }
288 				// s1 = s1 + "                           " +
289 				// "                       ";
290 				// s1 = s1.substring( 0, 51 );
291 				// }
292 			}
293 			if( targetPort == -1 )
294 			{
295 				targetPort = 80;
296 			}
297 
298 			exchange.setTargetUrl( targetUrl );
299 
300 			outSocket = new Socket( targetHost, targetPort );
301 			tmpIn2 = outSocket.getInputStream();
302 
303 			CaptureInputStream responseCapture = new CaptureInputStream( tmpIn2 );
304 			tmpIn2 = responseCapture;
305 
306 			tmpOut2 = outSocket.getOutputStream();
307 			if( bufferedData != null )
308 			{
309 				byte[] b = bufferedData.getBytes();
310 				tmpOut2.write( b );
311 				slowLink.pump( b.length );
312 			}
313 
314 			// this is the channel to the endpoint
315 			rr1 = new SocketRR( getName() + " to endpoint", this, inSocket, tmpIn1, outSocket, tmpOut2, slowLink );
316 
317 			// create the response slow link from the inbound slow link
318 			SlowLinkSimulator responseLink = new SlowLinkSimulator( slowLink );
319 
320 			// this is the channel from the endpoint
321 			rr2 = new SocketRR( getName() + " from endpoint", this, outSocket, tmpIn2, inSocket, tmpOut1, responseLink );
322 
323 			while( ( rr1 != null ) || ( rr2 != null ) )
324 			{
325 				if( rr2 != null )
326 				{
327 					exchange.setTimeTaken( rr2.getElapsed() );
328 				}
329 
330 				// Only loop as long as the connection to the target
331 				// machine is available - once that's gone we can stop.
332 				// The old way, loop until both are closed, left us
333 				// looping forever since no one closed the 1st one.
334 
335 				if( ( null != rr1 ) && rr1.isDone() )
336 				{
337 					rr1 = null;
338 				}
339 
340 				if( ( null != rr2 ) && rr2.isDone() )
341 				{
342 					rr2 = null;
343 				}
344 
345 				synchronized( this )
346 				{
347 					this.wait( 10 ); // Safety just incase we're not told to wake
348 					// up.
349 				}
350 			}
351 
352 			active = false;
353 			exchange.finish( requestCapture.getCapturedData(), responseCapture.getCapturedData() );
354 			monitor.addMessageExchange( exchange );
355 		}
356 		catch( Exception e )
357 		{
358 			StringWriter st = new StringWriter();
359 			PrintWriter wr = new PrintWriter( st );
360 			e.printStackTrace( wr );
361 			wr.close();
362 			halt();
363 		}
364 	}
365 
366 	protected boolean isActive()
367 	{
368 		return active;
369 	}
370 
371 	/***
372 	 * Method wakeUp
373 	 */
374 	synchronized void wakeUp()
375 	{
376 		this.notifyAll();
377 	}
378 
379 	/***
380 	 * Method halt
381 	 */
382 	public void halt()
383 	{
384 		try
385 		{
386 			if( rr1 != null )
387 			{
388 				rr1.halt();
389 			}
390 			if( rr2 != null )
391 			{
392 				rr2.halt();
393 			}
394 			if( inSocket != null )
395 			{
396 				inSocket.close();
397 			}
398 			inSocket = null;
399 			if( outSocket != null )
400 			{
401 				outSocket.close();
402 			}
403 			outSocket = null;
404 		}
405 		catch( Exception e )
406 		{
407 			SoapUI.log.info( "Error halting connection: " + e.toString() );
408 		}
409 	}
410 
411 	/***
412 	 * Method remove
413 	 */
414 	public void remove()
415 	{
416 		try
417 		{
418 			halt();
419 		}
420 		catch( Exception e )
421 		{
422 			e.printStackTrace();
423 		}
424 	}
425 }