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