001package org.jsoup;
002
003import org.jsoup.helper.RequestAuthenticator;
004import org.jsoup.nodes.Document;
005import org.jsoup.parser.Parser;
006import org.jsoup.parser.StreamParser;
007import org.jspecify.annotations.Nullable;
008
009import javax.net.ssl.SSLSocketFactory;
010import java.io.BufferedInputStream;
011import java.io.IOException;
012import java.io.InputStream;
013import java.io.UncheckedIOException;
014import java.net.Authenticator;
015import java.net.CookieStore;
016import java.net.Proxy;
017import java.net.URL;
018import java.util.Collection;
019import java.util.List;
020import java.util.Map;
021
022/**
023 The Connection interface is a convenient HTTP client and session object to fetch content from the web, and parse them
024 into Documents.
025 <p>To start a new session, use either {@link org.jsoup.Jsoup#newSession()} or {@link org.jsoup.Jsoup#connect(String)}.
026 Connections contain {@link Connection.Request} and {@link Connection.Response} objects (once executed). Configuration
027 settings (URL, timeout, useragent, etc) set on a session will be applied by default to each subsequent request.</p>
028 <p>To start a new request from the session, use {@link #newRequest()}.</p>
029 <p>Cookies are stored in memory for the duration of the session. For that reason, do not use one single session for all
030 requests in a long-lived application, or you are likely to run out of memory, unless care is taken to clean up the
031 cookie store. The cookie store for the session is available via {@link #cookieStore()}. You may provide your own
032 implementation via {@link #cookieStore(java.net.CookieStore)} before making requests.</p>
033 <p>Request configuration can be made using either the shortcut methods in Connection (e.g. {@link #userAgent(String)}),
034 or by methods in the {@link Connection.Request} object directly. All request configuration must be made before the request is
035 executed. When used as an ongoing session, initialize all defaults prior to making multi-threaded {@link
036#newRequest()}s.</p>
037 <p>Note that the term "Connection" used here does not mean that a long-lived connection is held against a server for
038 the lifetime of the Connection object. A socket connection is only made at the point of request execution ({@link
039#execute()}, {@link #get()}, or {@link #post()}), and the server's response consumed.</p>
040 <p>For multi-threaded implementations, it is important to use a {@link #newRequest()} for each request. The session may
041 be shared across concurrent threads, but a not a specific request.</p>
042 */
043@SuppressWarnings("unused")
044public interface Connection {
045
046    /**
047     * GET and POST http methods.
048     */
049    enum Method {
050        GET(false),
051        POST(true),
052        PUT(true),
053        DELETE(true),
054        /**
055         Note that unfortunately, PATCH is not supported in many JDKs.
056         */
057        PATCH(true),
058        HEAD(false),
059        OPTIONS(false),
060        TRACE(false);
061
062        private final boolean hasBody;
063
064        Method(boolean hasBody) {
065            this.hasBody = hasBody;
066        }
067
068        /**
069         * Check if this HTTP method has/needs a request body
070         * @return if body needed
071         */
072        public final boolean hasBody() {
073            return hasBody;
074        }
075    }
076
077    /**
078     Creates a new request, using this Connection as the session-state and to initialize the connection settings (which
079     may then be independently changed on the returned {@link Connection.Request} object).
080     @return a new Connection object, with a shared Cookie Store and initialized settings from this Connection and Request
081     @since 1.14.1
082     */
083    Connection newRequest();
084
085    /**
086     Creates a new request, using this Connection as the session-state and to initialize the connection settings (which
087     may then be independently changed on the returned {@link Connection.Request} object).
088     @return a new Connection object, with a shared Cookie Store and initialized settings from this Connection and Request
089     @param url URL for the new request
090     @since 1.17.1
091     */
092    default Connection newRequest(String url) {
093        return newRequest().url(url);
094    }
095
096    /**
097     Creates a new request, using this Connection as the session-state and to initialize the connection settings (which
098     may then be independently changed on the returned {@link Connection.Request} object).
099     @return a new Connection object, with a shared Cookie Store and initialized settings from this Connection and Request
100     @param url URL for the new request
101     @since 1.17.1
102     */
103    default Connection newRequest(URL url) {
104        return newRequest().url(url);
105    }
106
107    /**
108     * Set the request URL to fetch. The protocol must be HTTP or HTTPS.
109     * @param url URL to connect to
110     * @return this Connection, for chaining
111     */
112    Connection url(URL url);
113
114    /**
115     * Set the request URL to fetch. The protocol must be HTTP or HTTPS.
116     * @param url URL to connect to
117     * @return this Connection, for chaining
118     */
119    Connection url(String url);
120
121    /**
122     * Set the proxy to use for this request. Set to <code>null</code> to disable a previously set proxy.
123     * @param proxy proxy to use
124     * @return this Connection, for chaining
125     */
126    Connection proxy(@Nullable Proxy proxy);
127
128    /**
129     * Set the HTTP proxy to use for this request.
130     * @param host the proxy hostname
131     * @param port the proxy port
132     * @return this Connection, for chaining
133     */
134    Connection proxy(String host, int port);
135
136    /**
137     * Set the request user-agent header.
138     * @param userAgent user-agent to use
139     * @return this Connection, for chaining
140     * @see org.jsoup.helper.HttpConnection#DEFAULT_UA
141     */
142    Connection userAgent(String userAgent);
143
144    /**
145     * Set the total request timeout duration. If a timeout occurs, an {@link java.net.SocketTimeoutException} will be thrown.
146     * <p>The default timeout is <b>30 seconds</b> (30,000 millis). A timeout of zero is treated as an infinite timeout.
147     * <p>Note that this timeout specifies the combined maximum duration of the connection time and the time to read
148     * the full response.
149     * @param millis number of milliseconds (thousandths of a second) before timing out connects or reads.
150     * @return this Connection, for chaining
151     * @see #maxBodySize(int)
152     */
153    Connection timeout(int millis);
154
155    /**
156     * Set the maximum bytes to read from the (uncompressed) connection into the body, before the connection is closed,
157     * and the input truncated (i.e. the body content will be trimmed). <b>The default maximum is 2MB</b>. A max size of
158     * <code>0</code> is treated as an infinite amount (bounded only by your patience and the memory available on your
159     * machine).
160     *
161     * @param bytes number of bytes to read from the input before truncating
162     * @return this Connection, for chaining
163     */
164    Connection maxBodySize(int bytes);
165
166    /**
167     * Set the request referrer (aka "referer") header.
168     * @param referrer referrer to use
169     * @return this Connection, for chaining
170     */
171    Connection referrer(String referrer);
172
173    /**
174     * Configures the connection to (not) follow server redirects. By default, this is <b>true</b>.
175     * @param followRedirects true if server redirects should be followed.
176     * @return this Connection, for chaining
177     */
178    Connection followRedirects(boolean followRedirects);
179
180    /**
181     * Set the request method to use, GET or POST. Default is GET.
182     * @param method HTTP request method
183     * @return this Connection, for chaining
184     */
185    Connection method(Method method);
186
187    /**
188     * Configures the connection to not throw exceptions when an HTTP error occurs. (4xx - 5xx, e.g. 404 or 500). By
189     * default, this is <b>false</b>; an IOException is thrown if an error is encountered. If set to <b>true</b>, the
190     * response is populated with the error body, and the status message will reflect the error.
191     * @param ignoreHttpErrors - false (default) if HTTP errors should be ignored.
192     * @return this Connection, for chaining
193     */
194    Connection ignoreHttpErrors(boolean ignoreHttpErrors);
195
196    /**
197     * Ignore the document's Content-Type when parsing the response. By default, this is <b>false</b>, an unrecognised
198     * content-type will cause an IOException to be thrown. (This is to prevent producing garbage by attempting to parse
199     * a JPEG binary image, for example.) Set to true to force a parse attempt regardless of content type.
200     * @param ignoreContentType set to true if you would like the content type ignored on parsing the response into a
201     * Document.
202     * @return this Connection, for chaining
203     */
204    Connection ignoreContentType(boolean ignoreContentType);
205
206    /**
207     * Set custom SSL socket factory
208     * @param sslSocketFactory custom SSL socket factory
209     * @return this Connection, for chaining
210     */
211    Connection sslSocketFactory(SSLSocketFactory sslSocketFactory);
212
213    /**
214     * Add a request data parameter. Request parameters are sent in the request query string for GETs, and in the
215     * request body for POSTs. A request may have multiple values of the same name.
216     * @param key data key
217     * @param value data value
218     * @return this Connection, for chaining
219     */
220    Connection data(String key, String value);
221
222    /**
223     * Add an input stream as a request data parameter. For GETs, has no effect, but for POSTS this will upload the
224     * input stream.
225     * <p>Use the {@link #data(String, String, InputStream, String)} method to set the uploaded file's mimetype.</p>
226     * @param key data key (form item name)
227     * @param filename the name of the file to present to the remove server. Typically just the name, not path,
228     * component.
229     * @param inputStream the input stream to upload, that you probably obtained from a {@link java.io.FileInputStream}.
230     * You must close the InputStream in a {@code finally} block.
231     * @return this Connection, for chaining
232     * @see #data(String, String, InputStream, String)
233     */
234    Connection data(String key, String filename, InputStream inputStream);
235
236    /**
237     * Add an input stream as a request data parameter. For GETs, has no effect, but for POSTS this will upload the
238     * input stream.
239     * @param key data key (form item name)
240     * @param filename the name of the file to present to the remove server. Typically just the name, not path,
241     * component.
242     * @param inputStream the input stream to upload, that you probably obtained from a {@link java.io.FileInputStream}.
243     * @param contentType the Content Type (aka mimetype) to specify for this file.
244     * You must close the InputStream in a {@code finally} block.
245     * @return this Connection, for chaining
246     */
247    Connection data(String key, String filename, InputStream inputStream, String contentType);
248
249    /**
250     * Adds all of the supplied data to the request data parameters
251     * @param data collection of data parameters
252     * @return this Connection, for chaining
253     */
254    Connection data(Collection<KeyVal> data);
255
256    /**
257     * Adds all of the supplied data to the request data parameters
258     * @param data map of data parameters
259     * @return this Connection, for chaining
260     */
261    Connection data(Map<String, String> data);
262
263    /**
264     Add one or more request {@code key, val} data parameter pairs.
265     <p>Multiple parameters may be set at once, e.g.:
266     <code>.data("name", "jsoup", "language", "Java", "language", "English");</code> creates a query string like:
267     <code>{@literal ?name=jsoup&language=Java&language=English}</code></p>
268     <p>For GET requests, data parameters will be sent on the request query string. For POST (and other methods that
269     contain a body), they will be sent as body form parameters, unless the body is explicitly set by
270     {@link #requestBody(String)}, in which case they will be query string parameters.</p>
271
272     @param keyvals a set of key value pairs.
273     @return this Connection, for chaining
274     */
275    Connection data(String... keyvals);
276
277    /**
278     * Get the data KeyVal for this key, if any
279     * @param key the data key
280     * @return null if not set
281     */
282    @Nullable KeyVal data(String key);
283
284    /**
285     * Set a POST (or PUT) request body. Useful when a server expects a plain request body (such as JSON), and not a set
286     * of URL encoded form key/value pairs. E.g.:
287     * <code><pre>Jsoup.connect(url)
288     * .requestBody(json)
289     * .header("Content-Type", "application/json")
290     * .post();</pre></code>
291     * If any data key/vals are supplied, they will be sent as URL query params.
292     * @see #requestBodyStream(InputStream)
293     * @return this Request, for chaining
294     */
295    Connection requestBody(String body);
296
297    /**
298     Set the request body. Useful for posting data such as byte arrays or files, and the server expects a single request
299     body (and not a multipart upload). E.g.:
300     <code><pre> Jsoup.connect(url)
301     .requestBody(new ByteArrayInputStream(bytes))
302     .header("Content-Type", "application/octet-stream")
303     .post();
304     </pre></code>
305     <p>Or, use a FileInputStream to data from disk.</p>
306     <p>You should close the stream in a finally block.</p>
307
308     @param stream the input stream to send.
309     @return this Request, for chaining
310     @see #requestBody(String)
311     @since 1.20.1
312     */
313    default Connection requestBodyStream(InputStream stream) {
314        throw new UnsupportedOperationException();
315    }
316
317    /**
318     * Set a request header. Replaces any existing header with the same case-insensitive name.
319     * @param name header name
320     * @param value header value
321     * @return this Connection, for chaining
322     * @see org.jsoup.Connection.Request#header(String, String)
323     * @see org.jsoup.Connection.Request#headers()
324     */
325    Connection header(String name, String value);
326
327    /**
328     * Sets each of the supplied headers on the request. Existing headers with the same case-insensitive name will be
329     * replaced with the new value.
330     * @param headers map of headers name {@literal ->} value pairs
331     * @return this Connection, for chaining
332     * @see org.jsoup.Connection.Request#headers()
333     */
334    Connection headers(Map<String,String> headers);
335
336    /**
337     * Set a cookie to be sent in the request.
338     * @param name name of cookie
339     * @param value value of cookie
340     * @return this Connection, for chaining
341     */
342    Connection cookie(String name, String value);
343
344    /**
345     * Adds each of the supplied cookies to the request.
346     * @param cookies map of cookie name {@literal ->} value pairs
347     * @return this Connection, for chaining
348     */
349    Connection cookies(Map<String, String> cookies);
350
351    /**
352     Provide a custom or pre-filled CookieStore to be used on requests made by this Connection.
353     @param cookieStore a cookie store to use for subsequent requests
354     @return this Connection, for chaining
355     @since 1.14.1
356     */
357    Connection cookieStore(CookieStore cookieStore);
358
359    /**
360     Get the cookie store used by this Connection.
361     @return the cookie store
362     @since 1.14.1
363     */
364    CookieStore cookieStore();
365
366    /**
367     * Provide a specific parser to use when parsing the response to a Document. If not set, jsoup defaults to the
368     * {@link Parser#htmlParser() HTML parser}, unless the response content-type is XML, in which case the
369     * {@link Parser#xmlParser() XML parser} is used.
370     * @param parser alternate parser
371     * @return this Connection, for chaining
372     */
373    Connection parser(Parser parser);
374
375    /**
376     * Set the character-set used to encode the request body. Defaults to {@code UTF-8}.
377     * @param charset character set to encode the request body
378     * @return this Connection, for chaining
379     */
380    Connection postDataCharset(String charset);
381
382    /**
383     Set the authenticator to use for this connection, enabling requests to URLs, and via proxies, that require
384     authentication credentials.
385     <p>The authentication scheme used is automatically detected during the request execution.
386     Supported schemes (subject to the platform) are {@code basic}, {@code digest}, {@code NTLM},
387     and {@code Kerberos}.</p>
388
389     <p>To use, supply a {@link RequestAuthenticator} function that:
390     <ol>
391     <li>validates the URL that is requesting authentication, and</li>
392     <li>returns the appropriate credentials (username and password)</li>
393     </ol>
394     </p>
395
396     <p>For example, to authenticate both to a proxy and a downstream web server:
397     <code><pre>
398     Connection session = Jsoup.newSession()
399         .proxy("proxy.example.com", 8080)
400         .auth(auth -&gt; {
401             if (auth.isServer()) { // provide credentials for the request url
402                 Validate.isTrue(auth.url().getHost().equals("example.com"));
403                 // check that we're sending credentials were we expect, and not redirected out
404                 return auth.credentials("username", "password");
405             } else { // auth.isProxy()
406                 return auth.credentials("proxy-user", "proxy-password");
407             }
408         });
409
410     Connection.Response response = session.newRequest("https://example.com/adminzone/").execute();
411     </pre></code>
412     </p>
413
414     <p>The system may cache the authentication and use it for subsequent requests to the same resource.</p>
415
416     <p><b>Implementation notes</b></p>
417     <p>For compatibility, on a Java 8 platform, authentication is set up via the system-wide default
418     {@link java.net.Authenticator#setDefault(Authenticator)} method via a ThreadLocal delegator. Whilst the
419     authenticator used is request specific and thread-safe, if you have other calls to {@code setDefault}, they will be
420     incompatible with this implementation.</p>
421     <p>On Java 9 and above, the preceding note does not apply; authenticators are directly set on the request. </p>
422     <p>If you are attempting to authenticate to a proxy that uses the {@code basic} scheme and will be fetching HTTPS
423     URLs, you need to configure your Java platform to enable that, by setting the
424     {@code jdk.http.auth.tunneling.disabledSchemes} system property to {@code ""}.
425     This must be executed prior to any authorization attempts. E.g.:
426     <code><pre>
427     static {
428        System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
429        // removes Basic, which is otherwise excluded from auth for CONNECT tunnels
430     }</pre></code>
431     </p>
432     * @param authenticator the authenticator to use in this connection
433     * @return this Connection, for chaining
434     * @since 1.17.1
435     */
436    default Connection auth(@Nullable RequestAuthenticator authenticator) {
437        throw new UnsupportedOperationException();
438    }
439
440    /**
441     * Execute the request as a GET, and parse the result.
442     * @return parsed Document
443     * @throws java.net.MalformedURLException if the request URL is not an HTTP or HTTPS URL, or is otherwise malformed
444     * @throws HttpStatusException if the response is not OK and HTTP response errors are not ignored
445     * @throws UnsupportedMimeTypeException if the response mime type is not supported and those errors are not ignored
446     * @throws java.net.SocketTimeoutException if the connection times out
447     * @throws IOException on error
448     */
449    Document get() throws IOException;
450
451    /**
452     * Execute the request as a POST, and parse the result.
453     * @return parsed Document
454     * @throws java.net.MalformedURLException if the request URL is not a HTTP or HTTPS URL, or is otherwise malformed
455     * @throws HttpStatusException if the response is not OK and HTTP response errors are not ignored
456     * @throws UnsupportedMimeTypeException if the response mime type is not supported and those errors are not ignored
457     * @throws java.net.SocketTimeoutException if the connection times out
458     * @throws IOException on error
459     */
460    Document post() throws IOException;
461
462    /**
463     * Execute the request.
464     * @return the executed {@link Response}
465     * @throws java.net.MalformedURLException if the request URL is not a HTTP or HTTPS URL, or is otherwise malformed
466     * @throws HttpStatusException if the response is not OK and HTTP response errors are not ignored
467     * @throws UnsupportedMimeTypeException if the response mime type is not supported and those errors are not ignored
468     * @throws java.net.SocketTimeoutException if the connection times out
469     * @throws IOException on error
470     */
471    Response execute() throws IOException;
472
473    /**
474     * Get the request object associated with this connection
475     * @return request
476     */
477    Request request();
478
479    /**
480     * Set the connection's request
481     * @param request new request object
482     * @return this Connection, for chaining
483     */
484    Connection request(Request request);
485
486    /**
487     * Get the response, once the request has been executed.
488     * @return response
489     * @throws IllegalArgumentException if called before the response has been executed.
490     */
491    Response response();
492
493    /**
494     * Set the connection's response
495     * @param response new response
496     * @return this Connection, for chaining
497     */
498    Connection response(Response response);
499
500    /**
501     Set the response progress handler, which will be called periodically as the response body is downloaded. Since
502     documents are parsed as they are downloaded, this is also a good proxy for the parse progress.
503     <p>The Response object is supplied as the progress context, and may be read from to obtain headers etc.</p>
504     @param handler the progress handler
505     @return this Connection, for chaining
506     @since 1.18.1
507     */
508    default Connection onResponseProgress(Progress<Response> handler) {
509        throw new UnsupportedOperationException();
510    }
511
512    /**
513     * Common methods for Requests and Responses
514     * @param <T> Type of Base, either Request or Response
515     */
516    @SuppressWarnings("UnusedReturnValue")
517    interface Base<T extends Base<T>> {
518        /**
519         * Get the URL of this Request or Response. For redirected responses, this will be the final destination URL.
520         * @return URL
521         * @throws IllegalArgumentException if called on a Request that was created without a URL.
522         */
523        URL url();
524
525        /**
526         * Set the URL
527         * @param url new URL
528         * @return this, for chaining
529         */
530        T url(URL url);
531
532        /**
533         * Get the request method, which defaults to <code>GET</code>
534         * @return method
535         */
536        Method method();
537
538        /**
539         * Set the request method
540         * @param method new method
541         * @return this, for chaining
542         */
543        T method(Method method);
544
545        /**
546         * Get the value of a header. If there is more than one header value with the same name, the headers are returned
547         * comma separated, per <a href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2">rfc2616-sec4</a>.
548         * <p>
549         * Header names are case-insensitive.
550         * </p>
551         * @param name name of header (case-insensitive)
552         * @return value of header, or null if not set.
553         * @see #hasHeader(String)
554         * @see #cookie(String)
555         */
556        @Nullable String header(String name);
557
558        /**
559         * Get the values of a header.
560         * @param name header name, case-insensitive.
561         * @return a list of values for this header, or an empty list if not set.
562         */
563        List<String> headers(String name);
564
565        /**
566         * Set a header. This method will overwrite any existing header with the same case-insensitive name. If there
567         * is more than one value for this header, this method will update the first matching header.
568         * <p>For compatibility, if the content of the header includes text that cannot be represented by ISO-8859-1,
569         * then it should be encoded first per <a href="https://www.ietf.org/rfc/rfc2047.txt">RFC 2047</a>.</p>
570         * @param name Name of header
571         * @param value Value of header
572         * @return this, for chaining
573         * @see #addHeader(String, String)
574         */
575        T header(String name, String value);
576
577        /**
578         * Add a header. The header will be added regardless of whether a header with the same name already exists.
579         * <p>For compatibility, if the content of the header includes text that cannot be represented by ISO-8859-1,
580         * then it should be encoded first per <a href="https://www.ietf.org/rfc/rfc2047.txt">RFC 2047</a>.</p>
581         * @param name Name of new header
582         * @param value Value of new header
583         * @return this, for chaining
584         */
585        T addHeader(String name, String value);
586
587        /**
588         * Check if a header is present
589         * @param name name of header (case-insensitive)
590         * @return if the header is present in this request/response
591         */
592        boolean hasHeader(String name);
593
594        /**
595         * Check if a header is present, with the given value
596         * @param name header name (case-insensitive)
597         * @param value value (case-insensitive)
598         * @return if the header and value pair are set in this req/res
599         */
600        boolean hasHeaderWithValue(String name, String value);
601
602        /**
603         * Remove headers by name. If there is more than one header with this name, they will all be removed.
604         * @param name name of header to remove (case-insensitive)
605         * @return this, for chaining
606         */
607        T removeHeader(String name);
608
609        /**
610         * Retrieve all of the request/response header names and corresponding values as a map. For headers with multiple
611         * values, only the first header is returned.
612         * <p>Note that this is a view of the headers only, and changes made to this map will not be reflected in the
613         * request/response object.</p>
614         * @return headers
615         * @see #multiHeaders()
616
617         */
618        Map<String, String> headers();
619
620        /**
621         * Retreive all of the headers, keyed by the header name, and with a list of values per header.
622         * @return a list of multiple values per header.
623         */
624        Map<String, List<String>> multiHeaders();
625
626        /**
627         * Get a cookie value by name from this request/response.
628         * @param name name of cookie to retrieve.
629         * @return value of cookie, or null if not set
630         */
631        @Nullable String cookie(String name);
632
633        /**
634         * Set a cookie in this request/response.
635         * @param name name of cookie
636         * @param value value of cookie
637         * @return this, for chaining
638         */
639        T cookie(String name, String value);
640
641        /**
642         * Check if a cookie is present
643         * @param name name of cookie
644         * @return if the cookie is present in this request/response
645         */
646        boolean hasCookie(String name);
647
648        /**
649         * Remove a cookie by name
650         * @param name name of cookie to remove
651         * @return this, for chaining
652         */
653        T removeCookie(String name);
654
655        /**
656         Retrieve the request/response cookies as a map. For response cookies, if duplicate cookie names were sent, the
657         last one set will be the one included. For session management, rather than using these response cookies, prefer
658         to use {@link Jsoup#newSession()} and related methods.
659
660         @return simple cookie map
661         @see #cookieStore()
662         */
663        Map<String, String> cookies();
664    }
665
666    /**
667     * Represents a HTTP request.
668     */
669    @SuppressWarnings("UnusedReturnValue")
670    interface Request extends Base<Request> {
671        /**
672         * Get the proxy used for this request.
673         * @return the proxy; <code>null</code> if not enabled.
674         */
675        @Nullable Proxy proxy();
676
677        /**
678         * Update the proxy for this request.
679         * @param proxy the proxy ot use; <code>null</code> to disable.
680         * @return this Request, for chaining
681         */
682        Request proxy(@Nullable Proxy proxy);
683
684        /**
685         * Set the HTTP proxy to use for this request.
686         * @param host the proxy hostname
687         * @param port the proxy port
688         * @return this Connection, for chaining
689         */
690        Request proxy(String host, int port);
691
692        /**
693         * Get the request timeout, in milliseconds.
694         * @return the timeout in milliseconds.
695         */
696        int timeout();
697
698        /**
699         * Update the request timeout.
700         * @param millis timeout, in milliseconds
701         * @return this Request, for chaining
702         */
703        Request timeout(int millis);
704
705        /**
706         * Get the maximum body size, in bytes.
707         * @return the maximum body size, in bytes.
708         */
709        int maxBodySize();
710
711        /**
712         * Update the maximum body size, in bytes.
713         * @param bytes maximum body size, in bytes.
714         * @return this Request, for chaining
715         */
716        Request maxBodySize(int bytes);
717
718        /**
719         * Get the current followRedirects configuration.
720         * @return true if followRedirects is enabled.
721         */
722        boolean followRedirects();
723
724        /**
725         * Configures the request to (not) follow server redirects. By default this is <b>true</b>.
726         * @param followRedirects true if server redirects should be followed.
727         * @return this Request, for chaining
728         */
729        Request followRedirects(boolean followRedirects);
730
731        /**
732         * Get the current ignoreHttpErrors configuration.
733         * @return true if errors will be ignored; false (default) if HTTP errors will cause an IOException to be
734         * thrown.
735         */
736        boolean ignoreHttpErrors();
737
738        /**
739         * Configures the request to ignore HTTP errors in the response.
740         * @param ignoreHttpErrors set to true to ignore HTTP errors.
741         * @return this Request, for chaining
742         */
743        Request ignoreHttpErrors(boolean ignoreHttpErrors);
744
745        /**
746         * Get the current ignoreContentType configuration.
747         * @return true if invalid content-types will be ignored; false (default) if they will cause an IOException to
748         * be thrown.
749         */
750        boolean ignoreContentType();
751
752        /**
753         * Configures the request to ignore the Content-Type of the response.
754         * @param ignoreContentType set to true to ignore the content type.
755         * @return this Request, for chaining
756         */
757        Request ignoreContentType(boolean ignoreContentType);
758
759        /**
760         * Get the current custom SSL socket factory, if any.
761         * @return custom SSL socket factory if set, null otherwise
762         */
763        @Nullable SSLSocketFactory sslSocketFactory();
764
765        /**
766         * Set a custom SSL socket factory.
767         * @param sslSocketFactory SSL socket factory
768         */
769        void sslSocketFactory(SSLSocketFactory sslSocketFactory);
770
771        /**
772         * Add a data parameter to the request
773         * @param keyval data to add.
774         * @return this Request, for chaining
775         */
776        Request data(KeyVal keyval);
777
778        /**
779         * Get all of the request's data parameters
780         * @return collection of keyvals
781         */
782        Collection<KeyVal> data();
783
784        /**
785         * Set a POST (or PUT) request body. Useful when a server expects a plain request body, not a set of URL
786         * encoded form key/value pairs. E.g.:
787         * <code><pre>Jsoup.connect(url)
788         * .requestBody(json)
789         * .header("Content-Type", "application/json")
790         * .post();</pre></code>
791         * <p>If any data key/vals are supplied, they will be sent as URL query params.</p>
792         * @param body to use as the request body. Set to null to clear a previously set body.
793         * @return this Request, for chaining
794         * @see #requestBodyStream(InputStream)
795         */
796        Request requestBody(@Nullable String body);
797
798        /**
799         * Get the current request body.
800         * @return null if not set.
801         */
802        @Nullable String requestBody();
803
804        /**
805         Set the request body. Useful for posting data such as byte arrays or files, and the server expects a single
806         request body (and not a multipart upload). E.g.:
807         <code><pre> Jsoup.connect(url)
808         .requestBody(new ByteArrayInputStream(bytes))
809         .header("Content-Type", "application/octet-stream")
810         .post();
811         </pre></code>
812         <p>Or, use a FileInputStream to data from disk.</p>
813         <p>You should close the stream in a finally block.</p>
814
815         @param stream the input stream to send.
816         @return this Request, for chaining
817         @see #requestBody(String)
818         @since 1.20.1
819         */
820        default Request requestBodyStream(InputStream stream) {
821            throw new UnsupportedOperationException();
822        }
823
824        /**
825         * Specify the parser to use when parsing the document.
826         * @param parser parser to use.
827         * @return this Request, for chaining
828         */
829        Request parser(Parser parser);
830
831        /**
832         * Get the current parser to use when parsing the document.
833         * @return current Parser
834         */
835        Parser parser();
836
837        /**
838         * Sets the post data character set for x-www-form-urlencoded post data
839         * @param charset character set to encode post data
840         * @return this Request, for chaining
841         */
842        Request postDataCharset(String charset);
843
844        /**
845         * Gets the post data character set for x-www-form-urlencoded post data
846         * @return character set to encode post data
847         */
848        String postDataCharset();
849
850        /**
851         Set the authenticator to use for this request.
852         See {@link Connection#auth(RequestAuthenticator) Connection.auth(authenticator)} for examples and
853         implementation notes.
854         * @param authenticator the authenticator
855         * @return this Request, for chaining.
856         * @since 1.17.1
857         */
858        default Request auth(@Nullable RequestAuthenticator authenticator)  {
859            throw new UnsupportedOperationException();
860        }
861
862        /**
863         Get the RequestAuthenticator, if any, that will be used on this request.
864         * @return the RequestAuthenticator, or {@code null} if not set
865         * @since 1.17.1
866         */
867        @Nullable
868        default RequestAuthenticator auth() {
869            throw new UnsupportedOperationException();
870        }
871    }
872
873    /**
874     * Represents a HTTP response.
875     */
876    interface Response extends Base<Response> {
877
878        /**
879         * Get the status code of the response.
880         * @return status code
881         */
882        int statusCode();
883
884        /**
885         * Get the status message of the response.
886         * @return status message
887         */
888        String statusMessage();
889
890        /**
891         * Get the character set name of the response, derived from the content-type header.
892         * @return character set name if set, <b>null</b> if not
893         */
894        @Nullable String charset();
895
896        /**
897         * Set / override the response character set. When the document body is parsed it will be with this charset.
898         * @param charset to decode body as
899         * @return this Response, for chaining
900         */
901        Response charset(String charset);
902
903        /**
904         * Get the response content type (e.g. "text/html");
905         * @return the response content type, or <b>null</b> if one was not set
906         */
907        @Nullable String contentType();
908
909        /**
910         * Read and parse the body of the response as a Document. If you intend to parse the same response multiple
911         * times, you should {@link #bufferUp()} first.
912         * @return a parsed Document
913         * @throws IOException on error
914         */
915        Document parse() throws IOException;
916
917        /**
918         * Get the body of the response as a plain string.
919         * @return body
920         */
921        String body();
922
923        /**
924         * Get the body of the response as an array of bytes.
925         * @return body bytes
926         */
927        byte[] bodyAsBytes();
928
929        /**
930         * Read the body of the response into a local buffer, so that {@link #parse()} may be called repeatedly on the
931         * same connection response. Otherwise, once the response is read, its InputStream will have been drained and
932         * may not be re-read.
933         * <p>Calling {@link #body() } or {@link #bodyAsBytes()} has the same effect.</p>
934         * @return this response, for chaining
935         * @throws UncheckedIOException if an IO exception occurs during buffering.
936         */
937        Response bufferUp();
938
939        /**
940         Get the body of the response as a (buffered) InputStream. You should close the input stream when you're done
941         with it.
942         <p>Other body methods (like bufferUp, body, parse, etc) will generally not work in conjunction with this method,
943         as it consumes the InputStream.</p>
944         <p>Any configured max size or maximum read timeout applied to the connection will not be applied to this stream,
945         unless {@link #bufferUp()} is called prior.</p>
946         <p>This method is useful for writing large responses to disk, without buffering them completely into memory
947         first.</p>
948         @return the response body input stream
949         */
950        BufferedInputStream bodyStream();
951
952        /**
953         Returns a {@link StreamParser} that will parse the Response progressively.
954         * @return a StreamParser, prepared to parse this response.
955         * @throws IOException if an IO exception occurs preparing the parser.
956         */
957        default StreamParser streamParser() throws IOException {
958            throw new UnsupportedOperationException();
959        }
960    }
961
962    /**
963     * A Key:Value tuple(+), used for form data.
964     */
965    interface KeyVal {
966
967        /**
968         * Update the key of a keyval
969         * @param key new key
970         * @return this KeyVal, for chaining
971         */
972        KeyVal key(String key);
973
974        /**
975         * Get the key of a keyval
976         * @return the key
977         */
978        String key();
979
980        /**
981         * Update the value of a keyval
982         * @param value the new value
983         * @return this KeyVal, for chaining
984         */
985        KeyVal value(String value);
986
987        /**
988         * Get the value of a keyval
989         * @return the value
990         */
991        String value();
992
993        /**
994         * Add or update an input stream to this keyVal
995         * @param inputStream new input stream
996         * @return this KeyVal, for chaining
997         */
998        KeyVal inputStream(InputStream inputStream);
999
1000        /**
1001         * Get the input stream associated with this keyval, if any
1002         * @return input stream if set, or null
1003         */
1004        @Nullable InputStream inputStream();
1005
1006        /**
1007         * Does this keyval have an input stream?
1008         * @return true if this keyval does indeed have an input stream
1009         */
1010        boolean hasInputStream();
1011
1012        /**
1013         * Set the Content Type header used in the MIME body (aka mimetype) when uploading files.
1014         * Only useful if {@link #inputStream(InputStream)} is set.
1015         * <p>Will default to {@code application/octet-stream}.</p>
1016         * @param contentType the new content type
1017         * @return this KeyVal
1018         */
1019        KeyVal contentType(String contentType);
1020
1021        /**
1022         * Get the current Content Type, or {@code null} if not set.
1023         * @return the current Content Type.
1024         */
1025        @Nullable String contentType();
1026    }
1027}