You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@wookie.apache.org by sc...@apache.org on 2010/02/16 23:27:37 UTC

svn commit: r910736 - in /incubator/wookie/trunk: src-tests/org/apache/wookie/tests/functional/ProxyTest.java src/org/apache/wookie/proxy/ProxyClient.java src/org/apache/wookie/proxy/ProxyServlet.java

Author: scottbw
Date: Tue Feb 16 22:27:36 2010
New Revision: 910736

URL: http://svn.apache.org/viewvc?rev=910736&view=rev
Log:
Fixed a problem reported for WOOKIE-116 reported by Aaron Duley, whereby a formdata request results in an illegal state (STREAMED) error. This is caused by accessing parameters (which calls an InputStream) and a Reader to read content on the same request/response. I've changed the "sendXMLData" code and added more test cases to check behaviour. I've also made parts of the proxy code return more meaningful exception types to make debugging easier.

Modified:
    incubator/wookie/trunk/src-tests/org/apache/wookie/tests/functional/ProxyTest.java
    incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyClient.java
    incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyServlet.java

Modified: incubator/wookie/trunk/src-tests/org/apache/wookie/tests/functional/ProxyTest.java
URL: http://svn.apache.org/viewvc/incubator/wookie/trunk/src-tests/org/apache/wookie/tests/functional/ProxyTest.java?rev=910736&r1=910735&r2=910736&view=diff
==============================================================================
--- incubator/wookie/trunk/src-tests/org/apache/wookie/tests/functional/ProxyTest.java (original)
+++ incubator/wookie/trunk/src-tests/org/apache/wookie/tests/functional/ProxyTest.java Tue Feb 16 22:27:36 2010
@@ -16,10 +16,14 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.commons.httpclient.Credentials;
 import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.httpclient.HttpMethod;
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthPolicy;
 import org.apache.commons.httpclient.auth.AuthScope;
 import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.commons.httpclient.methods.PostMethod;
@@ -34,7 +38,7 @@
 	private static final String VALID_SITE_URL = "http://incubator.apache.org/wookie/";
 	private static final String INVALID_SITE_URL = "DFASFAFEQ3FQ32145235123452";
 	private static final String BLOCKED_SITE_URL = "http://very.bad.place";
