1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
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
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
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
466 if (getRequestHeader("Content-Type") == null) {
467 setRequestHeader("Content-Type", FORM_URL_ENCODED_CONTENT_TYPE);
468 }
469 }
470 }
471
472 }