View Javadoc

1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PostMethod.java,v 1.45.2.7 2004/08/08 12:50:57 olegk Exp $
3    * $Revision: 1.45.2.7 $
4    * $Date: 2004/08/08 12:50:57 $
5    *
6    * ====================================================================
7    *
8    *  Copyright 1999-2004 The Apache Software Foundation
9    *
10   *  Licensed under the Apache License, Version 2.0 (the "License");
11   *  you may not use this file except in compliance with the License.
12   *  You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   * ====================================================================
22   *
23   * This software consists of voluntary contributions made by many
24   * individuals on behalf of the Apache Software Foundation.  For more
25   * information on the Apache Software Foundation, please see
26   * <http://www.apache.org/>.
27   *
28   * [Additional notices, if required by prior licensing conditions]
29   *
30   */
31  package org.apache.commons.httpclient.methods;
32  
33  import java.io.IOException;
34  import java.util.Iterator;
35  import java.util.Vector;
36  
37  import org.apache.commons.httpclient.HttpConnection;
38  import org.apache.commons.httpclient.HttpConstants;
39  import org.apache.commons.httpclient.HttpException;
40  import org.apache.commons.httpclient.HttpState;
41  import org.apache.commons.httpclient.NameValuePair;
42  import org.apache.commons.httpclient.util.EncodingUtil;
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  
46  /***
47   * Implements the HTTP POST method.
48   * <p>
49   * The HTTP POST method is defined in section 9.5 of 
50   * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
51   * <blockquote>
52   * The POST method is used to request that the origin server accept the entity
53   * enclosed in the request as a new subordinate of the resource identified by
54   * the Request-URI in the Request-Line. POST is designed to allow a uniform
55   * method to cover the following functions:
56   * <ul>
57   *   <li>Annotation of existing resources</li>
58   *   <li>Posting a message to a bulletin board, newsgroup, mailing list, or 
59   *     similar group of articles</li>
60   *   <li>Providing a block of data, such as the result of submitting a form,
61   *     to a data-handling process</li>
62   *   <li>Extending a database through an append operation</li>
63   * </ul>
64   * </blockquote>
65   * </p>
66   *
67   * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
68   * @author <a href="mailto:dsale@us.britannica.com">Doug Sale</a>
69   * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
70   * @author Ortwin Gl?ck
71   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
72   * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
73   *
74   * @version $Revision: 1.45.2.7 $
75   * @since 1.0
76   */
77  public class PostMethod extends EntityEnclosingMethod {
78      // -------------------------------------------------------------- Constants
79  
80      /*** Log object for this class. */
81      private static final Log LOG = LogFactory.getLog(PostMethod.class);
82  
83      /*** The Content-Type for www-form-urlencoded. */
84      public static final String FORM_URL_ENCODED_CONTENT_TYPE = 
85          "application/x-www-form-urlencoded";
86  
87      /*** 
88       * The buffered request body consisting of <code>NameValuePair</code>s. 
89       */
90      private Vector params = new Vector();
91  
92      // ----------------------------------------------------------- Constructors
93  
94      /***
95       * No-arg constructor.
96       *
97       * @since 1.0
98       */
99      public PostMethod() {
100         super();
101     }
102 
103     /***
104      * Constructor specifying a URI.
105      *
106      * @param uri either an absolute or relative URI
107      *
108      * @since 1.0
109      */
110     public PostMethod(String uri) {
111         super(uri);
112     }
113 
114     /***
115      * Constructor specifying a URI and a tempDir.
116      *
117      * @param uri either an absolute or relative URI
118      * @param tempDir directory to store temp files in
119      *
120      * @deprecated the client is responsible for disk I/O
121      * @since 1.0
122      */
123     public PostMethod(String uri, String tempDir) {
124         super(uri, tempDir);
125     }
126 
127     /***
128      * Constructor specifying a URI, tempDir and tempFile.
129      *
130      * @param uri either an absolute or relative URI
131      * @param tempDir directory to store temp files in
132      * @param tempFile file to store temporary data in
133      *
134      * @deprecated the client is responsible for disk I/O
135      * @since 1.0
136      */
137     public PostMethod(String uri, String tempDir, String tempFile) {
138         super(uri, tempDir, tempFile);
139     }
140 
141     // ----------------------------------------------------- Instance Methods
142 
143     /***
144      * Returns <tt>"POST"</tt>.
145      *
146      * @return <tt>"POST"</tt>
147      *
148      * @since 2.0
149      */
150     public String getName() {
151         return "POST";
152     }
153 
154 
155     /***
156      * Returns <tt>true</tt> if there is a request body to be sent.
157      * 
158      * <P>This method must be overwritten by sub-classes that implement
159      * alternative request content input methods
160      * </p>
161      * 
162      * @return boolean
163      * 
164      * @since 2.0beta1
165      */
166     protected boolean hasRequestContent() {
167         LOG.trace("enter PostMethod.hasRequestContent()");
168         if (!this.params.isEmpty()) {
169             return true;
170         } else {
171             return super.hasRequestContent();
172         }
173     }
174 
175     /***
176      * Clears request body.
177      * 
178      * <p>This method must be overwritten by sub-classes that implement
179      * alternative request content input methods</p>
180      * 
181      * @since 2.0beta1
182      */
183     protected void clearRequestBody() {
184         LOG.trace("enter PostMethod.clearRequestBody()");
185         this.params.clear();
186         super.clearRequestBody();
187     }
188 
189     /***
190      * Generates the request body.
191      * 
192      * <p>This method must be overwritten by sub-classes that implement
193      * alternative request content input methods
194      * </p>   
195      * 
196      * @return request body as an array of bytes. If the request content 
197      *          has not been set, returns <tt>null</tt>.
198      * 
199      * @since 2.0beta1
200      */
201     protected byte[] generateRequestBody() {
202         LOG.trace("enter PostMethod.renerateRequestBody()");
203         if (!this.params.isEmpty()) {
204             String content = EncodingUtil.formUrlEncode(getParameters(), getRequestCharSet());
205             return HttpConstants.getContentBytes(content);
206         } else {
207             return super.generateRequestBody();
208         }
209     }
210 
211 
212     /***
213      * Sets the value of parameter with parameterName to parameterValue. This method
214      * does not preserve the initial insertion order.
215      *
216      * @param parameterName name of the parameter
217      * @param parameterValue value of the parameter
218      *
219      * @since 2.0
220      */
221     public void setParameter(String parameterName, String parameterValue) {
222         LOG.trace("enter PostMethod.setParameter(String, String)");
223 
224         removeParameter(parameterName);
225         addParameter(parameterName, parameterValue);
226     }
227 
228     /***
229      * Gets the parameter of the specified name. If there exists more than one
230      * parameter with the name paramName, then only the first one is returned.
231      *
232      * @param paramName name of the parameter
233      *
234      * @return If a parameter exists with the name argument, the coresponding
235      *         NameValuePair is returned.  Otherwise null.
236      *
237      * @since 2.0
238      * 
239      */
240     public NameValuePair getParameter(String paramName) {
241         LOG.trace("enter PostMethod.getParameter(String)");
242 
243         if (paramName == null) {
244             return null;
245         }
246 
247         Iterator iter = this.params.iterator();
248 
249         while (iter.hasNext()) {
250             NameValuePair parameter = (NameValuePair) iter.next();
251 
252             if (paramName.equals(parameter.getName())) {
253                 return parameter;
254             }
255         }
256         return null;
257     }
258 
259     /***
260      * Gets the parameters currently added to the PostMethod. If there are no
261      * parameters, a valid array is returned with zero elements. The returned
262      * array object contains an array of pointers to  the internal data
263      * members.
264      *
265      * @return An array of the current parameters
266      *
267      * @since 2.0
268      * 
269      */
270     public NameValuePair[] getParameters() {
271         LOG.trace("enter PostMethod.getParameters()");
272 
273         int numPairs = this.params.size();
274         Object[] objectArr = this.params.toArray();
275         NameValuePair[] nvPairArr = new NameValuePair[numPairs];
276 
277         for (int i = 0; i < numPairs; i++) {
278             nvPairArr[i] = (NameValuePair) objectArr[i];
279         }
280 
281         return nvPairArr;
282     }
283 
284     /***
285      * Adds a new parameter to be used in the POST request body.
286      *
287      * @param paramName The parameter name to add.
288      * @param paramValue The parameter value to add.
289      *
290      * @throws IllegalArgumentException if either argument is null
291      *
292      * @since 1.0
293      */
294     public void addParameter(String paramName, String paramValue) 
295     throws IllegalArgumentException {
296         LOG.trace("enter PostMethod.addParameter(String, String)");
297 
298         if ((paramName == null) || (paramValue == null)) {
299             throw new IllegalArgumentException(
300                 "Arguments to addParameter(String, String) cannot be null");
301         }
302         super.clearRequestBody();
303         this.params.add(new NameValuePair(paramName, paramValue));
304     }
305 
306     /***
307      * Adds a new parameter to be used in the POST request body.
308      *
309      * @param param The parameter to add.
310      *
311      * @throws IllegalArgumentException if the argument is null or contains
312      *         null values
313      *
314      * @since 2.0
315      */
316     public void addParameter(NameValuePair param) 
317     throws IllegalArgumentException {
318         LOG.trace("enter PostMethod.addParameter(NameValuePair)");
319 
320         if (param == null) {
321             throw new IllegalArgumentException("NameValuePair may not be null");
322         }
323         addParameter(param.getName(), param.getValue());
324     }
325 
326     /***
327      * Adds an array of parameters to be used in the POST request body. Logs a
328      * warning if the parameters argument is null.
329      *
330      * @param parameters The array of parameters to add.
331      *
332      * @since 2.0
333      */
334     public void addParameters(NameValuePair[] parameters) {
335         LOG.trace("enter PostMethod.addParameters(NameValuePair[])");
336 
337         if (parameters == null) {
338             LOG.warn("Attempt to addParameters(null) ignored");
339         } else {
340             super.clearRequestBody();
341             for (int i = 0; i < parameters.length; i++) {
342                 this.params.add(parameters[i]);
343             }
344         }
345     }
346 
347     /***
348      * Removes all parameters with the given paramName. If there is more than
349      * one parameter with the given paramName, all of them are removed.  If
350      * there is just one, it is removed.  If there are none, then the request
351      * is ignored.
352      *
353      * @param paramName The parameter name to remove.
354      *
355      * @return true if at least one parameter was removed
356      *
357      * @throws IllegalArgumentException When the parameter name passed is null
358      *
359      * @since 2.0
360      */
361     public boolean removeParameter(String paramName) 
362     throws IllegalArgumentException {
363         LOG.trace("enter PostMethod.removeParameter(String)");
364 
365         if (paramName == null) {
366             throw new IllegalArgumentException(
367                 "Argument passed to removeParameter(String) cannot be null");
368         }
369         boolean removed = false;
370         Iterator iter = this.params.iterator();
371 
372         while (iter.hasNext()) {
373             NameValuePair pair = (NameValuePair) iter.next();
374 
375             if (paramName.equals(pair.getName())) {
376                 iter.remove();
377                 removed = true;
378             }
379         }
380         return removed;
381     }
382 
383     /***
384      * Removes all parameter with the given paramName and paramValue. If there
385      * is more than one parameter with the given paramName, only one is
386      * removed.  If there are none, then the request is ignored.
387      *
388      * @param paramName The parameter name to remove.
389      * @param paramValue The parameter value to remove.
390      *
391      * @return true if a parameter was removed.
392      *
393      * @throws IllegalArgumentException when param name or value are null
394      *
395      * @since 2.0
396      */
397     public boolean removeParameter(String paramName, String paramValue) 
398     throws IllegalArgumentException {
399         LOG.trace("enter PostMethod.removeParameter(String, String)");
400 
401         if (paramName == null) {
402             throw new IllegalArgumentException("Parameter name may not be null");
403         }
404         if (paramValue == null) {
405             throw new IllegalArgumentException("Parameter value may not be null");
406         }
407 
408         Iterator iter = this.params.iterator();
409 
410         while (iter.hasNext()) {
411             NameValuePair pair = (NameValuePair) iter.next();
412 
413             if (paramName.equals(pair.getName())
414                 && paramValue.equals(pair.getValue())) {
415                 iter.remove();
416                 return true;
417             }
418         }
419 
420         return false;
421     }
422 
423     /***
424      * Sets an array of parameters to be used in the POST request body
425      *
426      * @param parametersBody The array of parameters to add.
427      *
428      * @throws IllegalArgumentException when param parameters are null
429      * 
430      * @since 2.0beta1
431      */
432     public void setRequestBody(NameValuePair[] parametersBody)
433     throws IllegalArgumentException {
434         LOG.trace("enter PostMethod.setRequestBody(NameValuePair[])");
435 
436         if (parametersBody == null) {
437             throw new IllegalArgumentException("Array of parameters may not be null");
438         }
439         clearRequestBody();
440         addParameters(parametersBody);
441     }
442 
443     /***
444      * Adds <tt>Content Type: application/x-www-form-urlencoded</tt> header in
445      * addition to the "standard" set of headers, if no <tt>Content Type</tt>
446      * header has been set by the user 
447      * 
448      * @param state the {@link HttpState state} information associated with this method
449      * @param conn the {@link HttpConnection connection} used to execute
450      *        this HTTP method
451      *
452      * @throws IOException if an I/O (transport) error occurs
453      * @throws HttpException  if a protocol exception occurs.
454      * @throws HttpRecoverableException if a recoverable transport error occurs. 
455      *                    Usually this kind of exceptions can be recovered from by
456      *                    retrying the HTTP method 
457      *
458      * @since 2.0
459      */
460     protected void addRequestHeaders(HttpState state, HttpConnection conn)
461     throws IOException, HttpException {
462         super.addRequestHeaders(state, conn);
463 
464         if (!this.params.isEmpty()) {
465             //there are some parameters, so set the contentType header
466             if (getRequestHeader("Content-Type") == null) {
467                 setRequestHeader("Content-Type", FORM_URL_ENCODED_CONTENT_TYPE);
468             }
469         }
470     }
471 
472 }