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 Wilsonimport static tests.http.MockWebServer.ASCII;
25b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
26b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson/**
27b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson * A scripted response to be replayed by the mock web server.
28b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson */
290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonpublic class MockResponse implements Cloneable {
300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson    private static final String RFC_1123_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
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;
38e942f46f10bb9384a1b186b3d7b74f9704c57090Jesse Wilson    private SocketPolicy socketPolicy = SocketPolicy.KEEP_OPEN;
39b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
40b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse() {
41b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        headers.add(EMPTY_BODY_HEADER);
42b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
43b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson    @Override public MockResponse clone() {
450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson        try {
460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson            MockResponse result = (MockResponse) super.clone();
470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson            result.headers = new ArrayList<String>(result.headers);
480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson            return result;
490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson        } catch (CloneNotSupportedException e) {
500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson            throw new AssertionError();
510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson        }
520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson    }
530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson
54b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    /**
55b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     * Returns the HTTP response line, such as "HTTP/1.1 200 OK".
56b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     */
57b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public String getStatus() {
58b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return status;
59b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
60b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
61b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse setResponseCode(int code) {
62b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        this.status = "HTTP/1.1 " + code + " OK";
63b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return this;
64b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
65b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
66706d53593cd8841d378dbe298a8d1940db1e71dfJesse Wilson    public MockResponse setStatus(String status) {
67706d53593cd8841d378dbe298a8d1940db1e71dfJesse Wilson        this.status = status;
68706d53593cd8841d378dbe298a8d1940db1e71dfJesse Wilson        return this;
69706d53593cd8841d378dbe298a8d1940db1e71dfJesse Wilson    }
70706d53593cd8841d378dbe298a8d1940db1e71dfJesse Wilson
71b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    /**
72b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     * Returns the HTTP headers, such as "Content-Length: 0".
73b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     */
74b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public List<String> getHeaders() {
75b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return headers;
76b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
77b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
78c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson    public MockResponse clearHeaders() {
79c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson        headers.clear();
80c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson        return this;
81c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson    }
82c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson
83b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse addHeader(String header) {
84b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        headers.add(header);
85b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return this;
86b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
87b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
88b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    /**
89b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     * Returns an input stream containing the raw HTTP payload.
90b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson     */
91b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public byte[] getBody() {
92b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return body;
93b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
94b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
95b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse setBody(byte[] body) {
96b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        if (this.body == EMPTY_BODY) {
97b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            headers.remove(EMPTY_BODY_HEADER);
98b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        }
99b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        this.headers.add("Content-Length: " + body.length);
100b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        this.body = body;
101b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return this;
102b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
103b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
104b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse setBody(String body) {
105b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        try {
106b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            return setBody(body.getBytes(ASCII));
107b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        } catch (UnsupportedEncodingException e) {
108b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            throw new AssertionError();
109b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        }
110b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
111b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
112b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse setChunkedBody(byte[] body, int maxChunkSize) throws IOException {
113b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        headers.remove(EMPTY_BODY_HEADER);
114b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        headers.add(CHUNKED_BODY_HEADER);
115b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
116b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
117b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        int pos = 0;
118b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        while (pos < body.length) {
119b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            int chunkSize = Math.min(body.length - pos, maxChunkSize);
120b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            bytesOut.write(Integer.toHexString(chunkSize).getBytes(ASCII));
121b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            bytesOut.write("\r\n".getBytes(ASCII));
122b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            bytesOut.write(body, pos, chunkSize);
123b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            bytesOut.write("\r\n".getBytes(ASCII));
124b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson            pos += chunkSize;
125b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        }
126c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson        bytesOut.write("0\r\n\r\n".getBytes(ASCII)); // last chunk + empty trailer + crlf
127b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        this.body = bytesOut.toByteArray();
128b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return this;
129b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
130b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
131b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    public MockResponse setChunkedBody(String body, int maxChunkSize) throws IOException {
132b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return setChunkedBody(body.getBytes(ASCII), maxChunkSize);
133b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
134b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson
135e942f46f10bb9384a1b186b3d7b74f9704c57090Jesse Wilson    public SocketPolicy getSocketPolicy() {
136e942f46f10bb9384a1b186b3d7b74f9704c57090Jesse Wilson        return socketPolicy;
1374559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
1384559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
139e942f46f10bb9384a1b186b3d7b74f9704c57090Jesse Wilson    public MockResponse setSocketPolicy(SocketPolicy socketPolicy) {
140e942f46f10bb9384a1b186b3d7b74f9704c57090Jesse Wilson        this.socketPolicy = socketPolicy;
14151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson        return this;
14251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson    }
14351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson
144b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    @Override public String toString() {
145b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson        return status;
146b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson    }
147b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson}
148