-	private static final String PROTECTED_SITE_URL = "http://localhost:8080/wookie/admin";
+	private static final String PROTECTED_SITE_URL = "http://localhost:8080/wookie/admin/";
 
 	/**
 	 * Create an instance of a widget
@@ -89,12 +93,55 @@
 		String url = PROXY_URL+"?instanceid_key="+instance_id_key+"&url="+BLOCKED_SITE_URL;
 		assertEquals(403,send(url,"GET"));
 	}
+	
+	@Test
+	public void postWithMixedQueryAndParameters() throws Exception{
+		HttpClient client = new HttpClient();
+		List<String> authPrefs =  new ArrayList<String>(2);
+		authPrefs.add(AuthPolicy.DIGEST );
+		authPrefs.add(AuthPolicy.BASIC);
+		client.getParams().setParameter (AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
+		// send the basic authentication response even before the server gives an unauthorized response
+		client.getParams().setAuthenticationPreemptive(true);
+		client.getState().setCredentials(
+				new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM),
+				new UsernamePasswordCredentials("java", "java"));
+		PostMethod req;
+		req = new PostMethod(PROXY_URL+"?instanceid_key="+instance_id_key);
+		req.addParameter("url", PROTECTED_SITE_URL);
+		client.executeMethod(req);
+		int code = req.getStatusCode();
+		req.releaseConnection();
+		assertEquals(200,code);
+	}
+
+	@Test
+	public void postWithOnlyParameters() throws Exception{
+		HttpClient client = new HttpClient();
+		List<String> authPrefs =  new ArrayList<String>(2);
+		authPrefs.add(AuthPolicy.DIGEST );
+		authPrefs.add(AuthPolicy.BASIC);
+		client.getParams().setParameter (AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
+		// send the basic authentication response even before the server gives an unauthorized response
+		client.getParams().setAuthenticationPreemptive(true);
+		client.getState().setCredentials(
+				new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM),
+				new UsernamePasswordCredentials("java", "java"));
+		PostMethod req;
+		req = new PostMethod(PROXY_URL);
+		req.addParameter("url", PROTECTED_SITE_URL);
+		req.addParameter("instanceid_key", instance_id_key);
+		client.executeMethod(req);
+		int code = req.getStatusCode();
+		req.releaseConnection();
+		assertEquals(200,code);
+	}
 
 	@Test
 	public void getProtectedSiteWithoutAuth() throws Exception{
 		HttpClient client = new HttpClient();
 		HttpMethod req;
-		req = new GetMethod(PROTECTED_SITE_URL);
+		req = new GetMethod(PROXY_URL+"?instanceid_key="+instance_id_key+"&url="+PROTECTED_SITE_URL);
 		client.executeMethod(req);
 		int code = req.getStatusCode();
 		req.releaseConnection();
@@ -104,10 +151,17 @@
 	@Test
 	public void getProtectedSiteWithBasicAuth() throws Exception{
 		HttpClient client = new HttpClient();
-		Credentials defaultcreds = new UsernamePasswordCredentials("java", "java");
-		client.getState().setCredentials(new AuthScope("localhost", 8080, AuthScope.ANY_REALM), defaultcreds);
+		List<String> authPrefs =  new ArrayList<String>(2);
+		authPrefs.add(AuthPolicy.DIGEST );
+		authPrefs.add(AuthPolicy.BASIC);
+		client.getParams().setParameter (AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
+		// send the basic authentication response even before the server gives an unauthorized response
+		client.getParams().setAuthenticationPreemptive(true);
+		client.getState().setCredentials(
+				new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM),
+				new UsernamePasswordCredentials("java", "java"));		
 		HttpMethod req;
-		req = new GetMethod(PROTECTED_SITE_URL);
+		req = new GetMethod(PROXY_URL+"?instanceid_key="+instance_id_key+"&url="+PROTECTED_SITE_URL);
 		client.executeMethod(req);
 		int code = req.getStatusCode();
 		req.releaseConnection();

Modified: incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyClient.java
URL: http://svn.apache.org/viewvc/incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyClient.java?rev=910736&r1=910735&r2=910736&view=diff
==============================================================================
--- incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyClient.java (original)
+++ incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyClient.java Tue Feb 16 22:27:36 2010
@@ -16,6 +16,7 @@
 
 import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
@@ -33,6 +34,7 @@
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
 import org.apache.commons.httpclient.auth.AuthPolicy;
 import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.commons.httpclient.auth.AuthenticationException;
 import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
 import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.commons.httpclient.methods.PostMethod;
@@ -57,7 +59,7 @@
 		String proxyUserName = request.getParameter("username");
 		String proxyPassword = request.getParameter("password");
 		String base64Auth = request.getHeader("Authorization");  
-		if(proxyUserName != null && proxyPassword != null )							
+		if(proxyUserName != null && proxyPassword != null )	
 			this.setProxyAuthConfig(proxyUserName, proxyPassword);
 		if(base64Auth != null)
 			this.setBase64AuthConfig(base64Auth);
@@ -102,8 +104,7 @@
 	}
 
 
-	@SuppressWarnings("unchecked")
-	private String executeMethod(HttpMethod method, Configuration properties) throws Exception {
+	private String executeMethod(HttpMethod method, Configuration properties) throws Exception, AuthenticationException {
 		// Execute the method.
 		try {		
 			HttpClient client = new HttpClient();
@@ -115,7 +116,7 @@
 					method.setRequestHeader("Authorization", fBase64Auth);
 				}
 				else {
-					List authPrefs =  new ArrayList(2);
+					List<String> authPrefs =  new ArrayList<String>(2);
 					authPrefs.add(AuthPolicy.DIGEST );
 					authPrefs.add(AuthPolicy.BASIC);
 					client.getParams().setParameter (AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
@@ -124,12 +125,10 @@
 					// Pass our credentials to HttpClient
 					client.getState().setCredentials(
 							new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM),
-							// this needs to be tenc username & password!
 							new UsernamePasswordCredentials(fProxyUsername, fProxyPassword));
 				}
 			}
 
-
 			// Add user language to http request in order to notify server of user's language
 			Locale locale = Locale.getDefault();
 
@@ -138,23 +137,20 @@
 			int statusCode = client.executeMethod(method);
 
 			if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_CREATED) {
-
 				Header hType = method.getResponseHeader("Content-type");					
 				fContentType = hType.getValue();
 				// for now we are only expecting Strings					
-				return method.getResponseBodyAsString();
-				//return readFully(new InputStreamReader(method.getResponseBodyAsStream(), "UTF-8"));
+				//return method.getResponseBodyAsString();
+				return readFully(new InputStreamReader(method.getResponseBodyAsStream(), "UTF-8"));
 			}
-			else if (statusCode == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED)
-				throw new Exception("ERROR_PROXY"); 
-			else if (statusCode == HttpStatus.SC_UNAUTHORIZED)
-				throw new Exception("ERROR_INVALID_PASSWORD"); 																			
+			else if (statusCode == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED || statusCode == HttpStatus.SC_UNAUTHORIZED)
+				throw new AuthenticationException();																			
 			else {
 				throw new Exception("Method failed: " + method.getStatusLine() + ' ' + method.getURI() + ' ' + method.getStatusText() + method.getResponseBodyAsString()); //$NON-NLS-1$
 			}
 		} 
 		catch (IOException e) {
-			throw new Exception("ERROR_CONNECT", e);
+			throw e;
 		} 
 		finally {
 			// Release the connection.

Modified: incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyServlet.java
URL: http://svn.apache.org/viewvc/incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyServlet.java?rev=910736&r1=910735&r2=910736&view=diff
==============================================================================
--- incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyServlet.java (original)
+++ incubator/wookie/trunk/src/org/apache/wookie/proxy/ProxyServlet.java Tue Feb 16 22:27:36 2010
@@ -30,14 +30,13 @@
 import javax.servlet.http.HttpSession;
 
 import org.apache.commons.configuration.Configuration;
+import org.apache.commons.httpclient.auth.AuthenticationException;
 import org.apache.log4j.Logger;
 import org.apache.wookie.Messages;
 import org.apache.wookie.beans.Whitelist;
 import org.apache.wookie.beans.WidgetInstance;
 import org.apache.wookie.server.LocaleHandler;
 
-import java.io.BufferedReader;
-
 /**
  * A web proxy servlet which will translate calls for content and return them as if they came from
  * this domain
@@ -105,7 +104,11 @@
 		}
 		catch (Exception ex) {
 			try {
-				response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());
+				if (ex instanceof AuthenticationException){
+					response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+				} else {
+					response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());
+				}
 				fLogger.error(ex.getMessage());
 				throw new ServletException(ex);
 			} catch (IOException e) {
@@ -123,18 +126,15 @@
 	 * @throws IOException
 	 */
 	private String getXmlData(HttpServletRequest request) throws IOException{
-		BufferedReader br = request.getReader();  
-		StringBuffer sb = new StringBuffer();  
-		String line;
-		while ((line = br.readLine()) != null) {  
-			sb.append(line);  
-		}  
-		br.close();  
-		String xml = sb.toString();	
+		// Note that we cannot use a Reader for this as we already
+		// call getParameter() which works on an InputStream - and you
+		// can only use an InputStream OR a Reader, not both.
+		byte[] b = new byte[request.getContentLength()];
+		request.getInputStream().read(b, 0, request.getContentLength());
+		String xml = new String(b);
 		return xml;
 	}
 
