-
Notifications
You must be signed in to change notification settings - Fork 532
/
Copy pathHttpRequest.java
606 lines (544 loc) · 19.2 KB
/
HttpRequest.java
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
/*
* Copyright (c) 2011-2013 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.vertx.ext.web.client;
import io.vertx.codegen.annotations.*;
import io.vertx.core.*;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.ProxyOptions;
import io.vertx.core.streams.ReadStream;
import io.vertx.ext.auth.authentication.Credentials;
import io.vertx.ext.auth.authentication.TokenCredentials;
import io.vertx.ext.auth.authentication.UsernamePasswordCredentials;
import io.vertx.ext.web.client.predicate.ResponsePredicate;
import io.vertx.ext.web.client.predicate.ResponsePredicateResult;
import io.vertx.ext.web.codec.BodyCodec;
import io.vertx.ext.web.multipart.MultipartForm;
import io.vertx.uritemplate.Variables;
import io.vertx.uritemplate.UriTemplate;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* A client-side HTTP request.
* <p>
* Instances are created by an {@link WebClient} instance, via one of the methods corresponding to the specific
* HTTP methods such as {@link WebClient#get}, etc...
* <p>
* The request shall be configured prior sending, the request is immutable and when a mutator method
* is called, a new request is returned allowing to expose the request in a public API and apply further customization.
* <p>
* After the request has been configured, the methods
* <ul>
* <li>{@link #send(Handler)}</li>
* <li>{@link #sendStream(ReadStream, Handler)}</li>
* <li>{@link #sendJson(Object, Handler)} ()}</li>
* <li>{@link #sendForm(MultiMap, Handler)}</li>
* </ul>
* can be called.
* The {@code sendXXX} methods perform the actual request, they can be called multiple times to perform the same HTTP
* request at different points in time.
* <p>
* The handler is called back with
* <ul>
* <li>an {@link HttpResponse} instance when the HTTP response has been received</li>
* <li>a failure when the HTTP request failed (like a connection error) or when the HTTP response could
* not be obtained (like connection or unmarshalling errors)</li>
* </ul>
* <p>
* Most of the time, this client will buffer the HTTP response fully unless a specific {@link BodyCodec} is used
* such as {@link BodyCodec#create(Handler)}.
*
* @param <T> the type of response body
* @author <a href="mailto:[email protected]">Julien Viet</a>
*/
@VertxGen
public interface HttpRequest<T> {
/**
* Configure the request to use a new method {@code value}.
*
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> method(HttpMethod value);
/**
* @return the request method
*/
HttpMethod method();
/**
* Configure the request to use a new port {@code value}.
* <p> This overrides the port set by absolute URI requests
*
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> port(int value);
/**
* @return the request port or {@code 0} when none is set for absolute URI templates
*/
int port();
/**
* Configure the request to decode the response with the {@code responseCodec}.
*
* @param responseCodec the response codec
* @return a reference to this, so the API can be used fluently
*/
<U> HttpRequest<U> as(BodyCodec<U> responseCodec);
/**
* @return the request body codec
*/
BodyCodec<T> bodyCodec();
/**
* Configure the request to use a new host {@code value}.
* <p> This overrides the host set by absolute URI requests
*
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> host(String value);
/**
* @return the request host or {@code null} when none is set for absolute URI templates
*/
String host();
/**
* Configure the request to use a virtual host {@code value}.
* <p/>
* Usually the header <i>host</i> (<i>:authority</i> pseudo header for HTTP/2) is set from the request host value
* since this host value resolves to the server IP address.
* <p/>
* Sometimes you need to set a host header for an address that does not resolve to the server IP address.
* The virtual host value overrides the value of the actual <i>host</i> header (<i>:authority</i> pseudo header
* for HTTP/2).
* <p/>
* The virtual host is also be used for SNI.
*
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> virtualHost(String value);
/**
* @return the request virtual host if any or {@code null}
*/
String virtualHost();
/**
* Configure the request to use a new request URI {@code value}.
* <p> This overrides the port set by absolute URI requests
* <p> When the uri has query parameters, they are set in the {@link #queryParams()}, overwriting
* any parameters previously set
*
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> uri(String value);
/**
* @return the request uri or {@code null} when none is set for absolute URI templates
*/
String uri();
/**
* Configure the request to add multiple HTTP headers .
*
* @param headers The HTTP headers
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> putHeaders(MultiMap headers);
/**
* Configure the request to set a new HTTP header.
*
* @param name the header name
* @param value the header value
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> putHeader(String name, String value);
/**
* Configure the request to set a new HTTP header with multiple values.
*
* @param name the header name
* @param value the header value
* @return a reference to this, so the API can be used fluently
*/
@Fluent
@GenIgnore(GenIgnore.PERMITTED_TYPE)
HttpRequest<T> putHeader(String name, Iterable<String> value);
/**
* @return The HTTP headers
*/
@CacheReturn
MultiMap headers();
/**
* Configure the request to perform HTTP Authentication.
* <p>
* Performs a generic authentication using the credentials provided by the user. For the sake of validation safety
* it is recommended that {@link Credentials#applyHttpChallenge(String)} is called to ensure that the credentials
* are applicable to the HTTP Challenged received on a previous request that returned a 401 response code.
*
* @param credentials the credentials to use.
* @return a reference to this, so the API can be used fluently
*/
@Fluent
@GenIgnore(GenIgnore.PERMITTED_TYPE)
HttpRequest<T> authentication(Credentials credentials);
/**
* Configure the request to perform basic access authentication.
* <p>
* In basic HTTP authentication, a request contains a header field of the form 'Authorization: Basic <credentials>',
* where credentials is the base64 encoding of id and password joined by a colon.
* </p>
* In practical terms the arguments are converted to a {@link UsernamePasswordCredentials} object.
*
* @param id the id
* @param password the password
* @return a reference to this, so the API can be used fluently
*/
@Fluent
default HttpRequest<T> basicAuthentication(String id, String password) {
return authentication(new UsernamePasswordCredentials(id, password).applyHttpChallenge(null));
}
/**
* Configure the request to perform basic access authentication.
* <p>
* In basic HTTP authentication, a request contains a header field of the form 'Authorization: Basic <credentials>',
* where credentials is the base64 encoding of id and password joined by a colon.
* </p>
* In practical terms the arguments are converted to a {@link UsernamePasswordCredentials} object.
*
* @param id the id
* @param password the password
* @return a reference to this, so the API can be used fluently
*/
@Fluent
default HttpRequest<T> basicAuthentication(Buffer id, Buffer password) {
return basicAuthentication(id.toString(), password.toString());
}
/**
* Configure the request to perform bearer token authentication.
* <p>
* In OAuth 2.0, a request contains a header field of the form 'Authorization: Bearer <bearerToken>',
* where bearerToken is the bearer token issued by an authorization server to access protected resources.
* </p>
* In practical terms the arguments are converted to a {@link TokenCredentials} object.
*
* @param bearerToken the bearer token
* @return a reference to this, so the API can be used fluently
*/
@Fluent
default HttpRequest<T> bearerTokenAuthentication(String bearerToken) {
return authentication(new TokenCredentials(bearerToken).applyHttpChallenge(null));
}
/**
* Configure the request whether to use SSL.
* <p> This overrides the SSL value set by absolute URI requests
*
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> ssl(Boolean value);
/**
* @return whether the request uses SSL or {@code null} when none is set for absolute URI templates
*/
Boolean ssl();
/**
* Configures the amount of time in milliseconds after which if the request does not return any data within the timeout
* period an {@link java.util.concurrent.TimeoutException} fails the request.
* <p>
* Setting zero or a negative {@code value} disables the timeout.
*
* @param value The quantity of time in milliseconds.
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> timeout(long value);
/**
* @return the current timeout in milliseconds
*/
long timeout();
/**
* Add a query parameter to the request.
*
* @param paramName the param name
* @param paramValue the param value
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> addQueryParam(String paramName, String paramValue);
/**
* Set a query parameter to the request.
*
* @param paramName the param name
* @param paramValue the param value
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> setQueryParam(String paramName, String paramValue);
/**
* Set a request URI template string parameter to the request, expanded when the request URI is a {@link UriTemplate}.
*
* @param paramName the param name
* @param paramValue the param value
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> setTemplateParam(String paramName, String paramValue);
/**
* Set a request URI template list parameter to the request, expanded when the request URI is a {@link UriTemplate}.
*
* @param paramName the param name
* @param paramValue the param value
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> setTemplateParam(String paramName, List<String> paramValue);
/**
* Set a request URI template map parameter to the request, expanded when the request URI is a {@link UriTemplate}.
*
* @param paramName the param name
* @param paramValue the param value
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> setTemplateParam(String paramName, Map<String, String> paramValue);
/**
* Set whether to follow request redirections
*
* @param value true if redirections should be followed
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> followRedirects(boolean value);
/**
* @return whether to follow request redirections
*/
boolean followRedirects();
/**
* Configure the request to set a proxy for this request.
*
* Setting proxy here supersedes the proxy set on the client itself
*
* @param proxyOptions The proxy options
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> proxy(ProxyOptions proxyOptions);
/**
* @return the proxy for this request
*/
ProxyOptions proxy();
/**
* Add an expectation that the response is valid according to the provided {@code predicate}.
* <p>
* Multiple predicates can be added.
*
* @param predicate the predicate
* @return a reference to this, so the API can be used fluently
*/
@Fluent
default HttpRequest<T> expect(Function<HttpResponse<Void>, ResponsePredicateResult> predicate) {
return expect(predicate::apply);
}
/**
* Add an expectation that the response is valid according to the provided {@code predicate}.
* <p>
* Multiple predicates can be added.
*
* @param predicate the predicate
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> expect(ResponsePredicate predicate);
/**
* @return a read-only list of the response predicate expectations
*/
List<ResponsePredicate> expectations();
/**
* Return the current query parameters.
*
* @return the current query parameters
*/
MultiMap queryParams();
/**
* Return the current request URI template parameters.
*
* @return the current request URI template parameters
*/
Variables templateParams();
/**
* Copy this request
*
* @return a copy of this request
*/
HttpRequest<T> copy();
/**
* Allow or disallow multipart mixed encoding when sending {@link MultipartForm} having files sharing the same
* file name.
* <br/>
* The default value is {@code true}.
* <br/>
* Set to {@code false} if you want to achieve the behavior for <a href="http://www.w3.org/TR/html5/forms.html#multipart-form-data">HTML5</a>.
*
* @param allow {@code true} allows use of multipart mixed encoding
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> multipartMixed(boolean allow);
/**
* @return whether multipart mixed encoding is allowed
*/
boolean multipartMixed();
/**
* Trace operation name override.
*
* @param traceOperation Name of operation to use in traces
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpRequest<T> traceOperation(String traceOperation);
/**
* @return the trace operation name override
*/
String traceOperation();
/**
* Like {@link #send(Handler)} but with an HTTP request {@code body} stream.
*
* @param body the body
*/
void sendStream(ReadStream<Buffer> body, Handler<AsyncResult<HttpResponse<T>>> handler);
/**
* @param body the body
* @see HttpRequest#sendStream(ReadStream, Handler)
*/
default Future<HttpResponse<T>> sendStream(ReadStream<Buffer> body) {
Promise<HttpResponse<T>> promise = Promise.promise();
sendStream(body, promise);
return promise.future();
}
/**
* Like {@link #send(Handler)} but with an HTTP request {@code body} buffer.
*
* @param body the body
*/
void sendBuffer(Buffer body, Handler<AsyncResult<HttpResponse<T>>> handler);
/**
* @param body the body
* @see HttpRequest#sendBuffer(Buffer, Handler)
*/
default Future<HttpResponse<T>> sendBuffer(Buffer body) {
Promise<HttpResponse<T>> promise = Promise.promise();
sendBuffer(body, promise);
return promise.future();
}
/**
* Like {@link #send(Handler)} but with an HTTP request {@code body} object encoded as json and the content type
* set to {@code application/json}.
*
* @param body the body
*/
void sendJsonObject(JsonObject body, Handler<AsyncResult<HttpResponse<T>>> handler);
/**
* @param body the body
* @see HttpRequest#sendJsonObject(JsonObject, Handler)
*/
default Future<HttpResponse<T>> sendJsonObject(JsonObject body) {
Promise<HttpResponse<T>> promise = Promise.promise();
sendJsonObject(body, promise);
return promise.future();
}
/**
* Like {@link #send(Handler)} but with an HTTP request {@code body} object encoded as json and the content type
* set to {@code application/json}.
*
* @param body the body
*/
void sendJson(@Nullable Object body, Handler<AsyncResult<HttpResponse<T>>> handler);
/**
* @param body the body
* @see HttpRequest#sendJson(Object, Handler)
*/
default Future<HttpResponse<T>> sendJson(@Nullable Object body) {
Promise<HttpResponse<T>> promise = Promise.promise();
sendJson(body, promise);
return promise.future();
}
/**
* Like {@link #send(Handler)} but with an HTTP request {@code body} multimap encoded as form and the content type
* set to {@code application/x-www-form-urlencoded}.
* <p>
* When the content type header is previously set to {@code multipart/form-data} it will be used instead.
*
* @param body the body
*/
void sendForm(MultiMap body, Handler<AsyncResult<HttpResponse<T>>> handler);
/**
* @param body the body
* @see HttpRequest#sendForm(MultiMap, Handler)
*/
default Future<HttpResponse<T>> sendForm(MultiMap body) {
Promise<HttpResponse<T>> promise = Promise.promise();
sendForm(body, promise);
return promise.future();
}
/**
* Like {@link #send(Handler)} but with an HTTP request {@code body} multimap encoded as form and the content type
* set to {@code application/x-www-form-urlencoded}.
* <p>
* When the content type header is previously set to {@code multipart/form-data} it will be used instead.
*
* NOTE: the use of this method is strongly discouraged to use when the form is a {@code application/x-www-form-urlencoded}
* encoded form since the charset to use must be UTF-8.
*
* @param body the body
*/
void sendForm(MultiMap body, String charset, Handler<AsyncResult<HttpResponse<T>>> handler);
/**
* @param body the body
* @param charset the charset
* @see HttpRequest#sendForm(MultiMap, String, Handler)
*/
default Future<HttpResponse<T>> sendForm(MultiMap body, String charset) {
Promise<HttpResponse<T>> promise = Promise.promise();
sendForm(body, charset, promise);
return promise.future();
}
/**
* Like {@link #send(Handler)} but with an HTTP request {@code body} multimap encoded as form and the content type
* set to {@code multipart/form-data}. You may use this method to send attributes and upload files.
*
* @param body the body
*/
void sendMultipartForm(MultipartForm body, Handler<AsyncResult<HttpResponse<T>>> handler);
/**
* @param body the body
* @see HttpRequest#sendMultipartForm(MultipartForm, Handler)
*/
default Future<HttpResponse<T>> sendMultipartForm(MultipartForm body) {
Promise<HttpResponse<T>> promise = Promise.promise();
sendMultipartForm(body, promise);
return promise.future();
}
/**
* Send a request, the {@code handler} will receive the response as an {@link HttpResponse}.
*/
void send(Handler<AsyncResult<HttpResponse<T>>> handler);
/**
* @see HttpRequest#send(Handler)
*/
default Future<HttpResponse<T>> send() {
Promise<HttpResponse<T>> promise = Promise.promise();
send(promise);
return promise.future();
}
}