Index: java/org/apache/commons/httpclient/methods/PostMethod.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PostMethod.java,v retrieving revision 1.10 diff -u -u -r1.10 PostMethod.java --- java/org/apache/commons/httpclient/methods/PostMethod.java 10 Jul 2002 04:54:58 -0000 1.10 +++ java/org/apache/commons/httpclient/methods/PostMethod.java 10 Jul 2002 10:10:42 -0000 @@ -62,23 +62,39 @@ package org.apache.commons.httpclient.methods; -import java.io.*; -import java.util.*; import org.apache.commons.httpclient.HttpState; import org.apache.commons.httpclient.HttpConnection; import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.URIUtil; import org.apache.commons.httpclient.NameValuePair; -import java.util.Iterator; -import java.util.HashMap; -import java.util.List; +import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.log.Log; import org.apache.commons.httpclient.log.LogSource; +import java.util.Vector; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + /** * POST Method. + * This class encapsulates the HTTP POST specification. According to + * RFC2616: + *
The POST method is used to request that the origin server accept the + * entity enclosed in the request as a new subordinate of the resource + * identified by the Request-URI in the Request-Line. POST is designed + * to allow a uniform method to cover the following functions: + ** + * @author Jeffrey Dever * @author Remy Maucherat * @author Doug Sale */ @@ -103,7 +119,7 @@ } /** - * Constructor. + * Path and temp directory constructor. * @param path the path to request * @param tempDir directory to store temp files in */ @@ -112,7 +128,7 @@ } /** - * Constructor. + * Path, temp directory and temp file constructor. * @param path the path to request * @param tempDir directory to store temp files in * @param tempFile file to store temporary data in @@ -121,7 +137,8 @@ super(path, tempDir, tempFile); } - // ----------------------------------------------------- HttpMethod Methods + + // ----------------------------------------------------- Instance Methods /** * Returns "POST". @@ -142,71 +159,62 @@ } /** - * Overrides method of {@link HttpMethodBase} - * to throw {@link IllegalStateException} if - * my request body has already been - * {@link #generateRequestBody generated} - * or {@link #setRequestBody set}. + * Set the value of parameter with parameterName to parameterValue. + * Does not preserve the initial insertion order. * * @throws IllegalStateException if my request body has already been generated. + * @deprecated use #removeParameter followed by #setParameter */ public void setParameter(String parameterName, String parameterValue) { if(null != requestBody) { throw new IllegalStateException("Request body already generated."); } - parameters.put(parameterName,parameterValue); + removeParameter(parameterName, parameterValue); + addParameter(parameterName, parameterValue); } /** * Add a new parameter to be used in the POST request body. * - * @param parameterName The parameter name to add. - * @param parameterValue The parameter value to add. + * @param paramName The parameter name to add. + * @param paramValue The parameter value to add. * @throws IllegalStateException if my request body has already been generated. + * @throws IllegalArgumentException if either argument is null */ - public void addParameter(String parameterName, String parameterValue) { + public void addParameter(String paramName, String paramValue) { if(null != requestBody) { throw new IllegalStateException("Request body already generated."); } - Object old = parameters.put(parameterName,parameterValue); - if(null != old) { - List v = null; - if(old instanceof String) { - v = new ArrayList(); - v.add(old); - } else if(old instanceof List) { - v = (List)old; - } else { - throw new ClassCastException("Didn't expect to find " + - old.getClass().getName() + - " as parameter value for \"" + - parameterName + "\""); - } - v.add(parameterValue); - parameters.put(parameterName,v); + if (paramName == null || paramValue == null){ + throw new IllegalArgumentException("Arguments to addParameter(String, String) cannot be null"); + }else{ + parameters.add(new NameValuePair(paramName, paramValue)); } } /** * Add a new parameter to be used in the POST request body. - * Logs a warning if the parameter argument is null. * * @param parameter The parameter to add. * @throws IllegalStateException if my request body has already been generated. - * @see #addParameter(java.lang.String,java.lang.String) + * @throws IllegalArgumentException if the argument is null or contains null values + * @see #addParameter(String,String) * @since 2.0 */ - public void addParameter(NameValuePair parameter) { - if(null == parameter){ - log.warn("Attempt to addParameter(null) ignored"); + public void addParameter(NameValuePair param) { + if(null != requestBody) { + throw new IllegalStateException("Request body already generated."); + } + if(null == param){ + throw new IllegalArgumentException("Argument to addParameter(NameValuePair) cannot be null"); }else{ - addParameter(parameter.getName(), parameter.getValue()); + addParameter(param.getName(), param.getValue()); } } /** - * Add a list of parameters to be used in the POST request body. + * Add an Array of parameters to be used in the POST request body. * Logs a warning if the parameters argument is null. * * @param parameter The array of parameters to add. @@ -215,6 +223,9 @@ * @since 2.0 */ public void addParameters(NameValuePair[] parameters) { + if(null != requestBody) { + throw new IllegalStateException("Request body already generated."); + } if(null == parameters){ log.warn("Attempt to addParameters(null) ignored"); }else{ @@ -227,98 +238,112 @@ /** * Gets the parameter of the specified name. - * The returned object is new and is not a refrence to any - * internal data members. + * If there exists more than one parameter with the name paramName, + * then only the first one is returned. * * @return If a parameter exists with the name argument, the coresponding * NameValuePair is returned. Otherwise null. * @since 2.0 */ - public NameValuePair getParameter(String name){ - String value = null; - try{ - value = (String)parameters.get(name); - }catch (ClassCastException e){ - log.warn("Object of non-string type has been added as a parameter"); - value = null; - } - if (name == null || value == null){ + public NameValuePair getParameter(String paramName){ + if (paramName == null){ return null; - }else{ - return new NameValuePair(name, value); } + Iterator iter = parameters.iterator(); + while(iter.hasNext()){ + NameValuePair parameter = (NameValuePair)iter.next(); + if (paramName.equals(parameter.getName())){ + return parameter; + } + } + return null; } /** * Gets the parameters currently added to the PostMethod. - * The returned object is new and is not a refrence to any - * internal data members. + * If there are no parameters, a valid array is returned with + * zero elements. + * The returned array object contains an array of pointers to + * the internal data members. + * TODO: is it ok to return internal data? * * @return An array of the current parameters * @see #getParameter(java.lang.String); * @since 2.0 */ public NameValuePair[] getParameters(){ - Set keySet = parameters.keySet(); - Object[] keyArray = keySet.toArray(); - int numKeys = keyArray.length; - NameValuePair[] nvPairs = new NameValuePair[numKeys]; - Object key; - for (int i=0; i+ *
- Annotation of existing resources; + *
- Posting a message to a bulletin board, newsgroup, mailing list, + * or similar group of articles; + *
- Providing a block of data, such as the result of submitting a + * form, to a data-handling process; + *
- Extending a database through an append operation. + *
Once this method has been invoked, the request parameters + * cannot be altered until I am {@link #recycle recycled}. + * + * @return always returns true */ protected boolean writeRequestBody(HttpState state, HttpConnection conn) throws IOException, HttpException { log.debug("PostMethod.writeRequestBody(HttpState,HttpConnection)"); @@ -358,9 +404,7 @@ * Override method of {@link HttpMethodBase} * to return the length of the request body. * - * Once this method has been invoked, - * the request parameters cannot be altered - * until I am {@link #recycle recycled}. + @return number of bytes in the request body */ protected int getRequestContentLength() { if(null == requestBody) { @@ -369,45 +413,43 @@ return requestBody.getBytes().length; } - protected String generateRequestBody(Map params) { - if (!params.isEmpty()) { - StringBuffer sb = new StringBuffer(); - Iterator it = parameters.keySet().iterator(); - while(it.hasNext()) { - String name = (String)(it.next()); - Object value = parameters.get(name); - if(value instanceof List) { - List list = (List)value; - Iterator valit = list.iterator(); - while(valit.hasNext()) { - if(sb.length() > 0) { sb.append("&"); } - sb.append(URIUtil.encode(name,URIUtil.queryStringValueSafe(),true)); - Object val2 = valit.next(); - if(null != val2) { - sb.append("="); - sb.append(URIUtil.encode(String.valueOf(val2),URIUtil.queryStringValueSafe(),true)); - } - } - } else { - if(sb.length() > 0) { sb.append("&"); } - sb.append(URIUtil.encode(name,URIUtil.queryStringValueSafe())); - if(null != value) { - sb.append("="); - sb.append(URIUtil.encode(String.valueOf(value),URIUtil.queryStringValueSafe(),true)); - } - } + + // -------------------------------------------------------------- Class Methods + + /** + * Encode the list of parameters into a urlencoded string. + * + * TODO: consider moving this out into URIUtil. + * @return urlencoded string + */ + static String generateRequestBody(List params) { + Iterator it = params.iterator(); + StringBuffer sb = new StringBuffer(); + while(it.hasNext()) { + NameValuePair parameter = (NameValuePair)it.next(); + //TODO: make sure these encodings conform to the RFC + sb.append(URIUtil.encode(parameter.getName(), URIUtil.queryStringValueSafe(), false)); + sb.append("="); + sb.append(URIUtil.encode(parameter.getValue(), URIUtil.queryStringValueSafe(), true)); + if (it.hasNext()){ + sb.append("&"); } - return sb.toString(); - } else { - return ""; } + return sb.toString(); } + + // -------------------------------------------------------------- Instance Variables + private String requestBody = null; - private HashMap parameters = new HashMap(); + private Vector parameters = new Vector(); + // -------------------------------------------------------------- Constants /** org.apache.commons.httpclient.methods.PostMethod log. */ private static final Log log = LogSource.getInstance("org.apache.commons.httpclient.methods.PostMethod"); + + /** The Content-Type header for www-form-urlcoded. */ + static final Header CONTENT_TYPE = new Header ("Content-Type","application/x-www-form-urlencoded"); } Index: test/org/apache/commons/httpclient/TestMethodsNoHost.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestMethodsNoHost.java,v retrieving revision 1.2 diff -u -u -r1.2 TestMethodsNoHost.java --- test/org/apache/commons/httpclient/TestMethodsNoHost.java 10 Jul 2002 04:54:58 -0000 1.2 +++ test/org/apache/commons/httpclient/TestMethodsNoHost.java 10 Jul 2002 10:10:43 -0000 @@ -66,6 +66,7 @@ import org.apache.commons.httpclient.methods.*; /** + * @author Jeffrey Dever * @author Rodney Waldhoff * @version $Revision: 1.2 $ $Date: 2002/07/10 04:54:58 $ */ @@ -79,7 +80,7 @@ static final NameValuePair PAIR0 = new NameValuePair(NAME0, VALUE0); static final NameValuePair PAIR1 = new NameValuePair(NAME1, VALUE1); static final NameValuePair PAIR2 = new NameValuePair(NAME2, VALUE2); - + // ------------------------------------------------------------ Constructor @@ -106,6 +107,7 @@ } } + /** Ensure setRequestBody fails after addParameter is called. */ public void testPostCantSetBodyAfterAddParam() throws Exception { PostMethod post = new PostMethod("/foo"); post.addParameter("name","value"); @@ -117,11 +119,11 @@ } } - + /** Ensure that parameters can be added and getted. */ public void testPostAddGetParameter() { PostMethod post = new PostMethod(); - + //no parameters assertNull(post.getParameter("non-existant")); assertEquals(0, post.getParameters().length); @@ -135,7 +137,7 @@ post.addParameter(PAIR0); assertEquals(PAIR0, post.getParameter(PAIR0.getName())); assertEquals(2, post.getParameters().length); - + //add two more parameters post.addParameters(new NameValuePair[]{ PAIR1, PAIR2 }); assertEquals(4, post.getParameters().length); @@ -150,18 +152,57 @@ public void testPostAddParameterErrorCases() { PostMethod post = new PostMethod(); + //add null paramters + try{ + post.addParameter(null); + fail("Expected IllegalArgumentException"); + } catch(IllegalArgumentException e) { } + + try{ + post.addParameter(null, "value"); + fail("Expected IllegalArgumentException"); + } catch(IllegalArgumentException e) { } + + try{ + post.addParameter("name", null); + fail("Expected IllegalArgumentException"); + } catch(IllegalArgumentException e) { } + } + + /** Adding the same parameter twice should be OK. */ + public void testPostAddSameParameter() { + PostMethod post = new PostMethod(); + //add same parameter twice post.addParameter(PAIR0); post.addParameter(PAIR0); - assertEquals(1, post.getParameters().length); - //add null paramter - post.addParameter(null); - post.addParameter(null, "value"); - post.addParameter("name", null); + assertEquals(2, post.getParameters().length); + NameValuePair[] pairs = post.getParameters(); + assertEquals(pairs[0], pairs[1]); + } + + public void testPostParametersEncoding(){ + PostMethod post = new PostMethod(); + post.addParameter(PAIR); + assertEquals("name=value", post.getRequestBody()); + + post.addParameters(new NameValuePair[]{ PAIR1, PAIR2 }); + assertEquals("name=value&name1=value1&name2=value2", post.getRequestBody()); + + post.addParameter("hasSpace", "a b c d"); + assertEquals("name=value&name1=value1&name2=value2&hasSpace=a+b+c+d", post.getRequestBody()); + } - - + + public void testPostSetRequestBody() throws Exception { + PostMethod post = new PostMethod("/foo"); + String body = "this+is+the+body"; + post.setRequestBody(body); + assertEquals(body, post.getRequestBody()); + } + + public void testPostSetRequestBodyThrowsIllegalState() throws Exception { PostMethod post = new PostMethod("/foo"); post.addParameter(NAME0, VALUE0);