1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-21 03:41:07 +03:00

Merge pull request #553 from square/jwilson_0222_hex

OkBuffer toString and hex.
This commit is contained in:
Adrian Cole
2014-02-22 13:17:34 -08:00
25 changed files with 278 additions and 209 deletions

View File

@@ -63,7 +63,7 @@ import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okio.ByteString;
import okio.OkBuffers;
import okio.Okio;
import static com.squareup.okhttp.mockwebserver.SocketPolicy.DISCONNECT_AT_START;
import static com.squareup.okhttp.mockwebserver.SocketPolicy.FAIL_HANDSHAKE;
@@ -656,7 +656,7 @@ public final class MockWebServer {
}
}
InputStream bodyIn = OkBuffers.buffer(stream.getSource()).inputStream();
InputStream bodyIn = Okio.buffer(stream.getSource()).inputStream();
ByteArrayOutputStream bodyOut = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int count;

View File

@@ -39,6 +39,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadFactory;
import okio.ByteString;
import okio.OkBuffer;
import okio.Sink;
import okio.Source;
@@ -57,9 +58,6 @@ public final class Util {
/** A cheap and type-safe constant for the UTF-8 Charset. */
public static final Charset UTF_8 = Charset.forName("UTF-8");
private static final char[] DIGITS =
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
private Util() {
}
@@ -303,7 +301,7 @@ public final class Util {
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
byte[] md5bytes = messageDigest.digest(s.getBytes("UTF-8"));
return bytesToHexString(md5bytes);
return ByteString.of(md5bytes).hex();
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
} catch (UnsupportedEncodingException e) {
@@ -311,17 +309,6 @@ public final class Util {
}
}
private static String bytesToHexString(byte[] bytes) {
char[] digits = DIGITS;
char[] buf = new char[bytes.length * 2];
int c = 0;
for (byte b : bytes) {
buf[c++] = digits[(b >> 4) & 0xf];
buf[c++] = digits[b & 0xf];
}
return new String(buf);
}
/** Returns an immutable copy of {@code list}. */
public static <T> List<T> immutableList(List<T> list) {
return Collections.unmodifiableList(new ArrayList<T>(list));

View File

@@ -11,7 +11,7 @@ import java.util.List;
import java.util.Map;
import okio.BufferedSource;
import okio.ByteString;
import okio.OkBuffers;
import okio.Okio;
import okio.Source;
/**
@@ -125,7 +125,7 @@ final class HpackDraft05 {
Reader(boolean client, int maxHeaderTableByteCount, Source source) {
this.huffmanCodec = client ? Huffman.Codec.RESPONSE : Huffman.Codec.REQUEST;
this.maxHeaderTableByteCount = maxHeaderTableByteCount;
this.source = OkBuffers.buffer(source);
this.source = Okio.buffer(source);
}
int maxHeaderTableByteCount() {

View File

@@ -10,7 +10,7 @@ import okio.ByteString;
import okio.Deadline;
import okio.InflaterSource;
import okio.OkBuffer;
import okio.OkBuffers;
import okio.Okio;
import okio.Source;
/**
@@ -70,7 +70,7 @@ class NameValueBlockReader {
};
this.inflaterSource = new InflaterSource(throttleSource, inflater);
this.source = OkBuffers.buffer(inflaterSource);
this.source = Okio.buffer(inflaterSource);
}
public List<Header> readNameValueBlock(int length) throws IOException {

View File

@@ -33,7 +33,7 @@ import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import okio.BufferedSource;
import okio.ByteString;
import okio.OkBuffers;
import okio.Okio;
/**
* A socket connection to a remote peer. A connection hosts streams which can
@@ -464,7 +464,7 @@ public final class SpdyConnection implements Closeable {
private boolean client;
public Builder(boolean client, Socket socket) throws IOException {
this("", client, OkBuffers.buffer(OkBuffers.source(socket.getInputStream())),
this("", client, Okio.buffer(Okio.source(socket.getInputStream())),
socket.getOutputStream());
}

View File

@@ -26,17 +26,18 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class ByteStringTest {
@Test public void equals() throws Exception {
ByteString byteString = ByteString.of((byte) 0x0, (byte) 0x1, (byte) 0x2);
ByteString byteString = ByteString.decodeHex("000102");
assertTrue(byteString.equals(byteString));
assertTrue(byteString.equals(ByteString.of((byte) 0x0, (byte) 0x1, (byte) 0x2)));
assertTrue(byteString.equals(ByteString.decodeHex("000102")));
assertTrue(ByteString.of().equals(ByteString.EMPTY));
assertTrue(ByteString.EMPTY.equals(ByteString.of()));
assertFalse(byteString.equals(new Object()));
assertFalse(byteString.equals(ByteString.of((byte) 0x0, (byte) 0x2, (byte) 0x1)));
assertFalse(byteString.equals(ByteString.decodeHex("000201")));
}
private final String bronzeHorseman = "На берегу пустынных волн";
@@ -58,15 +59,15 @@ public class ByteStringTest {
}
@Test public void testHashCode() throws Exception {
ByteString byteString = ByteString.of((byte) 0x1, (byte) 0x2);
ByteString byteString = ByteString.decodeHex("0102");
assertEquals(byteString.hashCode(), byteString.hashCode());
assertEquals(byteString.hashCode(), ByteString.of((byte) 0x1, (byte) 0x2).hashCode());
assertEquals(byteString.hashCode(), ByteString.decodeHex("0102").hashCode());
}
@Test public void read() throws Exception {
InputStream in = new ByteArrayInputStream("abc".getBytes(Util.UTF_8));
assertEquals(ByteString.of((byte) 0x61, (byte) 0x62), ByteString.read(in, 2));
assertEquals(ByteString.of((byte) 0x63), ByteString.read(in, 1));
assertEquals(ByteString.decodeHex("6162"), ByteString.read(in, 2));
assertEquals(ByteString.decodeHex("63"), ByteString.read(in, 1));
assertEquals(ByteString.of(), ByteString.read(in, 0));
}
@@ -92,7 +93,7 @@ public class ByteStringTest {
@Test public void write() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteString.of((byte) 0x61, (byte) 0x62, (byte) 0x63).write(out);
ByteString.decodeHex("616263").write(out);
assertByteArraysEquals(new byte[] { 0x61, 0x62, 0x63 }, out.toByteArray());
}
@@ -123,16 +124,16 @@ public class ByteStringTest {
@Test public void decodeBase64() {
assertEquals("", ByteString.decodeBase64("").utf8());
assertEquals(null, ByteString.decodeBase64("/===")); // Can't do anything with 6 bits!
assertEquals(bytes(0xff), ByteString.decodeBase64("//=="));
assertEquals(bytes(0xff, 0xff), ByteString.decodeBase64("///="));
assertEquals(bytes(0xff, 0xff, 0xff), ByteString.decodeBase64("////"));
assertEquals(bytes(0xff, 0xff, 0xff, 0xff, 0xff, 0xff), ByteString.decodeBase64("////////"));
assertEquals(ByteString.decodeHex("ff"), ByteString.decodeBase64("//=="));
assertEquals(ByteString.decodeHex("ffff"), ByteString.decodeBase64("///="));
assertEquals(ByteString.decodeHex("ffffff"), ByteString.decodeBase64("////"));
assertEquals(ByteString.decodeHex("ffffffffffff"), ByteString.decodeBase64("////////"));
assertEquals("What's to be scared about? It's just a little hiccup in the power...",
ByteString.decodeBase64("V2hhdCdzIHRvIGJlIHNjYXJlZCBhYm91dD8gSXQncyBqdXN0IGEgbGl0dGxlIGhpY2"
+ "N1cCBpbiB0aGUgcG93ZXIuLi4=").utf8());
}
@Test public void decodeWithWhitespace() {
@Test public void decodeBase64WithWhitespace() {
assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64(" AA AA ").utf8());
assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64(" AA A\r\nA ").utf8());
assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64("AA AA").utf8());
@@ -142,13 +143,28 @@ public class ByteStringTest {
assertEquals("", ByteString.decodeBase64(" ").utf8());
}
/** Make it easy to make varargs calls. Otherwise we need a lot of (byte) casts. */
private ByteString bytes(int... bytes) {
byte[] result = new byte[bytes.length];
for (int i = 0; i < bytes.length; i++) {
result[i] = (byte) bytes[i];
@Test public void encodeHex() throws Exception {
assertEquals("000102", ByteString.of((byte) 0x0, (byte) 0x1, (byte) 0x2).hex());
}
@Test public void decodeHex() throws Exception {
assertEquals(ByteString.of((byte) 0x0, (byte) 0x1, (byte) 0x2), ByteString.decodeHex("000102"));
}
@Test public void decodeHexOddNumberOfChars() throws Exception {
try {
ByteString.decodeHex("aaa");
fail();
} catch (IllegalArgumentException expected) {
}
}
@Test public void decodeHexInvalidChar() throws Exception {
try {
ByteString.decodeHex("a\u0000");
fail();
} catch (IllegalArgumentException expected) {
}
return ByteString.of(result);
}
private static void assertByteArraysEquals(byte[] a, byte[] b) {

View File

@@ -23,7 +23,7 @@ import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import okio.ByteString;
import okio.OkBuffers;
import okio.Okio;
import org.junit.Before;
import org.junit.Test;
@@ -800,7 +800,7 @@ public class HpackDraft05Test {
}
private HpackDraft05.Reader newReader(InputStream input) {
return new HpackDraft05.Reader(false, 4096, OkBuffers.source(input));
return new HpackDraft05.Reader(false, 4096, Okio.source(input));
}
private InputStream byteStream(int... bytes) {

View File

@@ -33,7 +33,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import okio.BufferedSource;
import okio.ByteString;
import okio.OkBuffers;
import okio.Okio;
/** Replays prerecorded outgoing frames and records incoming frames. */
public final class MockSpdyPeer implements Closeable {
@@ -118,7 +118,7 @@ public final class MockSpdyPeer implements Closeable {
socket = serverSocket.accept();
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
FrameReader reader = variant.newReader(OkBuffers.buffer(OkBuffers.source(in)), client);
FrameReader reader = variant.newReader(Okio.buffer(Okio.source(in)), client);
Iterator<OutFrame> outFramesIterator = outFrames.iterator();
byte[] outBytes = bytesOut.toByteArray();

View File

@@ -24,7 +24,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import okio.ByteString;
import okio.OkBuffer;
import okio.OkBuffers;
import okio.Okio;
import okio.Source;
import org.junit.After;
import org.junit.Test;
@@ -1252,7 +1252,7 @@ public final class SpdyConnectionTest {
assertEquals(headerEntries("a", "android"), stream.getResponseHeaders());
Source in = stream.getSource();
try {
OkBuffers.buffer(in).readByteString(101);
Okio.buffer(in).readByteString(101);
fail();
} catch (IOException expected) {
assertEquals("stream was reset: PROTOCOL_ERROR", expected.getMessage());

View File

@@ -34,7 +34,7 @@ import java.net.SocketTimeoutException;
import javax.net.ssl.SSLSocket;
import okio.BufferedSource;
import okio.ByteString;
import okio.OkBuffers;
import okio.Okio;
import static java.net.HttpURLConnection.HTTP_OK;
import static java.net.HttpURLConnection.HTTP_PROXY_AUTH;
@@ -306,7 +306,7 @@ public final class Connection implements Closeable {
* retried if the proxy requires authorization.
*/
private void makeTunnel(TunnelRequest tunnelRequest) throws IOException {
BufferedSource tunnelSource = OkBuffers.buffer(OkBuffers.source(in));
BufferedSource tunnelSource = Okio.buffer(Okio.source(in));
HttpConnection tunnelConnection = new HttpConnection(pool, this, tunnelSource, out);
Request request = tunnelRequest.getRequest();
String requestLine = tunnelRequest.requestLine();
@@ -338,7 +338,7 @@ public final class Connection implements Closeable {
}
private void streamWrapper() throws IOException {
source = OkBuffers.buffer(OkBuffers.source(in));
source = Okio.buffer(Okio.source(in));
out = new BufferedOutputStream(out, 256);
}
}

View File

@@ -25,7 +25,7 @@ import java.io.InputStream;
import java.net.ProtocolException;
import java.net.Proxy;
import java.net.URL;
import okio.OkBuffers;
import okio.Okio;
import okio.Source;
import static com.squareup.okhttp.internal.Util.getEffectivePort;
@@ -264,7 +264,7 @@ final class Job extends NamedRunnable {
InputStream result = in;
return result != null
? result
: (in = OkBuffers.buffer(source).inputStream());
: (in = Okio.buffer(source).inputStream());
}
}
}

View File

@@ -32,7 +32,7 @@ import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import okio.OkBuffers;
import okio.Okio;
import okio.Source;
import static com.squareup.okhttp.internal.Util.UTF_8;
@@ -221,7 +221,7 @@ public final class Response {
// TODO: Source needs to be an API type for this to be public
public Source source() {
Source s = source;
return s != null ? s : (source = OkBuffers.source(byteStream()));
return s != null ? s : (source = Okio.source(byteStream()));
}
public final byte[] bytes() throws IOException {

View File

@@ -32,7 +32,7 @@ import java.net.Socket;
import okio.BufferedSource;
import okio.Deadline;
import okio.OkBuffer;
import okio.OkBuffers;
import okio.Okio;
import okio.Source;
import static com.squareup.okhttp.internal.Util.checkOffsetAndCount;
@@ -425,7 +425,7 @@ public final class HttpConnection {
/** Copy the last {@code byteCount} bytes of {@code source} to the cache body. */
protected final void cacheWrite(OkBuffer source, long byteCount) throws IOException {
if (cacheBody != null) {
OkBuffers.copy(source, source.byteCount() - byteCount, byteCount, cacheBody);
Okio.copy(source, source.byteCount() - byteCount, byteCount, cacheBody);
}
}

View File

@@ -43,7 +43,7 @@ import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSocketFactory;
import okio.GzipSource;
import okio.OkBuffers;
import okio.Okio;
import okio.Source;
import static com.squareup.okhttp.internal.Util.closeQuietly;
@@ -290,7 +290,7 @@ public class HttpEngine {
InputStream result = responseBodyBytes;
return result != null
? result
: (responseBodyBytes = OkBuffers.buffer(getResponseBody()).inputStream());
: (responseBodyBytes = Okio.buffer(getResponseBody()).inputStream());
}
public final Connection getConnection() {

View File

@@ -37,7 +37,7 @@ import java.util.Set;
import okio.ByteString;
import okio.Deadline;
import okio.OkBuffer;
import okio.OkBuffers;
import okio.Okio;
import okio.Source;
import static com.squareup.okhttp.internal.spdy.Header.RESPONSE_STATUS;
@@ -273,7 +273,7 @@ public final class SpdyTransport implements Transport {
}
if (cacheBody != null) {
OkBuffers.copy(sink, sink.byteCount() - read, read, cacheBody);
Okio.copy(sink, sink.byteCount() - read, read, cacheBody);
}
return read;

View File

@@ -32,6 +32,9 @@ import java.util.Arrays;
* process.
*/
public final class ByteString {
private static final char[] HEX_DIGITS =
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
final byte[] data;
private transient int hashCode; // Lazily computed; 0 if unknown.
private transient String utf8; // Lazily computed.
@@ -78,6 +81,37 @@ public final class ByteString {
return decoded != null ? new ByteString(decoded) : null;
}
/** Returns this byte string encoded in hexadecimal. */
public String hex() {
char[] result = new char[data.length * 2];
int c = 0;
for (byte b : data) {
result[c++] = HEX_DIGITS[(b >> 4) & 0xf];
result[c++] = HEX_DIGITS[b & 0xf];
}
return new String(result);
}
/** Decodes the hex-encoded bytes and returns their value a byte string. */
public static ByteString decodeHex(String hex) {
if (hex.length() % 2 != 0) throw new IllegalArgumentException("Unexpected hex string: " + hex);
byte[] result = new byte[hex.length() / 2];
for (int i = 0; i < result.length; i++) {
int d1 = decodeHexDigit(hex.charAt(i * 2)) << 4;
int d2 = decodeHexDigit(hex.charAt(i * 2 + 1));
result[i] = (byte) (d1 + d2);
}
return of(result);
}
private static int decodeHexDigit(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
throw new IllegalArgumentException("Unexpected hex digit: " + c);
}
/**
* Returns true when {@code ascii} is not null and equals the bytes wrapped
* by this byte string.

View File

@@ -40,7 +40,7 @@ public final class DeflaterSink implements Sink {
private final Deflater deflater;
public DeflaterSink(Sink sink, Deflater deflater) {
this.sink = OkBuffers.buffer(sink);
this.sink = Okio.buffer(sink);
this.deflater = deflater;
}

View File

@@ -54,7 +54,7 @@ public final class GzipSource implements Source {
public GzipSource(Source source) throws IOException {
this.inflater = new Inflater(true);
this.source = OkBuffers.buffer(source);
this.source = Okio.buffer(source);
this.inflaterSource = new InflaterSource(this.source, inflater);
}

View File

@@ -37,7 +37,7 @@ public final class InflaterSource implements Source {
private boolean closed;
public InflaterSource(Source source, Inflater inflater) {
this(OkBuffers.buffer(source), inflater);
this(Okio.buffer(source), inflater);
}
/**

View File

@@ -18,6 +18,8 @@ package okio;
import java.io.EOFException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -41,9 +43,6 @@ import static okio.Util.checkOffsetAndCount;
* This class avoids zero-fill and GC churn by pooling byte arrays.
*/
public final class OkBuffer implements BufferedSource, BufferedSink, Cloneable {
private static final char[] HEX_DIGITS =
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
Segment head;
long byteCount;
@@ -579,22 +578,27 @@ public final class OkBuffer implements BufferedSource, BufferedSink, Cloneable {
return result;
}
/**
* Returns the contents of this buffer in hex. For buffers larger than 1 MiB
* this method is undefined.
*/
@Override public String toString() {
if (byteCount > 0x100000) return super.toString();
int charCount = (int) (byteCount * 2);
char[] result = new char[charCount];
int offset = 0;
for (Segment s = head; offset < charCount; s = s.next) {
for (int i = s.pos; i < s.limit; i++) {
result[offset++] = HEX_DIGITS[(s.data[i] >> 4) & 0xf];
result[offset++] = HEX_DIGITS[s.data[i] & 0xf];
}
if (byteCount == 0) {
return "OkBuffer[size=0]";
}
if (byteCount <= 16) {
ByteString data = clone().readByteString((int) byteCount);
return String.format("OkBuffer[size=%s data=%s]", byteCount, data.hex());
}
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(head.data, head.pos, head.limit - head.pos);
for (Segment s = head.next; s != head; s = s.next) {
md5.update(s.data, s.pos, s.limit - s.pos);
}
return String.format("OkBuffer[size=%s md5=%s]",
byteCount, ByteString.of(md5.digest()).hex());
} catch (NoSuchAlgorithmException e) {
throw new AssertionError();
}
return new String(result);
}
/** Returns a deep copy of this buffer. */

View File

@@ -21,8 +21,8 @@ import java.io.OutputStream;
import static okio.Util.checkOffsetAndCount;
public final class OkBuffers {
private OkBuffers() {
public final class Okio {
private Okio() {
}
public static BufferedSource buffer(Source source) {

View File

@@ -16,7 +16,6 @@
package okio;
import java.io.IOException;
import java.util.Arrays;
import java.util.zip.CRC32;
import org.junit.Test;
@@ -30,51 +29,52 @@ public class GzipSourceTest {
@Test public void gunzip() throws Exception {
OkBuffer gzipped = new OkBuffer();
gzipped.write(gzipHeader, 0, gzipHeader.length);
gzipped.write(deflated, 0, deflated.length);
gzipped.write(gzipTrailer, 0, gzipTrailer.length);
gzipped.write(gzipHeader);
gzipped.write(deflated);
gzipped.write(gzipTrailer);
assertGzipped(gzipped);
}
@Test public void gunzip_withHCRC() throws Exception {
CRC32 hcrc = new CRC32();
hcrc.update(gzipHeaderWithFlags((byte) 0x02));
ByteString gzipHeader = gzipHeaderWithFlags((byte) 0x02);
hcrc.update(gzipHeader.toByteArray());
OkBuffer gzipped = new OkBuffer();
gzipped.write(gzipHeaderWithFlags((byte) 0x02), 0, gzipHeader.length);
gzipped.write(gzipHeader);
gzipped.writeShort(Util.reverseBytesShort((short) hcrc.getValue())); // little endian
gzipped.write(deflated, 0, deflated.length);
gzipped.write(gzipTrailer, 0, gzipTrailer.length);
gzipped.write(deflated);
gzipped.write(gzipTrailer);
assertGzipped(gzipped);
}
@Test public void gunzip_withExtra() throws Exception {
OkBuffer gzipped = new OkBuffer();
gzipped.write(gzipHeaderWithFlags((byte) 0x04), 0, gzipHeader.length);
gzipped.write(gzipHeaderWithFlags((byte) 0x04));
gzipped.writeShort(Util.reverseBytesShort((short) 7)); // little endian extra length
gzipped.write("blubber".getBytes(UTF_8), 0, 7);
gzipped.write(deflated, 0, deflated.length);
gzipped.write(gzipTrailer, 0, gzipTrailer.length);
gzipped.write(deflated);
gzipped.write(gzipTrailer);
assertGzipped(gzipped);
}
@Test public void gunzip_withName() throws Exception {
OkBuffer gzipped = new OkBuffer();
gzipped.write(gzipHeaderWithFlags((byte) 0x08), 0, gzipHeader.length);
gzipped.write(gzipHeaderWithFlags((byte) 0x08));
gzipped.write("foo.txt".getBytes(UTF_8), 0, 7);
gzipped.writeByte(0); // zero-terminated
gzipped.write(deflated, 0, deflated.length);
gzipped.write(gzipTrailer, 0, gzipTrailer.length);
gzipped.write(deflated);
gzipped.write(gzipTrailer);
assertGzipped(gzipped);
}
@Test public void gunzip_withComment() throws Exception {
OkBuffer gzipped = new OkBuffer();
gzipped.write(gzipHeaderWithFlags((byte) 0x10), 0, gzipHeader.length);
gzipped.write(gzipHeaderWithFlags((byte) 0x10));
gzipped.write("rubbish".getBytes(UTF_8), 0, 7);
gzipped.writeByte(0); // zero-terminated
gzipped.write(deflated, 0, deflated.length);
gzipped.write(gzipTrailer, 0, gzipTrailer.length);
gzipped.write(deflated);
gzipped.write(gzipTrailer);
assertGzipped(gzipped);
}
@@ -84,15 +84,15 @@ public class GzipSourceTest {
*/
@Test public void gunzip_withAll() throws Exception {
OkBuffer gzipped = new OkBuffer();
gzipped.write(gzipHeaderWithFlags((byte) 0x1c), 0, gzipHeader.length);
gzipped.write(gzipHeaderWithFlags((byte) 0x1c));
gzipped.writeShort(Util.reverseBytesShort((short) 7)); // little endian extra length
gzipped.write("blubber".getBytes(UTF_8), 0, 7);
gzipped.write("foo.txt".getBytes(UTF_8), 0, 7);
gzipped.writeByte(0); // zero-terminated
gzipped.write("rubbish".getBytes(UTF_8), 0, 7);
gzipped.writeByte(0); // zero-terminated
gzipped.write(deflated, 0, deflated.length);
gzipped.write(gzipTrailer, 0, gzipTrailer.length);
gzipped.write(deflated);
gzipped.write(gzipTrailer);
assertGzipped(gzipped);
}
@@ -108,10 +108,10 @@ public class GzipSourceTest {
*/
@Test public void gunzipWhenHeaderCRCIncorrect() throws Exception {
OkBuffer gzipped = new OkBuffer();
gzipped.write(gzipHeaderWithFlags((byte) 0x02), 0, gzipHeader.length);
gzipped.write(gzipHeaderWithFlags((byte) 0x02));
gzipped.writeShort((short) 0); // wrong HCRC!
gzipped.write(deflated, 0, deflated.length);
gzipped.write(gzipTrailer, 0, gzipTrailer.length);
gzipped.write(deflated);
gzipped.write(gzipTrailer);
try {
gunzip(gzipped);
@@ -123,10 +123,10 @@ public class GzipSourceTest {
@Test public void gunzipWhenCRCIncorrect() throws Exception {
OkBuffer gzipped = new OkBuffer();
gzipped.write(gzipHeader, 0, gzipHeader.length);
gzipped.write(deflated, 0, deflated.length);
gzipped.write(gzipHeader);
gzipped.write(deflated);
gzipped.writeInt(Util.reverseBytesInt(0x1234567)); // wrong CRC
gzipped.write(gzipTrailer, 3, 4);
gzipped.write(gzipTrailer.toByteArray(), 3, 4);
try {
gunzip(gzipped);
@@ -138,9 +138,9 @@ public class GzipSourceTest {
@Test public void gunzipWhenLengthIncorrect() throws Exception {
OkBuffer gzipped = new OkBuffer();
gzipped.write(gzipHeader, 0, gzipHeader.length);
gzipped.write(deflated, 0, deflated.length);
gzipped.write(gzipTrailer, 0, 4);
gzipped.write(gzipHeader);
gzipped.write(deflated);
gzipped.write(gzipTrailer.toByteArray(), 0, 4);
gzipped.writeInt(Util.reverseBytesInt(0x123456)); // wrong length
try {
@@ -152,17 +152,11 @@ public class GzipSourceTest {
}
@Test public void gunzipExhaustsSource() throws Exception {
byte[] abcGzipped = {
(byte) 0x1f, (byte) 0x8b, (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x4b, (byte) 0x4c, (byte) 0x4a, (byte) 0x06,
(byte) 0x00, (byte) 0xc2, (byte) 0x41, (byte) 0x24, (byte) 0x35, (byte) 0x03, (byte) 0x00,
(byte) 0x00, (byte) 0x00
};
OkBuffer gzippedSource = new OkBuffer();
gzippedSource.write(abcGzipped, 0, abcGzipped.length);
OkBuffer gzippedSource = new OkBuffer()
.write(ByteString.decodeHex("1f8b08000000000000004b4c4a0600c241243503000000")); // 'abc'
ExhaustableSource exhaustableSource = new ExhaustableSource(gzippedSource);
BufferedSource gunzippedSource = OkBuffers.buffer(new GzipSource(exhaustableSource));
BufferedSource gunzippedSource = Okio.buffer(new GzipSource(exhaustableSource));
assertEquals('a', gunzippedSource.readByte());
assertEquals('b', gunzippedSource.readByte());
@@ -173,17 +167,11 @@ public class GzipSourceTest {
}
@Test public void gunzipThrowsIfSourceIsNotExhausted() throws Exception {
byte[] abcGzipped = {
(byte) 0x1f, (byte) 0x8b, (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x4b, (byte) 0x4c, (byte) 0x4a, (byte) 0x06,
(byte) 0x00, (byte) 0xc2, (byte) 0x41, (byte) 0x24, (byte) 0x35, (byte) 0x03, (byte) 0x00,
(byte) 0x00, (byte) 0x00
};
OkBuffer gzippedSource = new OkBuffer();
gzippedSource.write(abcGzipped, 0, abcGzipped.length);
OkBuffer gzippedSource = new OkBuffer()
.write(ByteString.decodeHex("1f8b08000000000000004b4c4a0600c241243503000000")); // 'abc'
gzippedSource.writeByte('d'); // This byte shouldn't be here!
BufferedSource gunzippedSource = OkBuffers.buffer(new GzipSource(gzippedSource));
BufferedSource gunzippedSource = Okio.buffer(new GzipSource(gzippedSource));
assertEquals('a', gunzippedSource.readByte());
assertEquals('b', gunzippedSource.readByte());
@@ -195,29 +183,22 @@ public class GzipSourceTest {
}
}
private byte[] gzipHeaderWithFlags(byte flags) {
byte[] result = Arrays.copyOf(gzipHeader, gzipHeader.length);
private ByteString gzipHeaderWithFlags(byte flags) {
byte[] result = gzipHeader.toByteArray();
result[3] = flags;
return result;
return ByteString.of(result);
}
private final byte[] gzipHeader = new byte[] {
(byte) 0x1f, (byte) 0x8b, (byte) 0x08, 0, 0, 0, 0, 0, 0, 0
};
private final ByteString gzipHeader = ByteString.decodeHex("1f8b0800000000000000");
// deflated "It's a UNIX system! I know this!"
private final byte[] deflated = new byte[] {
(byte) 0xf3, (byte) 0x2c, (byte) 0x51, (byte) 0x2f, (byte) 0x56, (byte) 0x48, (byte) 0x54,
(byte) 0x08, (byte) 0xf5, (byte) 0xf3, (byte) 0x8c, (byte) 0x50, (byte) 0x28, (byte) 0xae,
(byte) 0x2c, (byte) 0x2e, (byte) 0x49, (byte) 0xcd, (byte) 0x55, (byte) 0x54, (byte) 0xf0,
(byte) 0x54, (byte) 0xc8, (byte) 0xce, (byte) 0xcb, (byte) 0x2f, (byte) 0x57, (byte) 0x28,
(byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x56, (byte) 0x04, (byte) 0x00
};
// Deflated "It's a UNIX system! I know this!"
private final ByteString deflated = ByteString.decodeHex(
"f32c512f56485408f5f38c5028ae2c2e49cd5554f054c8cecb2f5728c9c82c560400");
private final byte[] gzipTrailer = new byte[] {
(byte) 0x8d, (byte) 0x8f, (byte) 0xad, (byte) 0x37, // checksum of deflated
0x20, 0, 0, 0, // 32 in little endian
};
private final ByteString gzipTrailer = ByteString.decodeHex(""
+ "8d8fad37" // Checksum of deflated.
+ "20000000" // 32 in little endian.
);
private OkBuffer gunzip(OkBuffer gzipped) throws IOException {
OkBuffer result = new OkBuffer();

View File

@@ -85,7 +85,7 @@ public final class InflaterSourceTest {
/** Use DeflaterOutputStream to deflate source. */
private OkBuffer deflate(ByteString source) throws IOException {
OkBuffer result = new OkBuffer();
Sink sink = OkBuffers.sink(new DeflaterOutputStream(result.outputStream()));
Sink sink = Okio.sink(new DeflaterOutputStream(result.outputStream()));
sink.write(new OkBuffer().write(source), source.size());
sink.close();
return result;

View File

@@ -15,14 +15,10 @@
*/
package okio;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import static okio.Util.UTF_8;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -75,10 +71,27 @@ public final class OkBufferTest {
assertEquals(repeat('a', Segment.SIZE), buffer.readUtf8(Segment.SIZE));
}
@Test public void bufferToString() throws Exception {
@Test public void toStringOnEmptyBuffer() throws Exception {
OkBuffer buffer = new OkBuffer();
buffer.writeUtf8("\u0000\u0001\u0002\u007f");
assertEquals("0001027f", buffer.toString());
assertEquals("OkBuffer[size=0]", buffer.toString());
}
@Test public void toStringOnSmallBufferIncludesContents() throws Exception {
OkBuffer buffer = new OkBuffer();
buffer.write(ByteString.decodeHex("a1b2c3d4e5f61a2b3c4d5e6f10203040"));
assertEquals("OkBuffer[size=16 data=a1b2c3d4e5f61a2b3c4d5e6f10203040]", buffer.toString());
}
@Test public void toStringIncludesMd5() throws Exception {
OkBuffer buffer = new OkBuffer();
buffer.write(ByteString.encodeUtf8("12345678901234567"));
assertEquals("OkBuffer[size=17 md5=2c9728a2138b2f25e9f89f99bdccf8db]", buffer.toString());
}
@Test public void toStringOnMultipleSegmentBuffer() throws Exception {
OkBuffer buffer = new OkBuffer();
buffer.writeUtf8(repeat('a', 6144));
assertEquals("OkBuffer[size=6144 md5=d890021f28522533c1cc1b9b1f83ce73]", buffer.toString());
}
@Test public void multipleSegmentBuffers() throws Exception {
@@ -325,58 +338,11 @@ public final class OkBufferTest {
assertEquals(halfSegment * 4 - 1, buffer.indexOf((byte) 'd', halfSegment * 4 - 1));
}
@Test public void sinkFromOutputStream() throws Exception {
OkBuffer data = new OkBuffer();
data.writeUtf8("a");
data.writeUtf8(repeat('b', 9998));
data.writeUtf8("c");
ByteArrayOutputStream out = new ByteArrayOutputStream();
Sink sink = OkBuffers.sink(out);
sink.write(data, 3);
assertEquals("abb", out.toString("UTF-8"));
sink.write(data, data.byteCount());
assertEquals("a" + repeat('b', 9998) + "c", out.toString("UTF-8"));
}
@Test public void sourceFromInputStream() throws Exception {
InputStream in = new ByteArrayInputStream(
("a" + repeat('b', Segment.SIZE * 2) + "c").getBytes(UTF_8));
// Source: ab...bc
Source source = OkBuffers.source(in);
OkBuffer sink = new OkBuffer();
// Source: b...bc. Sink: abb.
assertEquals(3, source.read(sink, 3));
assertEquals("abb", sink.readUtf8(3));
// Source: b...bc. Sink: b...b.
assertEquals(Segment.SIZE, source.read(sink, 20000));
assertEquals(repeat('b', Segment.SIZE), sink.readUtf8((int) sink.byteCount()));
// Source: b...bc. Sink: b...bc.
assertEquals(Segment.SIZE - 1, source.read(sink, 20000));
assertEquals(repeat('b', Segment.SIZE - 2) + "c", sink.readUtf8((int) sink.byteCount()));
// Source and sink are empty.
assertEquals(-1, source.read(sink, 1));
}
@Test public void sourceFromInputStreamBounds() throws Exception {
Source source = OkBuffers.source(new ByteArrayInputStream(new byte[100]));
try {
source.read(new OkBuffer(), -1);
fail();
} catch (IllegalArgumentException expected) {
}
}
@Test public void writeBytes() throws Exception {
OkBuffer data = new OkBuffer();
data.writeByte(0xab);
data.writeByte(0xcd);
assertEquals("abcd", data.toString());
assertEquals("OkBuffer[size=2 data=abcd]", data.toString());
}
@Test public void writeLastByteInSegment() throws Exception {
@@ -386,21 +352,21 @@ public final class OkBufferTest {
data.writeByte(0x21);
assertEquals(asList(Segment.SIZE, 1), data.segmentSizes());
assertEquals(repeat('a', Segment.SIZE - 1), data.readUtf8(Segment.SIZE - 1));
assertEquals("2021", data.toString());
assertEquals("OkBuffer[size=2 data=2021]", data.toString());
}
@Test public void writeShort() throws Exception {
OkBuffer data = new OkBuffer();
data.writeShort(0xabcd);
data.writeShort(0x4321);
assertEquals("abcd4321", data.toString());
assertEquals("OkBuffer[size=4 data=abcd4321]", data.toString());
}
@Test public void writeInt() throws Exception {
OkBuffer data = new OkBuffer();
data.writeInt(0xabcdef01);
data.writeInt(0x87654321);
assertEquals("abcdef0187654321", data.toString());
assertEquals("OkBuffer[size=8 data=abcdef0187654321]", data.toString());
}
@Test public void writeLastIntegerInSegment() throws Exception {
@@ -410,7 +376,7 @@ public final class OkBufferTest {
data.writeInt(0x87654321);
assertEquals(asList(Segment.SIZE, 4), data.segmentSizes());
assertEquals(repeat('a', Segment.SIZE - 4), data.readUtf8(Segment.SIZE - 4));
assertEquals("abcdef0187654321", data.toString());
assertEquals("OkBuffer[size=8 data=abcdef0187654321]", data.toString());
}
@Test public void writeIntegerDoesntQuiteFitInSegment() throws Exception {
@@ -420,7 +386,7 @@ public final class OkBufferTest {
data.writeInt(0x87654321);
assertEquals(asList(Segment.SIZE - 3, 8), data.segmentSizes());
assertEquals(repeat('a', Segment.SIZE - 3), data.readUtf8(Segment.SIZE - 3));
assertEquals("abcdef0187654321", data.toString());
assertEquals("OkBuffer[size=8 data=abcdef0187654321]", data.toString());
}
@Test public void readByte() throws Exception {

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2014 Square, Inc.
*
* 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 okio;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Arrays;
import org.junit.Test;
import static okio.Util.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public final class OkioTest {
@Test public void sinkFromOutputStream() throws Exception {
OkBuffer data = new OkBuffer();
data.writeUtf8("a");
data.writeUtf8(repeat('b', 9998));
data.writeUtf8("c");
ByteArrayOutputStream out = new ByteArrayOutputStream();
Sink sink = Okio.sink(out);
sink.write(data, 3);
assertEquals("abb", out.toString("UTF-8"));
sink.write(data, data.byteCount());
assertEquals("a" + repeat('b', 9998) + "c", out.toString("UTF-8"));
}
@Test public void sourceFromInputStream() throws Exception {
InputStream in = new ByteArrayInputStream(
("a" + repeat('b', Segment.SIZE * 2) + "c").getBytes(UTF_8));
// Source: ab...bc
Source source = Okio.source(in);
OkBuffer sink = new OkBuffer();
// Source: b...bc. Sink: abb.
assertEquals(3, source.read(sink, 3));
assertEquals("abb", sink.readUtf8(3));
// Source: b...bc. Sink: b...b.
assertEquals(Segment.SIZE, source.read(sink, 20000));
assertEquals(repeat('b', Segment.SIZE), sink.readUtf8((int) sink.byteCount()));
// Source: b...bc. Sink: b...bc.
assertEquals(Segment.SIZE - 1, source.read(sink, 20000));
assertEquals(repeat('b', Segment.SIZE - 2) + "c", sink.readUtf8((int) sink.byteCount()));
// Source and sink are empty.
assertEquals(-1, source.read(sink, 1));
}
@Test public void sourceFromInputStreamBounds() throws Exception {
Source source = Okio.source(new ByteArrayInputStream(new byte[100]));
try {
source.read(new OkBuffer(), -1);
fail();
} catch (IllegalArgumentException expected) {
}
}
private String repeat(char c, int count) {
char[] array = new char[count];
Arrays.fill(array, c);
return new String(array);
}
}