mirror of
https://github.com/square/okhttp.git
synced 2026-01-24 04:02:07 +03:00
@@ -18,7 +18,7 @@
|
||||
package com.squareup.okhttp.mockwebserver;
|
||||
|
||||
import com.squareup.okhttp.Protocol;
|
||||
import com.squareup.okhttp.internal.ByteString;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import com.squareup.okhttp.internal.NamedRunnable;
|
||||
import com.squareup.okhttp.internal.Platform;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.ByteString;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.squareup.okhttp.internal;
|
||||
|
||||
import com.squareup.okhttp.Protocol;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.squareup.okhttp.internal;
|
||||
package com.squareup.okhttp.internal.bytes;
|
||||
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -34,7 +35,7 @@ import static com.squareup.okhttp.internal.Util.asciiLowerCase;
|
||||
* process.
|
||||
*/
|
||||
public final class ByteString {
|
||||
private final byte[] data;
|
||||
final byte[] data;
|
||||
private transient int hashCode; // Lazily computed; 0 if unknown.
|
||||
private transient String utf8; // Lazily computed.
|
||||
|
||||
@@ -119,7 +120,7 @@ public final class ByteString {
|
||||
return new ByteString(result);
|
||||
}
|
||||
|
||||
private ByteString(byte[] data) {
|
||||
ByteString(byte[] data) {
|
||||
this.data = data; // Trusted internal constructor doesn't clone data.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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 com.squareup.okhttp.internal.bytes;
|
||||
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A collection of bytes in memory.
|
||||
*
|
||||
* <p><strong>Moving data from one OkBuffer to another is fast.</strong> Instead
|
||||
* of copying bytes from one place in memory to another, this class just changes
|
||||
* ownership of the underlying bytes.
|
||||
*
|
||||
* <p><strong>This buffer grows with your data.</strong> Just like ArrayList,
|
||||
* each OkBuffer starts small. It consumes only the memory it needs to.
|
||||
*
|
||||
* <p><strong>This buffer pools its byte arrays.</strong> When you allocate a
|
||||
* byte array in Java, the runtime must zero-fill the requested array before
|
||||
* returning it to you. Even if you're going to write over that space anyway.
|
||||
* This class avoids zero-fill and GC churn by pooling byte arrays.
|
||||
*/
|
||||
public final class OkBuffer implements Source, Sink {
|
||||
private static final char[] HEX_DIGITS =
|
||||
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
|
||||
private Segment segment;
|
||||
private long byteCount;
|
||||
|
||||
public OkBuffer() {
|
||||
}
|
||||
|
||||
/** Returns the number of bytes currently in this buffer. */
|
||||
public long byteCount() {
|
||||
return byteCount;
|
||||
}
|
||||
|
||||
/** Removes {@code byteCount} bytes from this and returns them as a byte string. */
|
||||
public ByteString readByteString(int byteCount) {
|
||||
return new ByteString(readBytes(byteCount));
|
||||
}
|
||||
|
||||
/** Removes {@code byteCount} bytes from this, decodes them as UTF-8 and returns the string. */
|
||||
public String readUtf8(int byteCount) {
|
||||
return new String(readBytes(byteCount), Util.UTF_8);
|
||||
}
|
||||
|
||||
private byte[] readBytes(int byteCount) {
|
||||
if (byteCount > this.byteCount) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("requested %s > available %s", byteCount, this.byteCount));
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
byte[] result = new byte[byteCount];
|
||||
|
||||
while (offset < byteCount) {
|
||||
int toCopy = Math.min(byteCount - offset, segment.limit - segment.pos);
|
||||
System.arraycopy(segment.data, segment.pos, result, offset, toCopy);
|
||||
|
||||
offset += toCopy;
|
||||
segment.pos += toCopy;
|
||||
|
||||
if (segment.pos == segment.limit) {
|
||||
segment = segment.pop(); // Recycle this empty segment.
|
||||
}
|
||||
}
|
||||
|
||||
this.byteCount -= byteCount;
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Appends {@code byteString} to this. */
|
||||
public void write(ByteString byteString) {
|
||||
write(byteString.data);
|
||||
}
|
||||
|
||||
/** Encodes {@code string} as UTF-8 and appends the bytes to this. */
|
||||
public void writeUtf8(String string) {
|
||||
write(string.getBytes(Util.UTF_8));
|
||||
}
|
||||
|
||||
private void write(byte[] data) {
|
||||
int offset = 0;
|
||||
while (offset < data.length) {
|
||||
if (segment == null) {
|
||||
segment = SegmentPool.INSTANCE.take(); // Acquire a first segment.
|
||||
segment.next = segment.prev = segment;
|
||||
}
|
||||
|
||||
Segment tail = segment.prev;
|
||||
if (tail.limit == Segment.SIZE) {
|
||||
tail = tail.push(); // Acquire a new empty segment.
|
||||
}
|
||||
|
||||
int toCopy = Math.min(data.length - offset, Segment.SIZE - tail.limit);
|
||||
System.arraycopy(data, offset, tail.data, tail.limit, toCopy);
|
||||
|
||||
offset += toCopy;
|
||||
tail.limit += toCopy;
|
||||
}
|
||||
|
||||
this.byteCount += data.length;
|
||||
}
|
||||
|
||||
@Override public void write(OkBuffer source, long byteCount, Timeout timeout) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override public long read(OkBuffer sink, long byteCount, Timeout timeout) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override public long indexOf(byte b, Timeout timeout) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override public void flush(Timeout timeout) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override public void close(Timeout timeout) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
char[] result = new char[(int) (byteCount * 2)];
|
||||
int offset = 0;
|
||||
for (Segment s = segment; offset < byteCount; 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];
|
||||
}
|
||||
offset += s.limit - s.pos;
|
||||
}
|
||||
return new String(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 com.squareup.okhttp.internal.bytes;
|
||||
|
||||
/**
|
||||
* A segment of an OkBuffer.
|
||||
*
|
||||
* <p>Each segment in an OkBuffer is a circularly-linked list node referencing
|
||||
* the following and preceding segments in the buffer.
|
||||
*
|
||||
* <p>Each segment in the pool is a singly-linked list node referencing the rest
|
||||
* of segments in the pool.
|
||||
*/
|
||||
final class Segment {
|
||||
/** The size of all segments in bytes. */
|
||||
// TODO: Using fixed-size segments makes pooling easier. But it harms memory
|
||||
// efficiency and encourages copying. Try variable sized segments?
|
||||
// TODO: Is 2 KiB a good default segment size?
|
||||
static final int SIZE = 2048;
|
||||
|
||||
final byte[] data;
|
||||
int pos;
|
||||
int limit;
|
||||
|
||||
/** Next segment in a linked list. */
|
||||
Segment next;
|
||||
|
||||
/** Previous segment in a linked list. */
|
||||
Segment prev;
|
||||
|
||||
Segment() {
|
||||
data = new byte[SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes this head of a circularly-linked list, recycles it, and returns the
|
||||
* new head of the list. Returns null if the list is now empty.
|
||||
*/
|
||||
public Segment pop() {
|
||||
Segment result = next != this ? next : null;
|
||||
prev.next = next;
|
||||
next.prev = prev;
|
||||
next = null;
|
||||
prev = null;
|
||||
SegmentPool.INSTANCE.recycle(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires a segment and appends it to this tail of a circularly-linked list.
|
||||
* Returns the new tail segment.
|
||||
*/
|
||||
public Segment push() {
|
||||
Segment result = SegmentPool.INSTANCE.take();
|
||||
result.prev = this;
|
||||
result.next = next;
|
||||
next.prev = result;
|
||||
next = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 com.squareup.okhttp.internal.bytes;
|
||||
|
||||
/**
|
||||
* A collection of unused segments, necessary to avoid GC churn and zero-fill.
|
||||
* This pool is a thread-safe static singleton.
|
||||
*/
|
||||
final class SegmentPool {
|
||||
static final SegmentPool INSTANCE = new SegmentPool();
|
||||
|
||||
/** The maximum number of bytes to pool. */
|
||||
// TODO: Is 64 KiB a good maximum size? Do we ever have that many idle segments?
|
||||
static final long MAX_SIZE = 64 * 1024; // 64 KiB.
|
||||
|
||||
/** Singly-linked list of segments. */
|
||||
private Segment next;
|
||||
|
||||
/** Total bytes in this pool. */
|
||||
long byteCount;
|
||||
|
||||
private SegmentPool() {
|
||||
}
|
||||
|
||||
Segment take() {
|
||||
synchronized (this) {
|
||||
if (next != null) {
|
||||
Segment result = next;
|
||||
next = result.next;
|
||||
result.next = null;
|
||||
byteCount -= Segment.SIZE;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return new Segment(); // Pool is empty. Don't zero-fill while holding a lock.
|
||||
}
|
||||
|
||||
void recycle(Segment segment) {
|
||||
if (segment.next != null || segment.prev != null) throw new IllegalArgumentException();
|
||||
synchronized (this) {
|
||||
if (byteCount + Segment.SIZE > MAX_SIZE) return; // Pool is full.
|
||||
byteCount += Segment.SIZE;
|
||||
segment.next = next;
|
||||
segment.pos = segment.limit = 0;
|
||||
next = segment;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 com.squareup.okhttp.internal.bytes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An alternative to OutputStream.
|
||||
*/
|
||||
public interface Sink {
|
||||
/** Removes {@code byteCount} bytes from {@code source} and appends them to this. */
|
||||
void write(OkBuffer source, long byteCount, Timeout timeout) throws IOException;
|
||||
|
||||
/** Pushes all buffered bytes to their final destination. */
|
||||
void flush(Timeout timeout) throws IOException;
|
||||
|
||||
/**
|
||||
* Pushes all buffered bytes to their final destination and releases the
|
||||
* resources held by this sink. It is an error to write a closed sink. It is
|
||||
* safe to close a sink more than once.
|
||||
*/
|
||||
void close(Timeout timeout) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 com.squareup.okhttp.internal.bytes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An alternative to InputStream.
|
||||
*/
|
||||
public interface Source {
|
||||
/**
|
||||
* Removes {@code byteCount} bytes from this and appends them to {@code sink}.
|
||||
* Returns the number of bytes actually written.
|
||||
*/
|
||||
long read(OkBuffer sink, long byteCount, Timeout timeout) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the index of {@code b} in this, or -1 if this source is exhausted
|
||||
* first. This may cause this source to buffer a large number of bytes.
|
||||
*/
|
||||
long indexOf(byte b, Timeout timeout) throws IOException;
|
||||
|
||||
/**
|
||||
* Closes this source and releases the resources held by this source. It is an
|
||||
* error to read a closed source. It is safe to close a source more than once.
|
||||
*/
|
||||
void close(Timeout timeout) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 com.squareup.okhttp.internal.bytes;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* The deadline for a requested operation. If the timeout elapses before the
|
||||
* operation has completed, the operation should be aborted.
|
||||
*/
|
||||
public class Timeout {
|
||||
public static final Timeout NONE = new Timeout() {
|
||||
@Override public Timeout start(long timeout, TimeUnit unit) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override public boolean reached() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private long deadlineNanos;
|
||||
|
||||
public Timeout() {
|
||||
}
|
||||
|
||||
public Timeout start(long timeout, TimeUnit unit) {
|
||||
deadlineNanos = System.nanoTime() + unit.toNanos(timeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean reached() {
|
||||
return System.nanoTime() - deadlineNanos >= 0; // Subtract to avoid overflow!
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.squareup.okhttp.internal.spdy;
|
||||
|
||||
import com.squareup.okhttp.internal.ByteString;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
|
||||
/** HTTP header: the name is an ASCII string, but the value can be UTF-8. */
|
||||
public final class Header {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.squareup.okhttp.internal.spdy;
|
||||
|
||||
import com.squareup.okhttp.internal.BitArray;
|
||||
import com.squareup.okhttp.internal.ByteString;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.squareup.okhttp.internal.spdy;
|
||||
|
||||
import com.squareup.okhttp.internal.ByteString;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import java.io.Closeable;
|
||||
import java.io.DataInputStream;
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
package com.squareup.okhttp.internal.spdy;
|
||||
|
||||
import com.squareup.okhttp.Protocol;
|
||||
import com.squareup.okhttp.internal.ByteString;
|
||||
import com.squareup.okhttp.internal.Platform;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.squareup.okhttp.internal;
|
||||
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 com.squareup.okhttp.internal.bytes;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public final class OkBufferTest {
|
||||
@Test public void readAndWriteUtf8() throws Exception {
|
||||
OkBuffer buffer = new OkBuffer();
|
||||
buffer.writeUtf8("ab");
|
||||
assertEquals(2, buffer.byteCount());
|
||||
buffer.writeUtf8("cdef");
|
||||
assertEquals(6, buffer.byteCount());
|
||||
assertEquals("abcd", buffer.readUtf8(4));
|
||||
assertEquals(2, buffer.byteCount());
|
||||
assertEquals("ef", buffer.readUtf8(2));
|
||||
assertEquals(0, buffer.byteCount());
|
||||
try {
|
||||
buffer.readUtf8(1);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void bufferToString() throws Exception {
|
||||
OkBuffer buffer = new OkBuffer();
|
||||
buffer.writeUtf8("\u0000\u0001\u0002\u007f");
|
||||
assertEquals("0001027f", buffer.toString());
|
||||
}
|
||||
|
||||
@Test public void multipleSegmentBuffers() throws Exception {
|
||||
OkBuffer buffer = new OkBuffer();
|
||||
buffer.writeUtf8(repeat('a', 1000));
|
||||
buffer.writeUtf8(repeat('b', 2500));
|
||||
buffer.writeUtf8(repeat('c', 5000));
|
||||
buffer.writeUtf8(repeat('d', 10000));
|
||||
buffer.writeUtf8(repeat('e', 25000));
|
||||
buffer.writeUtf8(repeat('f', 50000));
|
||||
|
||||
assertEquals(repeat('a', 999), buffer.readUtf8(999)); // a...a
|
||||
assertEquals("a" + repeat('b', 2500) + "c", buffer.readUtf8(2502)); // ab...bc
|
||||
assertEquals(repeat('c', 4998), buffer.readUtf8(4998)); // c...c
|
||||
assertEquals("c" + repeat('d', 10000) + "e", buffer.readUtf8(10002)); // cd...de
|
||||
assertEquals(repeat('e', 24998), buffer.readUtf8(24998)); // e...e
|
||||
assertEquals("e" + repeat('f', 50000), buffer.readUtf8(50001)); // ef...f
|
||||
assertEquals(0, buffer.byteCount());
|
||||
}
|
||||
|
||||
@Test public void fillAndDrainPool() throws Exception {
|
||||
OkBuffer buffer = new OkBuffer();
|
||||
|
||||
// Take 2 * MAX_SIZE segments. This will drain the pool, even if other tests filled it.
|
||||
buffer.write(ByteString.of(new byte[(int) SegmentPool.MAX_SIZE]));
|
||||
buffer.write(ByteString.of(new byte[(int) SegmentPool.MAX_SIZE]));
|
||||
assertEquals(0, SegmentPool.INSTANCE.byteCount);
|
||||
|
||||
// Recycle MAX_SIZE segments. They're all in the pool.
|
||||
buffer.readByteString((int) SegmentPool.MAX_SIZE);
|
||||
assertEquals(SegmentPool.MAX_SIZE, SegmentPool.INSTANCE.byteCount);
|
||||
|
||||
// Recycle MAX_SIZE more segments. The pool is full so they get garbage collected.
|
||||
buffer.readByteString((int) SegmentPool.MAX_SIZE);
|
||||
assertEquals(SegmentPool.MAX_SIZE, SegmentPool.INSTANCE.byteCount);
|
||||
|
||||
// Take MAX_SIZE segments to drain the pool.
|
||||
buffer.write(ByteString.of(new byte[(int) SegmentPool.MAX_SIZE]));
|
||||
assertEquals(0, SegmentPool.INSTANCE.byteCount);
|
||||
|
||||
// Take MAX_SIZE more segments. The pool is drained so these will need to be allocated.
|
||||
buffer.write(ByteString.of(new byte[(int) SegmentPool.MAX_SIZE]));
|
||||
assertEquals(0, SegmentPool.INSTANCE.byteCount);
|
||||
}
|
||||
|
||||
private String repeat(char c, int count) {
|
||||
char[] array = new char[count];
|
||||
Arrays.fill(array, c);
|
||||
return new String(array);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.squareup.okhttp.internal.spdy;
|
||||
|
||||
import com.squareup.okhttp.internal.ByteString;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.ByteString;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import com.squareup.okhttp.internal.Platform;
|
||||
import com.squareup.okhttp.internal.http.HttpAuthenticator;
|
||||
import com.squareup.okhttp.internal.http.HttpEngine;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.ByteString;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import com.squareup.okhttp.internal.http.HttpAuthenticator;
|
||||
import com.squareup.okhttp.internal.http.HttpURLConnectionImpl;
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.squareup.okhttp.Protocol;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.Route;
|
||||
import com.squareup.okhttp.internal.ByteString;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import com.squareup.okhttp.internal.Platform;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.squareup.okhttp.Headers;
|
||||
import com.squareup.okhttp.Protocol;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.internal.ByteString;
|
||||
import com.squareup.okhttp.internal.bytes.ByteString;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import com.squareup.okhttp.internal.spdy.ErrorCode;
|
||||
import com.squareup.okhttp.internal.spdy.Header;
|
||||
|
||||
Reference in New Issue
Block a user