154ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson/*
254ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson * Copyright (C) 2011 Google Inc.
354ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson *
454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
554ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson * you may not use this file except in compliance with the License.
654ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson * You may obtain a copy of the License at
754ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson *
854ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
954ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson *
1054ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson * Unless required by applicable law or agreed to in writing, software
1154ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
1254ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1354ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson * See the License for the specific language governing permissions and
1454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson * limitations under the License.
1554ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson */
1654ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson
1754ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilsonpackage com.google.mockwebserver;
1854ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson
197a68ed6a49c3060b235810391a82412a95f9c979jwilsonimport java.io.UnsupportedEncodingException;
2024198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilsonimport java.net.Socket;
217a68ed6a49c3060b235810391a82412a95f9c979jwilsonimport java.util.ArrayList;
2254ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilsonimport java.util.List;
2324198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilsonimport javax.net.ssl.SSLSocket;
2454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson
2554ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson/**
2654ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson * An HTTP request that came into the mock web server.
2754ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson */
2854ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilsonpublic final class RecordedRequest {
2954ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    private final String requestLine;
303b406d4de9b5f0f1caa990f079075eb0bfc5220aJeff Sharkey    private final String method;
313b406d4de9b5f0f1caa990f079075eb0bfc5220aJeff Sharkey    private final String path;
3254ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    private final List<String> headers;
3354ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    private final List<Integer> chunkSizes;
3454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    private final int bodySize;
3554ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    private final byte[] body;
3654ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    private final int sequenceNumber;
3724198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson    private final String sslProtocol;
3854ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson
397a68ed6a49c3060b235810391a82412a95f9c979jwilson    public RecordedRequest(String requestLine, List<String> headers, List<Integer> chunkSizes,
4024198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson            int bodySize, byte[] body, int sequenceNumber, Socket socket) {
4154ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        this.requestLine = requestLine;
4254ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        this.headers = headers;
4354ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        this.chunkSizes = chunkSizes;
4454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        this.bodySize = bodySize;
4554ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        this.body = body;
4654ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        this.sequenceNumber = sequenceNumber;
4724198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson
4824198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson        if (socket instanceof SSLSocket) {
4924198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson            SSLSocket sslSocket = (SSLSocket) socket;
5024198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson            sslProtocol = sslSocket.getSession().getProtocol();
5124198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson        } else {
5224198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson            sslProtocol = null;
5324198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson        }
543b406d4de9b5f0f1caa990f079075eb0bfc5220aJeff Sharkey
5583aa2d278c5a3f9b93cd809f6fdffba9d1fa3868Brian Muramatsu        if (requestLine != null) {
5683aa2d278c5a3f9b93cd809f6fdffba9d1fa3868Brian Muramatsu            int methodEnd = requestLine.indexOf(' ');
5783aa2d278c5a3f9b93cd809f6fdffba9d1fa3868Brian Muramatsu            int pathEnd = requestLine.indexOf(' ', methodEnd + 1);
5883aa2d278c5a3f9b93cd809f6fdffba9d1fa3868Brian Muramatsu            this.method = requestLine.substring(0, methodEnd);
5983aa2d278c5a3f9b93cd809f6fdffba9d1fa3868Brian Muramatsu            this.path = requestLine.substring(methodEnd + 1, pathEnd);
6083aa2d278c5a3f9b93cd809f6fdffba9d1fa3868Brian Muramatsu        } else {
6183aa2d278c5a3f9b93cd809f6fdffba9d1fa3868Brian Muramatsu            this.method = null;
6283aa2d278c5a3f9b93cd809f6fdffba9d1fa3868Brian Muramatsu            this.path = null;
6383aa2d278c5a3f9b93cd809f6fdffba9d1fa3868Brian Muramatsu        }
6454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    }
6554ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson
6654ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    public String getRequestLine() {
6754ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        return requestLine;
6854ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    }
6954ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson
707a68ed6a49c3060b235810391a82412a95f9c979jwilson    public String getMethod() {
717a68ed6a49c3060b235810391a82412a95f9c979jwilson        return method;
727a68ed6a49c3060b235810391a82412a95f9c979jwilson    }
737a68ed6a49c3060b235810391a82412a95f9c979jwilson
747a68ed6a49c3060b235810391a82412a95f9c979jwilson    public String getPath() {
757a68ed6a49c3060b235810391a82412a95f9c979jwilson        return path;
767a68ed6a49c3060b235810391a82412a95f9c979jwilson    }
777a68ed6a49c3060b235810391a82412a95f9c979jwilson
787a68ed6a49c3060b235810391a82412a95f9c979jwilson    /**
797a68ed6a49c3060b235810391a82412a95f9c979jwilson     * Returns all headers.
807a68ed6a49c3060b235810391a82412a95f9c979jwilson     */
8154ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    public List<String> getHeaders() {
8254ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        return headers;
8354ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    }
8454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson
8554ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    /**
867a68ed6a49c3060b235810391a82412a95f9c979jwilson     * Returns the first header named {@code name}, or null if no such header
877a68ed6a49c3060b235810391a82412a95f9c979jwilson     * exists.
887a68ed6a49c3060b235810391a82412a95f9c979jwilson     */
897a68ed6a49c3060b235810391a82412a95f9c979jwilson    public String getHeader(String name) {
907a68ed6a49c3060b235810391a82412a95f9c979jwilson        name += ":";
917a68ed6a49c3060b235810391a82412a95f9c979jwilson        for (String header : headers) {
927a68ed6a49c3060b235810391a82412a95f9c979jwilson            if (name.regionMatches(true, 0, header, 0, name.length())) {
937a68ed6a49c3060b235810391a82412a95f9c979jwilson                return header.substring(name.length()).trim();
947a68ed6a49c3060b235810391a82412a95f9c979jwilson            }
957a68ed6a49c3060b235810391a82412a95f9c979jwilson        }
967a68ed6a49c3060b235810391a82412a95f9c979jwilson        return null;
977a68ed6a49c3060b235810391a82412a95f9c979jwilson    }
987a68ed6a49c3060b235810391a82412a95f9c979jwilson
997a68ed6a49c3060b235810391a82412a95f9c979jwilson    /**
1007a68ed6a49c3060b235810391a82412a95f9c979jwilson     * Returns the headers named {@code name}.
1017a68ed6a49c3060b235810391a82412a95f9c979jwilson     */
1027a68ed6a49c3060b235810391a82412a95f9c979jwilson    public List<String> getHeaders(String name) {
1037a68ed6a49c3060b235810391a82412a95f9c979jwilson        List<String> result = new ArrayList<String>();
1047a68ed6a49c3060b235810391a82412a95f9c979jwilson        name += ":";
1057a68ed6a49c3060b235810391a82412a95f9c979jwilson        for (String header : headers) {
1067a68ed6a49c3060b235810391a82412a95f9c979jwilson            if (name.regionMatches(true, 0, header, 0, name.length())) {
1077a68ed6a49c3060b235810391a82412a95f9c979jwilson                result.add(header.substring(name.length()).trim());
1087a68ed6a49c3060b235810391a82412a95f9c979jwilson            }
1097a68ed6a49c3060b235810391a82412a95f9c979jwilson        }
1107a68ed6a49c3060b235810391a82412a95f9c979jwilson        return result;
1117a68ed6a49c3060b235810391a82412a95f9c979jwilson    }
1127a68ed6a49c3060b235810391a82412a95f9c979jwilson
1137a68ed6a49c3060b235810391a82412a95f9c979jwilson    /**
11454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     * Returns the sizes of the chunks of this request's body, or an empty list
11554ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     * if the request's body was empty or unchunked.
11654ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     */
11754ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    public List<Integer> getChunkSizes() {
11854ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        return chunkSizes;
11954ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    }
12054ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson
12154ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    /**
12254ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     * Returns the total size of the body of this POST request (before
12354ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     * truncation).
12454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     */
12554ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    public int getBodySize() {
12654ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        return bodySize;
12754ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    }
12854ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson
12954ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    /**
13054ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     * Returns the body of this POST request. This may be truncated.
13154ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     */
13254ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    public byte[] getBody() {
13354ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        return body;
13454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    }
13554ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson
13654ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    /**
1377a68ed6a49c3060b235810391a82412a95f9c979jwilson     * Returns the body of this POST request decoded as a UTF-8 string.
1387a68ed6a49c3060b235810391a82412a95f9c979jwilson     */
1397a68ed6a49c3060b235810391a82412a95f9c979jwilson    public String getUtf8Body() {
1407a68ed6a49c3060b235810391a82412a95f9c979jwilson        try {
1417a68ed6a49c3060b235810391a82412a95f9c979jwilson            return new String(body, "UTF-8");
1427a68ed6a49c3060b235810391a82412a95f9c979jwilson        } catch (UnsupportedEncodingException e) {
1437a68ed6a49c3060b235810391a82412a95f9c979jwilson            throw new AssertionError();
1447a68ed6a49c3060b235810391a82412a95f9c979jwilson        }
1457a68ed6a49c3060b235810391a82412a95f9c979jwilson    }
1467a68ed6a49c3060b235810391a82412a95f9c979jwilson
1477a68ed6a49c3060b235810391a82412a95f9c979jwilson    /**
14854ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     * Returns the index of this request on its HTTP connection. Since a single
14954ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     * HTTP connection may serve multiple requests, each request is assigned its
15054ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     * own sequence number.
15154ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson     */
15254ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    public int getSequenceNumber() {
15354ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson        return sequenceNumber;
15454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    }
15554ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson
15624198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson    /**
15724198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson     * Returns the connection's SSL protocol like {@code TLSv1}, {@code SSLv3},
15824198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson     * {@code NONE} or null if the connection doesn't use SSL.
15924198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson     */
16024198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson    public String getSslProtocol() {
16124198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson        return sslProtocol;
16224198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson    }
16324198dd39014c4490b963f039b04d52e01d79bc5Jesse Wilson
16454ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    @Override public String toString() {
165cb8ab9cb9f5da083e7390920f0f7d0c8a879cb6bNarayan Kamath        return "RecordedRequest {" + requestLine + "}";
16654ce6cb5d13f732a3e71aa3555cd3709d5bf3cf5Jesse Wilson    }
167cb8ab9cb9f5da083e7390920f0f7d0c8a879cb6bNarayan Kamath}
168