/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tests.http; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import static tests.http.MockWebServer.ASCII; /** * A scripted response to be replayed by the mock web server. */ public class MockResponse implements Cloneable { private static final String RFC_1123_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz"; private static final String EMPTY_BODY_HEADER = "Content-Length: 0"; private static final String CHUNKED_BODY_HEADER = "Transfer-encoding: chunked"; private static final byte[] EMPTY_BODY = new byte[0]; private String status = "HTTP/1.1 200 OK"; private List<String> headers = new ArrayList<String>(); private byte[] body = EMPTY_BODY; private SocketPolicy socketPolicy = SocketPolicy.KEEP_OPEN; public MockResponse() { headers.add(EMPTY_BODY_HEADER); } @Override public MockResponse clone() { try { MockResponse result = (MockResponse) super.clone(); result.headers = new ArrayList<String>(result.headers); return result; } catch (CloneNotSupportedException e) { throw new AssertionError(); } } /** * Returns the HTTP response line, such as "HTTP/1.1 200 OK". */ public String getStatus() { return status; } public MockResponse setResponseCode(int code) { this.status = "HTTP/1.1 " + code + " OK"; return this; } public MockResponse setStatus(String status) { this.status = status; return this; } /** * Returns the HTTP headers, such as "Content-Length: 0". */ public List<String> getHeaders() { return headers; } public MockResponse clearHeaders() { headers.clear(); return this; } public MockResponse addHeader(String header) { headers.add(header); return this; } /** * Returns an input stream containing the raw HTTP payload. */ public byte[] getBody() { return body; } public MockResponse setBody(byte[] body) { if (this.body == EMPTY_BODY) { headers.remove(EMPTY_BODY_HEADER); } this.headers.add("Content-Length: " + body.length); this.body = body; return this; } public MockResponse setBody(String body) { try { return setBody(body.getBytes(ASCII)); } catch (UnsupportedEncodingException e) { throw new AssertionError(); } } public MockResponse setChunkedBody(byte[] body, int maxChunkSize) throws IOException { headers.remove(EMPTY_BODY_HEADER); headers.add(CHUNKED_BODY_HEADER); ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); int pos = 0; while (pos < body.length) { int chunkSize = Math.min(body.length - pos, maxChunkSize); bytesOut.write(Integer.toHexString(chunkSize).getBytes(ASCII)); bytesOut.write("\r\n".getBytes(ASCII)); bytesOut.write(body, pos, chunkSize); bytesOut.write("\r\n".getBytes(ASCII)); pos += chunkSize; } bytesOut.write("0\r\n\r\n".getBytes(ASCII)); // last chunk + empty trailer + crlf this.body = bytesOut.toByteArray(); return this; } public MockResponse setChunkedBody(String body, int maxChunkSize) throws IOException { return setChunkedBody(body.getBytes(ASCII), maxChunkSize); } public SocketPolicy getSocketPolicy() { return socketPolicy; } public MockResponse setSocketPolicy(SocketPolicy socketPolicy) { this.socketPolicy = socketPolicy; return this; } @Override public String toString() { return status; } }