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  		try
95  		{
96  			active = true;
97  			httpProxyHost = System.getProperty( "http.proxyHost" );
98  			if( ( httpProxyHost != null ) && httpProxyHost.equals( "" ) )
99  			{
100 				httpProxyHost = null;
101 			}
102 			if( httpProxyHost != null )
103 			{
104 				String tmp = System.getProperty( "http.proxyPort" );
105 				if( ( tmp != null ) && tmp.equals( "" ) )
106 				{
107 					tmp = null;
108 				}
109 				if( tmp == null )
110 				{
111 					httpProxyPort = 80;
112 				}
113 				else
114 				{
115 					httpProxyPort = Integer.parseInt( tmp );
116 				}
117 			}
118 
119 			String fromHost = "";
120 			if( inSocket != null )
121 			{
122 				fromHost = ( inSocket.getInetAddress() ).getHostName();
123 			}
124 
125 			String targetHost = monitor.getTargetHost();
126 			int targetPort = monitor.getTargetPort();
127 			int listenPort = monitor.getLocalPort();
128 			InputStream tmpIn1 = inputStream;
129 			OutputStream tmpOut1 = null;
130 			InputStream tmpIn2 = null;
131 			OutputStream tmpOut2 = null;
132 			if( tmpIn1 == null )
133 			{
134 				tmpIn1 = inSocket.getInputStream();
135 			}
136 			if( inSocket != null )
137 			{
138 				tmpOut1 = inSocket.getOutputStream();
139 			}
140 
141 			CaptureInputStream requestCapture = new CaptureInputStream( tmpIn1 );
142 			tmpIn1 = requestCapture;
143 
144 			String bufferedData = null;
145 			StringBuffer buf = null;
146 
147 			TcpMonWsdlMonitorMessageExchange exchange = new TcpMonWsdlMonitorMessageExchange( monitor.getProject() );
148 			exchange.setRequestHost( fromHost );
149 
150 			// this is just temp, this class will be removed soon.
151 			// boolean isProxy = monitor.isProxy();
152 			boolean isProxy = true;
153 			URL targetUrl = isProxy ? null : new URL( monitor.getTargetEndpoint() );
154 
155 			if( isProxy || ( httpProxyHost != null ) )
156 			{
157 				// Check if we're a proxy
158 				byte[] b = new byte[1];
159 				buf = new StringBuffer();
160 				String s;
161 				for( ;; )
162 				{
163 					int len;
164 					len = tmpIn1.read( b, 0, 1 );
165 					if( len == -1 )
166 					{
167 						break;
168 					}
169 					s = new String( b );
170 					buf.append( s );
171 					if( b[0] != '\n' )
172 					{
173 						continue;
174 					}
175 					break;
176 				}
177 				bufferedData = buf.toString();
178 				if( bufferedData.startsWith( "GET " ) || bufferedData.startsWith( "POST " )
179 						|| bufferedData.startsWith( "PUT " ) || bufferedData.startsWith( "DELETE " ) )
180 				{
181 					int start, end;
182 
183 					start = bufferedData.indexOf( ' ' ) + 1;
184 					while( bufferedData.charAt( start ) == ' ' )
185 					{
186 						start++ ;
187 					}
188 					end = bufferedData.indexOf( ' ', start );
189 					String urlString = bufferedData.substring( start, end );
190 					if( urlString.charAt( 0 ) == '/' )
191 					{
192 						urlString = urlString.substring( 1 );
193 					}
194 					if( isProxy )
195 					{
196 						targetUrl = new URL( urlString );
197 						targetHost = targetUrl.getHost();
198 						targetPort = targetUrl.getPort();
199 						if( targetPort == -1 )
200 						{
201 							targetPort = 80;
202 						}
203 
204 						bufferedData = bufferedData.substring( 0, start ) + targetUrl.getFile()
205 								+ bufferedData.substring( end );
206 						bufferedData += "Connection: close\r\n";
207 					}
208 					else
209 					{
210 						targetUrl = new URL( "http://" + targetHost + ":" + targetPort + "/" + urlString );
211 						bufferedData = bufferedData.substring( 0, start ) + targetUrl.toExternalForm()
212 								+ bufferedData.substring( end );
213 						targetHost = httpProxyHost;
214 						targetPort = httpProxyPort;
215 					}
216 				}
217 			}
218 			else
219 			{
220 				// 
221 				// Change Host: header to point to correct host
222 				// 
223 				byte[] b1 = new byte[1];
224 				buf = new StringBuffer();
225 				String s1;
226 				String lastLine = null;
227 				for( ;; )
228 				{
229 					int len;
230 					len = tmpIn1.read( b1, 0, 1 );
231 					if( len == -1 )
232 					{
233 						break;
234 					}
235 					s1 = new String( b1 );
236 					buf.append( s1 );
237 					if( b1[0] != '\n' )
238 					{
239 						continue;
240 					}
241 
242 					// we have a complete line
243 					String line = buf.toString();
244 					buf.setLength( 0 );
245 
246 					// check to see if we have found Host: header
247 					if( line.startsWith( "Host: " ) )
248 					{
249 						// we need to update the hostname to target host
250 						String newHost = "Host: " + targetHost + ":" + listenPort + "\r\n";
251 						bufferedData = bufferedData.concat( newHost );
252 						bufferedData += "Connection: close\r\n";
253 						break;
254 					}
255 
256 					// failsafe
257 					if( line.equals( "\r\n" ) || ( "\n".equals( lastLine ) && line.equals( "\n" ) ) )
258 					{
259 						bufferedData += "Connection: close" + line;
260 						break;
261 					}
262 
263 					// add it to our headers so far
264 					if( bufferedData == null )
265 					{
266 						bufferedData = line;
267 					}
268 					else
269 					{
270 						bufferedData = bufferedData.concat( line );
271 					}
272 
273 					lastLine = line;
274 				}
275 
276 				// if( bufferedData != null )
277 				// {
278 				// int idx = ( bufferedData.length() < 50 ) ? bufferedData.length()
279 				// : 50;
280 				// s1 = bufferedData.substring( 0, idx );
281 				// int i = s1.indexOf( '\n' );
282 				// if( i > 0 )
283 				// {
284 				// s1 = s1.substring( 0, i - 1 );
285 				// }
286 				// s1 = s1 + "                           " +
287 				// "                       ";
288 				// s1 = s1.substring( 0, 51 );
289 				// }
290 			}
291 			if( targetPort == -1 )
292 			{
293 				targetPort = 80;
294 			}
295 
296 			exchange.setTargetUrl( targetUrl );
297 
298 			outSocket = new Socket( targetHost, targetPort );
299 			tmpIn2 = outSocket.getInputStream();
300 
301 			CaptureInputStream responseCapture = new CaptureInputStream( tmpIn2 );
302 			tmpIn2 = responseCapture;
303 
304 			tmpOut2 = outSocket.getOutputStream();
305 			if( bufferedData != null )
306 			{
307 				byte[] b = bufferedData.getBytes();
308 				tmpOut2.write( b );
309 				slowLink.pump( b.length );
310 			}
311 
312 			// this is the channel to the endpoint
313 			rr1 = new SocketRR( getName() + " to endpoint", this, inSocket, tmpIn1, outSocket, tmpOut2, slowLink );
314 
315 			// create the response slow link from the inbound slow link
316 			SlowLinkSimulator responseLink = new SlowLinkSimulator( slowLink );
317 
318 			// this is the channel from the endpoint
319 			rr2 = new SocketRR( getName() + " from endpoint", this, outSocket, tmpIn2, inSocket, tmpOut1, responseLink );
320 
321 			while( ( rr1 != null ) || ( rr2 != null ) )
322 			{
323 				if( rr2 != null )
324 				{
325 					exchange.setTimeTaken( rr2.getElapsed() );
326 				}
327 
328 				// Only loop as long as the connection to the target
329 				// machine is available - once that's gone we can stop.
330 				// The old way, loop until both are closed, left us
331 				// looping forever since no one closed the 1st one.
332 
333 				if( ( null != rr1 ) && rr1.isDone() )
334 				{
335 					rr1 = null;
336 				}
337 
338 				if( ( null != rr2 ) && rr2.isDone() )
339 				{
340 					rr2 = null;
341 				}
342 
343 				synchronized( this )
344 				{
345 					this.wait( 10 ); // Safety just incase we're not told to wake
346 					// up.
347 				}
348 			}
349 
350 			active = false;
351 			exchange.finish( requestCapture.getCapturedData(), responseCapture.getCapturedData() );
352 			monitor.addMessageExchange( exchange );
353 		}
354 		catch( Exception e )
355 		{
356 			StringWriter st = new StringWriter();
357 			PrintWriter wr = new PrintWriter( st );
358 			e.printStackTrace( wr );
359 			wr.close();
360 			halt();
361 		}
362 	}
363 
364 	protected boolean isActive()
365 	{
366 		return active;
367 	}
368 
369 	/***
370 	 * Method wakeUp
371 	 */
372 	synchronized void wakeUp()
373 	{
374 		this.notifyAll();
375 	}
376 
377 	/***
378 	 * Method halt
379 	 */
380 	public void halt()
381 	{
382 		try
383 		{
384 			if( rr1 != null )
385 			{
386 				rr1.halt();
387 			}
388 			if( rr2 != null )
389 			{
390 				rr2.halt();
391 			}
392 			if( inSocket != null )
393 			{
394 				inSocket.close();
395 			}
396 			inSocket = null;
397 			if( outSocket != null )
398 			{
399 				outSocket.close();
400 			}
401 			outSocket = null;
402 		}
403 		catch( Exception e )
404 		{
405 			SoapUI.log.info( "Error halting connection: " + e.toString() );
406 		}
407 	}
408 
409 	/***
410 	 * Method remove
411 	 */
412 	public void remove()
413 	{
414 		try
415 		{
416 			halt();
417 		}
418 		catch( Exception e )
419 		{
420 			e.printStackTrace();
421 		}
422 	}
423 }