diff options
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebResponse.java')
-rw-r--r-- | mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebResponse.java | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebResponse.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebResponse.java new file mode 100644 index 0000000000..8c224ed2e3 --- /dev/null +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebResponse.java @@ -0,0 +1,227 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * vim: ts=4 sw=4 expandtab: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.geckoview; + +import androidx.annotation.AnyThread; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import org.mozilla.gecko.annotation.WrapForJNI; + +/** + * WebResponse represents an HTTP[S] response. It is normally created by {@link + * GeckoWebExecutor#fetch(WebRequest)}. + */ +@WrapForJNI +@AnyThread +public class WebResponse extends WebMessage { + /** The default read timeout for the {@link #body} stream. */ + public static final long DEFAULT_READ_TIMEOUT_MS = 30000; + + /** The HTTP status code for the response, e.g. 200. */ + public final int statusCode; + + /** A boolean indicating whether or not this response is the result of a redirection. */ + public final boolean redirected; + + /** Whether or not this response was delivered via a secure connection. */ + public final boolean isSecure; + + /** The server certificate used with this response, if any. */ + public final @Nullable X509Certificate certificate; + + /** + * An {@link InputStream} containing the response body, if available. Attention: the stream must + * be closed whenever the app is done with it, even when the body is ignored. Otherwise the + * connection will not be closed until the stream is garbage collected + */ + public final @Nullable InputStream body; + + /** + * Specifies that the contents should request to be opened in another Android application. For + * example, provide PDF content and set this to true to request that Android opens the PDF in a + * system PDF viewer (if possible and allowed by the user). + */ + public final @Nullable boolean requestExternalApp; + + /** + * Specifies that the app may skip requesting the download in the UI. A confirmation of the + * download will still be shown. + */ + public final @Nullable boolean skipConfirmation; + + protected WebResponse(final @NonNull Builder builder) { + super(builder); + this.statusCode = builder.mStatusCode; + this.redirected = builder.mRedirected; + this.body = builder.mBody; + this.requestExternalApp = builder.mRequestExternalApp; + this.skipConfirmation = builder.mSkipConfirmation; + this.isSecure = builder.mIsSecure; + this.certificate = builder.mCertificate; + + this.setReadTimeoutMillis(DEFAULT_READ_TIMEOUT_MS); + } + + /** + * Sets the maximum amount of time to wait for data in the {@link #body} read() method. By + * default, the read timeout is set to {@link #DEFAULT_READ_TIMEOUT_MS}. + * + * <p>If 0, there will be no timeout and read() will block indefinitely. + * + * @param millis The duration in milliseconds for the timeout. + */ + public void setReadTimeoutMillis(final long millis) { + if (this.body != null && this.body instanceof GeckoInputStream) { + ((GeckoInputStream) this.body).setReadTimeoutMillis(millis); + } + } + + /** Builder offers a convenient way to create WebResponse instances. */ + @WrapForJNI + @AnyThread + public static class Builder extends WebMessage.Builder { + /* package */ int mStatusCode; + /* package */ boolean mRedirected; + /* package */ InputStream mBody; + /* package */ boolean mRequestExternalApp = false; + /* package */ boolean mSkipConfirmation = false; + /* package */ boolean mIsSecure; + /* package */ X509Certificate mCertificate; + + /** + * Constructs a new Builder instance with the specified URI. + * + * @param uri A URI String. + */ + public Builder(final @NonNull String uri) { + super(uri); + } + + @Override + public @NonNull Builder uri(final @NonNull String uri) { + super.uri(uri); + return this; + } + + @Override + public @NonNull Builder header(final @NonNull String key, final @NonNull String value) { + super.header(key, value); + return this; + } + + @Override + public @NonNull Builder addHeader(final @NonNull String key, final @NonNull String value) { + super.addHeader(key, value); + return this; + } + + /** + * Sets the {@link InputStream} containing the body of this response. + * + * @param stream An {@link InputStream} with the body of the response. + * @return This Builder instance. + */ + public @NonNull Builder body(final @NonNull InputStream stream) { + mBody = stream; + return this; + } + + /** + * Requests that the content be passed to an external Android application. The default is false. + * For example, set to true to request that the user have the option to open the content in + * another Android application. + * + * @param requestExternalApp request that the content be opened in another application. + * @return This Builder instance. + */ + public @NonNull Builder requestExternalApp(final boolean requestExternalApp) { + mRequestExternalApp = requestExternalApp; + return this; + } + + /** + * Specifies if a confirmation to begin downloading is necessary or not. (The confirmation that + * a download occurred will still be shown.) The default is false, which is to request a + * download confirmation. Skipping the confirmation is only advisable if the user has already + * opted to download. + * + * @param skipConfirmation whether to skip or show the confirm download flow + * @return This Builder instance. + */ + public @NonNull Builder skipConfirmation(final boolean skipConfirmation) { + mSkipConfirmation = skipConfirmation; + return this; + } + + /** + * @param isSecure Whether or not this response is secure. + * @return This Builder instance. + */ + public @NonNull Builder isSecure(final boolean isSecure) { + mIsSecure = isSecure; + return this; + } + + /** + * @param certificate The certificate used. + * @return This Builder instance. + */ + public @NonNull Builder certificate(final @NonNull X509Certificate certificate) { + mCertificate = certificate; + return this; + } + + /** + * @param encodedCert The certificate used, encoded via DER. Only used via JNI. + */ + @WrapForJNI(exceptionMode = "nsresult") + private void certificateBytes(final @NonNull byte[] encodedCert) { + try { + final CertificateFactory factory = CertificateFactory.getInstance("X.509"); + final X509Certificate cert = + (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert)); + certificate(cert); + } catch (final CertificateException e) { + throw new IllegalArgumentException("Unable to parse DER certificate"); + } + } + + /** + * Set the HTTP status code, e.g. 200. + * + * @param code A int representing the HTTP status code. + * @return This Builder instance. + */ + public @NonNull Builder statusCode(final int code) { + mStatusCode = code; + return this; + } + + /** + * Set whether or not this response was the result of a redirect. + * + * @param redirected A boolean representing whether or not the request was redirected. + * @return This Builder instance. + */ + public @NonNull Builder redirected(final boolean redirected) { + mRedirected = redirected; + return this; + } + + /** + * @return A {@link WebResponse} constructed with the values from this Builder instance. + */ + public @NonNull WebResponse build() { + return new WebResponse(this); + } + } +} |