MockResponse.java revision 4559b1d37edcb5d7f1da086cf2e3290388d74f46
1b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson/*
2b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson * Copyright (C) 2010 The Android Open Source Project
3b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson *
4b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson * you may not use this file except in compliance with the License.
6b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson * You may obtain a copy of the License at
7b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson *
8b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson *
10b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson * See the License for the specific language governing permissions and
14b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson * limitations under the License.
15b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson */
16b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
17b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilsonpackage tests.http;
18b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
19b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilsonimport java.io.ByteArrayOutputStream;
20b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilsonimport java.io.IOException;
21b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilsonimport java.io.UnsupportedEncodingException;
22b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilsonimport java.util.ArrayList;
23b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilsonimport java.util.List;
24b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
25b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilsonimport static tests.http.MockWebServer.ASCII;
26b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
27b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson/**
28b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson * A scripted response to be replayed by the mock web server.
29b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson */
30b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilsonpublic class MockResponse {
31b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    private static final String EMPTY_BODY_HEADER = "Content-Length: 0";
32b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    private static final String CHUNKED_BODY_HEADER = "Transfer-encoding: chunked";
33b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    private static final byte[] EMPTY_BODY = new byte[0];
34b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
35b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    private String status = "HTTP/1.1 200 OK";
36b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    private List<String> headers = new ArrayList<String>();
37b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    private byte[] body = EMPTY_BODY;
384559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    private boolean disconnectAtStart;
3951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson    private boolean disconnectAtEnd;
40b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
41b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse() {
42b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        headers.add(EMPTY_BODY_HEADER);
43b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
44b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
45b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    /**
46b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     * Returns the HTTP response line, such as "HTTP/1.1 200 OK".
47b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     */
48b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public String getStatus() {
49b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return status;
50b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
51b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
52b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse setResponseCode(int code) {
53b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        this.status = "HTTP/1.1 " + code + " OK";
54b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return this;
55b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
56b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
57706d53593cd8841d378dbe298a8d1940db1e71dfJesse Wilson    public MockResponse setStatus(String status) {
58706d53593cd8841d378dbe298a8d1940db1e71dfJesse Wilson        this.status = status;
59706d53593cd8841d378dbe298a8d1940db1e71dfJesse Wilson        return this;
60706d53593cd8841d378dbe298a8d1940db1e71dfJesse Wilson    }
61706d53593cd8841d378dbe298a8d1940db1e71dfJesse Wilson
62b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    /**
63b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     * Returns the HTTP headers, such as "Content-Length: 0".
64b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     */
65b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public List<String> getHeaders() {
66b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return headers;
67b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
68b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
69c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson    public MockResponse clearHeaders() {
70c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson        headers.clear();
71c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson        return this;
72c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson    }
73c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson
74b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse addHeader(String header) {
75b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        headers.add(header);
76b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return this;
77b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
78b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
79b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    /**
80b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     * Returns an input stream containing the raw HTTP payload.
81b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     */
82b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public byte[] getBody() {
83b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return body;
84b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
85b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
86b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse setBody(byte[] body) {
87b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        if (this.body == EMPTY_BODY) {
88b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            headers.remove(EMPTY_BODY_HEADER);
89b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        }
90b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        this.headers.add("Content-Length: " + body.length);
91b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        this.body = body;
92b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return this;
93b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
94b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
95b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse setBody(String body) {
96b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        try {
97b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            return setBody(body.getBytes(ASCII));
98b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        } catch (UnsupportedEncodingException e) {
99b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            throw new AssertionError();
100b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        }
101b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
102b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
103b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse setChunkedBody(byte[] body, int maxChunkSize) throws IOException {
104b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        headers.remove(EMPTY_BODY_HEADER);
105b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        headers.add(CHUNKED_BODY_HEADER);
106b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
107b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
108b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        int pos = 0;
109b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        while (pos < body.length) {
110b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            int chunkSize = Math.min(body.length - pos, maxChunkSize);
111b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            bytesOut.write(Integer.toHexString(chunkSize).getBytes(ASCII));
112b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            bytesOut.write("\r\n".getBytes(ASCII));
113b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            bytesOut.write(body, pos, chunkSize);
114b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            bytesOut.write("\r\n".getBytes(ASCII));
115b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            pos += chunkSize;
116b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        }
117c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson        bytesOut.write("0\r\n\r\n".getBytes(ASCII)); // last chunk + empty trailer + crlf
118b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        this.body = bytesOut.toByteArray();
119b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return this;
120b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
121b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
122b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse setChunkedBody(String body, int maxChunkSize) throws IOException {
123b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return setChunkedBody(body.getBytes(ASCII), maxChunkSize);
124b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
125b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
1264559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    /**
1274559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * Request immediate close of connection without even reading the
1284559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * request.
1294559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * <p>
1304559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * Use to simulate the real life case of losing connection
1314559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * because of bugger SSL server close connection when it seems
1324559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * something like a compression method or TLS extension it doesn't
1334559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * understand, instead of simply ignoring it like it should.
1344559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
1354559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public MockResponse setDisconnectAtStart(boolean disconnectAtStart) {
1364559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        this.disconnectAtStart = disconnectAtStart;
1374559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        return this;
1384559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
1394559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
1404559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public boolean getDisconnectAtStart() {
1414559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        return disconnectAtStart;
1424559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
1434559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
1444559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    /**
1454559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * Request close of connection after the response. This is the
1464559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * default HTTP/1.0 behavior.
1474559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
14851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson    public MockResponse setDisconnectAtEnd(boolean disconnectAtEnd) {
14951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson        this.disconnectAtEnd = disconnectAtEnd;
15051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson        return this;
15151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson    }
15251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson
15351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson    public boolean getDisconnectAtEnd() {
15451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson        return disconnectAtEnd;
15551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson    }
15651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson
157b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    @Override public String toString() {
158b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return status;
159b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
160b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson}
161