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