1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.webkit;
18
19import android.annotation.NonNull;
20import android.annotation.SystemApi;
21
22import java.io.InputStream;
23import java.io.StringBufferInputStream;
24import java.util.Map;
25
26/**
27 * Encapsulates a resource response. Applications can return an instance of this
28 * class from {@link WebViewClient#shouldInterceptRequest} to provide a custom
29 * response when the WebView requests a particular resource.
30 */
31public class WebResourceResponse {
32    private boolean mImmutable;
33    private String mMimeType;
34    private String mEncoding;
35    private int mStatusCode;
36    private String mReasonPhrase;
37    private Map<String, String> mResponseHeaders;
38    private InputStream mInputStream;
39
40    /**
41     * Constructs a resource response with the given MIME type, encoding, and
42     * input stream. Callers must implement
43     * {@link InputStream#read(byte[]) InputStream.read(byte[])} for the input
44     * stream.
45     *
46     * @param mimeType the resource response's MIME type, for example text/html
47     * @param encoding the resource response's encoding
48     * @param data the input stream that provides the resource response's data. Must not be a
49     *             StringBufferInputStream.
50     */
51    public WebResourceResponse(String mimeType, String encoding,
52            InputStream data) {
53        mMimeType = mimeType;
54        mEncoding = encoding;
55        setData(data);
56    }
57
58    /**
59     * Constructs a resource response with the given parameters. Callers must
60     * implement {@link InputStream#read(byte[]) InputStream.read(byte[])} for
61     * the input stream.
62     *
63     * @param mimeType the resource response's MIME type, for example text/html
64     * @param encoding the resource response's encoding
65     * @param statusCode the status code needs to be in the ranges [100, 299], [400, 599].
66     *                   Causing a redirect by specifying a 3xx code is not supported.
67     * @param reasonPhrase the phrase describing the status code, for example "OK". Must be
68     *                     non-empty.
69     * @param responseHeaders the resource response's headers represented as a mapping of header
70     *                        name -> header value.
71     * @param data the input stream that provides the resource response's data. Must not be a
72     *             StringBufferInputStream.
73     */
74    public WebResourceResponse(String mimeType, String encoding, int statusCode,
75            @NonNull String reasonPhrase, Map<String, String> responseHeaders, InputStream data) {
76        this(mimeType, encoding, data);
77        setStatusCodeAndReasonPhrase(statusCode, reasonPhrase);
78        setResponseHeaders(responseHeaders);
79    }
80
81    /**
82     * Sets the resource response's MIME type, for example &quot;text/html&quot;.
83     *
84     * @param mimeType The resource response's MIME type
85     */
86    public void setMimeType(String mimeType) {
87        checkImmutable();
88        mMimeType = mimeType;
89    }
90
91    /**
92     * Gets the resource response's MIME type.
93     *
94     * @return The resource response's MIME type
95     */
96    public String getMimeType() {
97        return mMimeType;
98    }
99
100    /**
101     * Sets the resource response's encoding, for example &quot;UTF-8&quot;. This is used
102     * to decode the data from the input stream.
103     *
104     * @param encoding The resource response's encoding
105     */
106    public void setEncoding(String encoding) {
107        checkImmutable();
108        mEncoding = encoding;
109    }
110
111    /**
112     * Gets the resource response's encoding.
113     *
114     * @return The resource response's encoding
115     */
116    public String getEncoding() {
117        return mEncoding;
118    }
119
120    /**
121     * Sets the resource response's status code and reason phrase.
122     *
123     * @param statusCode the status code needs to be in the ranges [100, 299], [400, 599].
124     *                   Causing a redirect by specifying a 3xx code is not supported.
125     * @param reasonPhrase the phrase describing the status code, for example "OK". Must be
126     *                     non-empty.
127     */
128    public void setStatusCodeAndReasonPhrase(int statusCode, @NonNull String reasonPhrase) {
129        checkImmutable();
130        if (statusCode < 100)
131            throw new IllegalArgumentException("statusCode can't be less than 100.");
132        if (statusCode > 599)
133            throw new IllegalArgumentException("statusCode can't be greater than 599.");
134        if (statusCode > 299 && statusCode < 400)
135            throw new IllegalArgumentException("statusCode can't be in the [300, 399] range.");
136        if (reasonPhrase == null)
137            throw new IllegalArgumentException("reasonPhrase can't be null.");
138        if (reasonPhrase.trim().isEmpty())
139            throw new IllegalArgumentException("reasonPhrase can't be empty.");
140        for (int i = 0; i < reasonPhrase.length(); i++) {
141            int c = reasonPhrase.charAt(i);
142            if (c > 0x7F) {
143                throw new IllegalArgumentException(
144                        "reasonPhrase can't contain non-ASCII characters.");
145            }
146        }
147        mStatusCode = statusCode;
148        mReasonPhrase = reasonPhrase;
149    }
150
151    /**
152     * Gets the resource response's status code.
153     *
154     * @return The resource response's status code.
155     */
156    public int getStatusCode() {
157        return mStatusCode;
158    }
159
160    /**
161     * Gets the description of the resource response's status code.
162     *
163     * @return The description of the resource response's status code.
164     */
165    public String getReasonPhrase() {
166        return mReasonPhrase;
167    }
168
169    /**
170     * Sets the headers for the resource response.
171     *
172     * @param headers Mapping of header name -> header value.
173     */
174    public void setResponseHeaders(Map<String, String> headers) {
175        checkImmutable();
176        mResponseHeaders = headers;
177    }
178
179    /**
180     * Gets the headers for the resource response.
181     *
182     * @return The headers for the resource response.
183     */
184    public Map<String, String> getResponseHeaders() {
185        return mResponseHeaders;
186    }
187
188    /**
189     * Sets the input stream that provides the resource response's data. Callers
190     * must implement {@link InputStream#read(byte[]) InputStream.read(byte[])}.
191     *
192     * @param data the input stream that provides the resource response's data. Must not be a
193     *             StringBufferInputStream.
194     */
195    public void setData(InputStream data) {
196        checkImmutable();
197        // If data is (or is a subclass of) StringBufferInputStream
198        if (data != null && StringBufferInputStream.class.isAssignableFrom(data.getClass())) {
199            throw new IllegalArgumentException("StringBufferInputStream is deprecated and must " +
200                "not be passed to a WebResourceResponse");
201        }
202        mInputStream = data;
203    }
204
205    /**
206     * Gets the input stream that provides the resource response's data.
207     *
208     * @return The input stream that provides the resource response's data
209     */
210    public InputStream getData() {
211        return mInputStream;
212    }
213
214    /**
215     * The internal version of the constructor that doesn't perform arguments checks.
216     * @hide
217     */
218    @SystemApi
219    public WebResourceResponse(boolean immutable, String mimeType, String encoding, int statusCode,
220            String reasonPhrase, Map<String, String> responseHeaders, InputStream data) {
221        mImmutable = immutable;
222        mMimeType = mimeType;
223        mEncoding = encoding;
224        mStatusCode = statusCode;
225        mReasonPhrase = reasonPhrase;
226        mResponseHeaders = responseHeaders;
227        mInputStream = data;
228    }
229
230    private void checkImmutable() {
231        if (mImmutable)
232            throw new IllegalStateException("This WebResourceResponse instance is immutable");
233    }
234}
235