private static long readLong(BufferedSource source) throws IOException { try { long result = source.readDecimalLong(); String line = source.readUtf8LineStrict(); if (!line.isEmpty()) { throw new IOException("expected new line was \"" + line + "\""); } return result; } catch (NumberFormatException e) { e.printStackTrace(); throw new IOException(e.getMessage()); } }
/** * Reads an entry from an input stream. A typical entry looks like this: * * <pre>{@code * http://google.com/foo * GET * 2 * Accept-Language: fr-CA * Accept-Charset: UTF-8 * HTTP/1.1 200 OK * 3 * Content-Type: image/png * Content-Length: 100 * Cache-Control: max-age=600 * }</pre> * * <p>A typical HTTPS file looks like this: * * <pre>{@code * https://google.com/foo * GET * 2 * Accept-Language: fr-CA * Accept-Charset: UTF-8 * HTTP/1.1 200 OK * 3 * Content-Type: image/png * Content-Length: 100 * Cache-Control: max-age=600 * * AES_256_WITH_MD5 * 2 * base64-encoded peerCertificate[0] * base64-encoded peerCertificate[1] * -1 * }</pre> * * The file is newline separated. The first two lines are the URL and the request method. Next * is the number of HTTP Vary request header lines, followed by those lines. * * <p>Next is the response status line, followed by the number of HTTP response header lines, * followed by those lines. * * <p>HTTPS responses also contain SSL session information. This begins with a blank line, and * then a line containing the cipher suite. Next is the length of the peer certificate chain. * These certificates are base64-encoded and appear each on their own line. The next line * contains the length of the local certificate chain. These certificates are also * base64-encoded and appear each on their own line. A length of -1 is used to encode a null * array. */ public Entry(Source in) throws IOException { try { BufferedSource source = Okio.buffer(in); url = source.readUtf8LineStrict(); requestMethod = source.readUtf8LineStrict(); if (readInt(source) == 1) { MediaType contentType = MediaType.parse(source.readUtf8LineStrict()); int contentLength = readInt(source); requestBody = RequestBody.create(contentType, source.readByteArray(contentLength)); } else { requestBody = null; } Headers.Builder varyHeadersBuilder = new Headers.Builder(); int varyRequestHeaderLineCount = readInt(source); for (int i = 0; i < varyRequestHeaderLineCount; i++) { OkHttpAccess.addLenient(varyHeadersBuilder, source.readUtf8LineStrict()); } varyHeaders = varyHeadersBuilder.build(); StatusLine statusLine = StatusLine.parse(source.readUtf8LineStrict()); protocol = statusLine.protocol; code = statusLine.code; message = statusLine.message; Headers.Builder responseHeadersBuilder = new Headers.Builder(); int responseHeaderLineCount = readInt(source); for (int i = 0; i < responseHeaderLineCount; i++) { OkHttpAccess.addLenient(responseHeadersBuilder, source.readUtf8LineStrict()); } responseHeaders = responseHeadersBuilder.build(); if (isHttps()) { String blank = source.readUtf8LineStrict(); if (blank.length() > 0) { throw new IOException("expected \"\" but was \"" + blank + "\""); } String cipherSuite = source.readUtf8LineStrict(); List<Certificate> peerCertificates = readCertificateList(source); List<Certificate> localCertificates = readCertificateList(source); handshake = Handshake.get(cipherSuite, peerCertificates, localCertificates); } else { handshake = null; } } finally { in.close(); } }
private List<Certificate> readCertificateList(BufferedSource source) throws IOException { int length = readInt(source); if (length == -1) return Collections.emptyList(); // OkHttp v1.2 used -1 to indicate null. try { CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); List<Certificate> result = new ArrayList<>(length); for (int i = 0; i < length; i++) { String line = source.readUtf8LineStrict(); Buffer bytes = new Buffer(); bytes.write(ByteString.decodeBase64(line)); result.add(certificateFactory.generateCertificate(bytes.inputStream())); } return result; } catch (CertificateException e) { throw new IOException(e.getMessage()); } }