dion 2002/07/10 04:33:29
Modified: httpclient/src/java/org/apache/commons/httpclient/methods
PostMethod.java
Log:
Fix for bug 10634 kindly provided by Jeffrey Dever.
Cleanups and tests also provided.
Revision Changes Path
1.11 +179 -137 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PostMethod.java
Index: PostMethod.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PostMethod.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- PostMethod.java 10 Jul 2002 04:54:58 -0000 1.10
+++ PostMethod.java 10 Jul 2002 11:33:29 -0000 1.11
@@ -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
+ * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
+ * <blockquote>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:
+ * <ul><li>Annotation of existing resources;
+ * <li>Posting a message to a bulletin board, newsgroup, mailing list,
+ * or similar group of articles;
+ * <li>Providing a block of data, such as the result of submitting a
+ * form, to a data-handling process;
+ * <li>Extending a database through an append operation.
+ * </ul>
+ * </blockquote>
*
+ * @author <a href="mailto:jsdever@sympatico.ca">Jeffrey Dever</a>
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
* @author <a href="mailto:dsale@us.britannica.com">Doug Sale</a>
*/
@@ -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 <tt>"POST"</tt>.
@@ -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 <b>not</b> 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 <b>not</b> 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<numKeys; i++){
- nvPairs[i] = this.getParameter((String)keyArray[i]);
- }
- return nvPairs;
+ int numPairs = parameters.size();
+ Object[] objectArr= parameters.toArray();
+ NameValuePair[] nvPairArr = new NameValuePair[numPairs];
+ for(int i=0; i<numPairs; i++){
+ nvPairArr[i] = (NameValuePair)objectArr[i];
+ }
+ return nvPairArr;
}
/**
- * Overrides method of {@link HttpMethodBase}
- * to throw {@link IllegalStateException} if
- * my request body has already been
- * {@link #generateRequestBody generated}
- * or {@link #setRequestBody set}.
- *
+ * Removes all parameters with the given paramName.
+ * If there is more than one parameter with the given paramName, all
+ * of them are removed. If there is just one, it is removed. If there
+ * are none, then the request is ignored.
+ *
+ * @param paramName The parameter name to remove.
+ * @return true if at least one parameter was removed
* @throws IllegalStateException if my request body has already been generated.
*/
- public void removeParameter(String paramName) {
+ public boolean removeParameter(String paramName) {
if(null != requestBody) {
throw new IllegalStateException("Request body already generated.");
}
- parameters.remove(paramName);
+ if (paramName == null){
+ throw new IllegalArgumentException("Argument passed to removeParameter(String)
cannot be null");
+ }
+ boolean removed = true;
+ Iterator iter = parameters.iterator();
+ while(iter.hasNext()){
+ NameValuePair pair = (NameValuePair)iter.next();
+ if (paramName.equals(pair.getName())){
+ iter.remove();
+ removed = true;
+ }
+ }
+ return removed;
}
/**
- * Overrides method of {@link HttpMethodBase}
- * to throw {@link IllegalStateException} if
- * my request body has already been
- * {@link #generateRequestBody generated}
- * or {@link #setRequestBody set}.
+ * Removes all parameter with the given paramName and paramValue.
+ * If there is more than one parameter with the given paramName, only
+ * one is removed. If there are none, then the request is ignored.
*
+ * @param paramName The parameter name to remove.
+ * @param paramValue The parameter value to remove.
+ * @return true if a parameter was removed.
* @throws IllegalStateException if my request body has already been generated.
*/
- public void removeParameter(String paramName, String paramValue) {
+ public boolean removeParameter(String paramName, String paramValue) {
if(null != requestBody) {
throw new IllegalStateException("Request body already generated.");
}
- Object old = parameters.get(paramName);
- if(null != old) {
- if(paramValue.equals(old)) {
- parameters.remove(paramName);
- } else if(old instanceof List) {
- List list = (List)old;
- if(list.remove(paramValue)) {
- if(list.isEmpty()) {
- parameters.remove(paramName);
- } else if(list.size() == 1) {
- parameters.put(paramName,list.get(0));
- } else {
- parameters.put(paramValue,list);
- }
- }
+ if (paramName == null || paramValue == null){
+ throw new IllegalArgumentException("Argument passed to removeParameter(String,String)
cannot be null");
+ }
+ Iterator iter = parameters.iterator();
+ while(iter.hasNext()){
+ NameValuePair pair = (NameValuePair)iter.next();
+ if (paramName.equals(pair.getName()) && paramValue.equals(pair.getValue())){
+ iter.remove();
+ return true;
}
}
+ return false;
}
- /**
+ /**
+ * Sets the request body to be the specified string.
+ *
+ * <p>Once this method has been invoked, the request parameters
+ * cannot be altered until I am {@link #recycle recycled}.
+ *
* @throws IllegalStateException if request params have been added
*/
public void setRequestBody(String body) {
@@ -329,21 +354,42 @@
}
/**
- * Override method of {@link HttpMethodBase}
- * to also add <tt>Content-Type</tt> header
+ * Gets the requestBody as it would be if it was executed.
+ *
+ * @return The request body if it has been set. The generated
+ * request body from the paramters if they exist. Null otherwise.
+ * @since 2.0
+ */
+ public String getRequestBody() {
+ if(requestBody != null){
+ return requestBody;
+ }else if (!parameters.isEmpty()){
+ return generateRequestBody(parameters);
+ }else{
+ return null;
+ }
+ }
+
+
+ /**
+ * Override method of {@link HttpMethodBase} to also add <tt>Content-Type</tt>
header
* when appropriate.
*/
protected void addRequestHeaders(HttpState state, HttpConnection conn) throws IOException,
HttpException {
super.addRequestHeaders(state,conn);
- if(!parameters.isEmpty()) {
- setRequestHeader("Content-Type","application/x-www-form-urlencoded");
+ if(!parameters.isEmpty()) { //there are some parameters, so set the contentType
header
+ setRequestHeader(CONTENT_TYPE);
}
}
/**
* Override method of {@link HttpMethodBase}
- * to write request parameters as the
- * request body.
+ * to write request parameters as the request body.
+ *
+ * <p>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
/** <tt>org.apache.commons.httpclient.methods.PostMethod</tt> 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");
}
--
To unsubscribe, e-mail: <mailto:commons-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:commons-dev-help@jakarta.apache.org>
|