-
 	private boolean isValidUser(HttpServletRequest request, boolean checkDomain){
 		return isSameDomain(request, checkDomain) && isValidWidgetInstance(request);
 	}
@@ -206,41 +206,40 @@
 		}	
 
 		private void doParse(HttpServletRequest request) throws MalformedURLException, UnsupportedEncodingException{
-
 			URL proxiedEndPointURL = null;
 			String endPointURL = null;
 
+			// Try to find a "url" parameter from the QueryString of the request
 			String file = request.getRequestURI();
 			if (request.getQueryString() != null) {
 				file += '?' + request.getQueryString();
-			}
-			// the request didn't contain any params
-			else{	
+				// build the requested path
+				proxiedEndPointURL = new URL(request.getScheme(),request.getServerName(),request.getServerPort() , file);
+				// find where the url parameter is ..
+				int idx = proxiedEndPointURL.toString().indexOf("url=");
+				if(idx>-1){
+					// reconstruct the path to be proxied by removing the reference to this servlet
+					endPointURL=proxiedEndPointURL.toString().substring(idx+4,proxiedEndPointURL.toString().length());
+				}
+			}
+
+			// try to locate a POST form parameter instead
+			if (endPointURL == null)	
+				endPointURL=request.getParameter("url");
+			
+			// the request didn't contain any params, so throw an exception
+			if (endPointURL == null)	
 				throw new MalformedURLException("Unable to obtain url from args");
-			}
 
-			// build the requested path
-			proxiedEndPointURL = new URL(request.getScheme() ,
-					request.getServerName() ,
-					request.getServerPort() , file);
-
-			// find where the url parameter is ..
-			int idx = proxiedEndPointURL.toString().indexOf("url=");
-			if(idx>-1){
-				// reconstruct the path to be proxied by removing the reference to this servlet
-				endPointURL=proxiedEndPointURL.toString().substring(idx+4,proxiedEndPointURL.toString().length());
-			}												
 			try {
 				fNewUrl = new URL(endPointURL);
-			} 
-			catch (Exception ex) {
+			} catch (Exception ex) {
 				// try decoding the URL
 				fNewUrl = new URL(URLDecoder.decode(endPointURL, "UTF-8"));
 			}
 		}
 
 		public URL getNewUrl() {
-
 			return fNewUrl;
 		}