001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.client.methods;
029
030import java.io.IOException;
031import java.net.URI;
032import java.net.URISyntaxException;
033import java.nio.charset.Charset;
034import java.util.ArrayList;
035import java.util.LinkedList;
036import java.util.List;
037
038import org.apache.http.Consts;
039import org.apache.http.Header;
040import org.apache.http.HeaderIterator;
041import org.apache.http.HttpEntity;
042import org.apache.http.HttpEntityEnclosingRequest;
043import org.apache.http.HttpRequest;
044import org.apache.http.NameValuePair;
045import org.apache.http.ProtocolVersion;
046import org.apache.http.client.config.RequestConfig;
047import org.apache.http.client.entity.UrlEncodedFormEntity;
048import org.apache.http.client.utils.URIBuilder;
049import org.apache.http.client.utils.URLEncodedUtils;
050import org.apache.http.entity.ContentType;
051import org.apache.http.message.BasicHeader;
052import org.apache.http.message.BasicNameValuePair;
053import org.apache.http.message.HeaderGroup;
054import org.apache.http.protocol.HTTP;
055import org.apache.http.util.Args;
056
057/**
058 * Builder for {@link HttpUriRequest} instances.
059 * <p>
060 * Please note that this class treats parameters differently depending on composition
061 * of the request: if the request has a content entity explicitly set with
062 * {@link #setEntity(org.apache.http.HttpEntity)} or it is not an entity enclosing method
063 * (such as POST or PUT), parameters will be added to the query component of the request URI.
064 * Otherwise, parameters will be added as a URL encoded {@link UrlEncodedFormEntity entity}.
065 * </p>
066 *
067 * @since 4.3
068 */
069public class RequestBuilder {
070
071    private String method;
072    private Charset charset;
073    private ProtocolVersion version;
074    private URI uri;
075    private HeaderGroup headergroup;
076    private HttpEntity entity;
077    private List<NameValuePair> parameters;
078    private RequestConfig config;
079
080    RequestBuilder(final String method) {
081        super();
082        this.charset = Consts.UTF_8;
083        this.method = method;
084    }
085
086    RequestBuilder(final String method, final URI uri) {
087        super();
088        this.method = method;
089        this.uri = uri;
090    }
091
092    RequestBuilder(final String method, final String uri) {
093        super();
094        this.method = method;
095        this.uri = uri != null ? URI.create(uri) : null;
096    }
097
098    RequestBuilder() {
099        this(null);
100    }
101
102    public static RequestBuilder create(final String method) {
103        Args.notBlank(method, "HTTP method");
104        return new RequestBuilder(method);
105    }
106
107    public static RequestBuilder get() {
108        return new RequestBuilder(HttpGet.METHOD_NAME);
109    }
110
111    /**
112     * @since 4.4
113     */
114    public static RequestBuilder get(final URI uri) {
115        return new RequestBuilder(HttpGet.METHOD_NAME, uri);
116    }
117
118    /**
119     * @since 4.4
120     */
121    public static RequestBuilder get(final String uri) {
122        return new RequestBuilder(HttpGet.METHOD_NAME, uri);
123    }
124
125    public static RequestBuilder head() {
126        return new RequestBuilder(HttpHead.METHOD_NAME);
127    }
128
129    /**
130     * @since 4.4
131     */
132    public static RequestBuilder head(final URI uri) {
133        return new RequestBuilder(HttpHead.METHOD_NAME, uri);
134    }
135
136    /**
137     * @since 4.4
138     */
139    public static RequestBuilder head(final String uri) {
140        return new RequestBuilder(HttpHead.METHOD_NAME, uri);
141    }
142
143    /**
144     * @since 4.4
145     */
146    public static RequestBuilder patch() {
147        return new RequestBuilder(HttpPatch.METHOD_NAME);
148    }
149
150    /**
151     * @since 4.4
152     */
153    public static RequestBuilder patch(final URI uri) {
154        return new RequestBuilder(HttpPatch.METHOD_NAME, uri);
155    }
156
157    /**
158     * @since 4.4
159     */
160    public static RequestBuilder patch(final String uri) {
161        return new RequestBuilder(HttpPatch.METHOD_NAME, uri);
162    }
163
164    public static RequestBuilder post() {
165        return new RequestBuilder(HttpPost.METHOD_NAME);
166    }
167
168    /**
169     * @since 4.4
170     */
171    public static RequestBuilder post(final URI uri) {
172        return new RequestBuilder(HttpPost.METHOD_NAME, uri);
173    }
174
175    /**
176     * @since 4.4
177     */
178    public static RequestBuilder post(final String uri) {
179        return new RequestBuilder(HttpPost.METHOD_NAME, uri);
180    }
181
182    public static RequestBuilder put() {
183        return new RequestBuilder(HttpPut.METHOD_NAME);
184    }
185
186    /**
187     * @since 4.4
188     */
189    public static RequestBuilder put(final URI uri) {
190        return new RequestBuilder(HttpPut.METHOD_NAME, uri);
191    }
192
193    /**
194     * @since 4.4
195     */
196    public static RequestBuilder put(final String uri) {
197        return new RequestBuilder(HttpPut.METHOD_NAME, uri);
198    }
199
200    public static RequestBuilder delete() {
201        return new RequestBuilder(HttpDelete.METHOD_NAME);
202    }
203
204    /**
205     * @since 4.4
206     */
207    public static RequestBuilder delete(final URI uri) {
208        return new RequestBuilder(HttpDelete.METHOD_NAME, uri);
209    }
210
211    /**
212     * @since 4.4
213     */
214    public static RequestBuilder delete(final String uri) {
215        return new RequestBuilder(HttpDelete.METHOD_NAME, uri);
216    }
217
218    public static RequestBuilder trace() {
219        return new RequestBuilder(HttpTrace.METHOD_NAME);
220    }
221
222    /**
223     * @since 4.4
224     */
225    public static RequestBuilder trace(final URI uri) {
226        return new RequestBuilder(HttpTrace.METHOD_NAME, uri);
227    }
228
229    /**
230     * @since 4.4
231     */
232    public static RequestBuilder trace(final String uri) {
233        return new RequestBuilder(HttpTrace.METHOD_NAME, uri);
234    }
235
236    public static RequestBuilder options() {
237        return new RequestBuilder(HttpOptions.METHOD_NAME);
238    }
239
240    /**
241     * @since 4.4
242     */
243    public static RequestBuilder options(final URI uri) {
244        return new RequestBuilder(HttpOptions.METHOD_NAME, uri);
245    }
246
247    /**
248     * @since 4.4
249     */
250    public static RequestBuilder options(final String uri) {
251        return new RequestBuilder(HttpOptions.METHOD_NAME, uri);
252    }
253
254    public static RequestBuilder copy(final HttpRequest request) {
255        Args.notNull(request, "HTTP request");
256        return new RequestBuilder().doCopy(request);
257    }
258
259    private RequestBuilder doCopy(final HttpRequest request) {
260        if (request == null) {
261            return this;
262        }
263        method = request.getRequestLine().getMethod();
264        version = request.getRequestLine().getProtocolVersion();
265
266        if (headergroup == null) {
267            headergroup = new HeaderGroup();
268        }
269        headergroup.clear();
270        headergroup.setHeaders(request.getAllHeaders());
271
272        parameters = null;
273        entity = null;
274
275        if (request instanceof HttpEntityEnclosingRequest) {
276            final HttpEntity originalEntity = ((HttpEntityEnclosingRequest) request).getEntity();
277            final ContentType contentType = ContentType.get(originalEntity);
278            if (contentType != null &&
279                    contentType.getMimeType().equals(ContentType.APPLICATION_FORM_URLENCODED.getMimeType())) {
280                try {
281                    final List<NameValuePair> formParams = URLEncodedUtils.parse(originalEntity);
282                    if (!formParams.isEmpty()) {
283                        parameters = formParams;
284                    }
285                } catch (final IOException ignore) {
286                }
287            } else {
288                entity = originalEntity;
289            }
290        }
291
292        final URI originalUri;
293        if (request instanceof HttpUriRequest) {
294            uri = ((HttpUriRequest) request).getURI();
295        } else {
296            uri = URI.create(request.getRequestLine().getUri());
297        }
298
299        if (request instanceof Configurable) {
300            config = ((Configurable) request).getConfig();
301        } else {
302            config = null;
303        }
304        return this;
305    }
306
307    /**
308     * @since 4.4
309     */
310    public RequestBuilder setCharset(final Charset charset) {
311        this.charset = charset;
312        return this;
313    }
314
315    /**
316     * @since 4.4
317     */
318    public Charset getCharset() {
319        return charset;
320    }
321
322    public String getMethod() {
323        return method;
324    }
325
326    public ProtocolVersion getVersion() {
327        return version;
328    }
329
330    public RequestBuilder setVersion(final ProtocolVersion version) {
331        this.version = version;
332        return this;
333    }
334
335    public URI getUri() {
336        return uri;
337    }
338
339    public RequestBuilder setUri(final URI uri) {
340        this.uri = uri;
341        return this;
342    }
343
344    public RequestBuilder setUri(final String uri) {
345        this.uri = uri != null ? URI.create(uri) : null;
346        return this;
347    }
348
349    public Header getFirstHeader(final String name) {
350        return headergroup != null ? headergroup.getFirstHeader(name) : null;
351    }
352
353    public Header getLastHeader(final String name) {
354        return headergroup != null ? headergroup.getLastHeader(name) : null;
355    }
356
357    public Header[] getHeaders(final String name) {
358        return headergroup != null ? headergroup.getHeaders(name) : null;
359    }
360
361    public RequestBuilder addHeader(final Header header) {
362        if (headergroup == null) {
363            headergroup = new HeaderGroup();
364        }
365        headergroup.addHeader(header);
366        return this;
367    }
368
369    public RequestBuilder addHeader(final String name, final String value) {
370        if (headergroup == null) {
371            headergroup = new HeaderGroup();
372        }
373        this.headergroup.addHeader(new BasicHeader(name, value));
374        return this;
375    }
376
377    public RequestBuilder removeHeader(final Header header) {
378        if (headergroup == null) {
379            headergroup = new HeaderGroup();
380        }
381        headergroup.removeHeader(header);
382        return this;
383    }
384
385    public RequestBuilder removeHeaders(final String name) {
386        if (name == null || headergroup == null) {
387            return this;
388        }
389        for (final HeaderIterator i = headergroup.iterator(); i.hasNext(); ) {
390            final Header header = i.nextHeader();
391            if (name.equalsIgnoreCase(header.getName())) {
392                i.remove();
393            }
394        }
395        return this;
396    }
397
398    public RequestBuilder setHeader(final Header header) {
399        if (headergroup == null) {
400            headergroup = new HeaderGroup();
401        }
402        this.headergroup.updateHeader(header);
403        return this;
404    }
405
406    public RequestBuilder setHeader(final String name, final String value) {
407        if (headergroup == null) {
408            headergroup = new HeaderGroup();
409        }
410        this.headergroup.updateHeader(new BasicHeader(name, value));
411        return this;
412    }
413
414    public HttpEntity getEntity() {
415        return entity;
416    }
417
418    public RequestBuilder setEntity(final HttpEntity entity) {
419        this.entity = entity;
420        return this;
421    }
422
423    public List<NameValuePair> getParameters() {
424        return parameters != null ? new ArrayList<NameValuePair>(parameters) :
425            new ArrayList<NameValuePair>();
426    }
427
428    public RequestBuilder addParameter(final NameValuePair nvp) {
429        Args.notNull(nvp, "Name value pair");
430        if (parameters == null) {
431            parameters = new LinkedList<NameValuePair>();
432        }
433        parameters.add(nvp);
434        return this;
435    }
436
437    public RequestBuilder addParameter(final String name, final String value) {
438        return addParameter(new BasicNameValuePair(name, value));
439    }
440
441    public RequestBuilder addParameters(final NameValuePair... nvps) {
442        for (final NameValuePair nvp: nvps) {
443            addParameter(nvp);
444        }
445        return this;
446    }
447
448    public RequestConfig getConfig() {
449        return config;
450    }
451
452    public RequestBuilder setConfig(final RequestConfig config) {
453        this.config = config;
454        return this;
455    }
456
457    public HttpUriRequest build() {
458        final HttpRequestBase result;
459        URI uriNotNull = this.uri != null ? this.uri : URI.create("/");
460        HttpEntity entityCopy = this.entity;
461        if (parameters != null && !parameters.isEmpty()) {
462            if (entityCopy == null && (HttpPost.METHOD_NAME.equalsIgnoreCase(method)
463                    || HttpPut.METHOD_NAME.equalsIgnoreCase(method))) {
464                entityCopy = new UrlEncodedFormEntity(parameters, charset != null ? charset : HTTP.DEF_CONTENT_CHARSET);
465            } else {
466                try {
467                    uriNotNull = new URIBuilder(uriNotNull)
468                      .setCharset(this.charset)
469                      .addParameters(parameters)
470                      .build();
471                } catch (final URISyntaxException ex) {
472                    // should never happen
473                }
474            }
475        }
476        if (entityCopy == null) {
477            result = new InternalRequest(method);
478        } else {
479            final InternalEntityEclosingRequest request = new InternalEntityEclosingRequest(method);
480            request.setEntity(entityCopy);
481            result = request;
482        }
483        result.setProtocolVersion(this.version);
484        result.setURI(uriNotNull);
485        if (this.headergroup != null) {
486            result.setHeaders(this.headergroup.getAllHeaders());
487        }
488        result.setConfig(this.config);
489        return result;
490    }
491
492    static class InternalRequest extends HttpRequestBase {
493
494        private final String method;
495
496        InternalRequest(final String method) {
497            super();
498            this.method = method;
499        }
500
501        @Override
502        public String getMethod() {
503            return this.method;
504        }
505
506    }
507
508    static class InternalEntityEclosingRequest extends HttpEntityEnclosingRequestBase {
509
510        private final String method;
511
512        InternalEntityEclosingRequest(final String method) {
513            super();
514            this.method = method;
515        }
516
517        @Override
518        public String getMethod() {
519            return this.method;
520        }
521
522    }
523
524}