/** * Returns the trailers. It is only safe to call this once the source stream has been completely * exhausted. */ public synchronized Headers trailers() throws IOException { if (errorCode != null) { throw new StreamResetException(errorCode); } if (!source.finished || !source.receiveBuffer.exhausted() || !source.readBuffer.exhausted()) { throw new IllegalStateException("too early; can't read the trailers yet"); } return source.trailers != null ? source.trailers : Util.EMPTY_HEADERS; }
/** * Returns the trailers. It is only safe to call this once the source stream has been completely * exhausted. */ public synchronized Headers trailers() throws IOException { if (errorCode != null) { throw new StreamResetException(errorCode); } if (!source.finished || !source.receiveBuffer.exhausted() || !source.readBuffer.exhausted()) { throw new IllegalStateException("too early; can't read the trailers yet"); } return source.trailers != null ? source.trailers : Util.EMPTY_HEADERS; }
private static int skipAll(Buffer buffer, byte b) { int count = 0; while (!buffer.exhausted() && buffer.getByte(0) == b) { count++; buffer.readByte(); } return count; }
/** * Returns true if the body in question probably contains human readable text. Uses a small sample * of code points to detect unicode control characters commonly used in binary file signatures. */ static boolean isPlaintext(Buffer buffer) { try { Buffer prefix = new Buffer(); long byteCount = buffer.size() < 64 ? buffer.size() : 64; buffer.copyTo(prefix, 0, byteCount); for (int i = 0; i < 16; i++) { if (prefix.exhausted()) { break; } int codePoint = prefix.readUtf8CodePoint(); if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) { return false; } } return true; } catch (EOFException e) { return false; // Truncated UTF-8 sequence. } }
/** Returns true if any commas were skipped. */ private static boolean skipWhitespaceAndCommas(Buffer buffer) { boolean commaFound = false; while (!buffer.exhausted()) { byte b = buffer.getByte(0); if (b == ',') { buffer.readByte(); // Consume ','. commaFound = true; } else if (b == ' ' || b == '\t') { buffer.readByte(); // Consume space or tab. } else { break; } } return commaFound; }
private static int skipAll(Buffer buffer, byte b) { int count = 0; while (!buffer.exhausted() && buffer.getByte(0) == b) { count++; buffer.readByte(); } return count; }
private static void canonicalizeForPath(Buffer out, String input, int pos, int limit, boolean alreadyEncoded) { Buffer utf8Buffer = null; // Lazily allocated. int codePoint; for (int i = pos; i < limit; i += Character.charCount(codePoint)) { codePoint = input.codePointAt(i); if (alreadyEncoded && (codePoint == '\t' || codePoint == '\n' || codePoint == '\f' || codePoint == '\r')) { // Skip this character. } else if (codePoint < 0x20 || codePoint >= 0x7f || PATH_SEGMENT_ALWAYS_ENCODE_SET.indexOf(codePoint) != -1 || (!alreadyEncoded && (codePoint == '/' || codePoint == '%'))) { // Percent encode this character. if (utf8Buffer == null) { utf8Buffer = new Buffer(); } utf8Buffer.writeUtf8CodePoint(codePoint); while (!utf8Buffer.exhausted()) { int b = utf8Buffer.readByte() & 0xff; out.writeByte('%'); out.writeByte(HEX_DIGITS[(b >> 4) & 0xf]); out.writeByte(HEX_DIGITS[b & 0xf]); } } else { // This character doesn't need encoding. Just copy it over. out.writeUtf8CodePoint(codePoint); } } }
while (!encodedCharBuffer.exhausted()) { int b = encodedCharBuffer.readByte() & 0xff; out.writeByte('%');
peek = readToken(header); if (peek == null) { if (!header.exhausted()) return; // Expected a token; got something else. result.add(new Challenge(schemeName, Collections.emptyMap())); return; if (!commaPrefixed && (commaSuffixed || header.exhausted())) { result.add(new Challenge(schemeName, Collections.singletonMap( null, peek + repeat('=', eqCount)))); if (skipWhitespaceAndCommas(header)) return; // Unexpected ','. String parameterValue = !header.exhausted() && header.getByte(0) == '"' ? readQuotedString(header) : readToken(header); peek = null; if (replaced != null) return; // Unexpected duplicate parameter. if (!skipWhitespaceAndCommas(header) && !header.exhausted()) return; // Expected ',' or EOF.
/** * Sets the response body to {@code body}, chunked every {@code maxChunkSize} bytes. */ public MockResponse setChunkedBody(Buffer body, int maxChunkSize) { removeHeader("Content-Length"); headers.add(CHUNKED_BODY_HEADER); Buffer bytesOut = new Buffer(); while (!body.exhausted()) { long chunkSize = Math.min(body.size(), maxChunkSize); bytesOut.writeHexadecimalUnsignedLong(chunkSize); bytesOut.writeUtf8("\r\n"); bytesOut.write(body, chunkSize); bytesOut.writeUtf8("\r\n"); } bytesOut.writeUtf8("0\r\n"); // Last chunk. Trailers follow! this.body = bytesOut; return this; }
/** Returns true if any commas were skipped. */ private static boolean skipWhitespaceAndCommas(Buffer buffer) { boolean commaFound = false; while (!buffer.exhausted()) { byte b = buffer.getByte(0); if (b == ',') { buffer.readByte(); // Consume ','. commaFound = true; } else if (b == ' ' || b == '\t') { buffer.readByte(); // Consume space or tab. } else { break; } } return commaFound; }
private void assertCodePointDecoded(String hex, int... codePoints) throws Exception { Buffer buffer = new Buffer().write(ByteString.decodeHex(hex)); for (int codePoint : codePoints) { assertEquals(codePoint, buffer.readUtf8CodePoint()); } assertTrue(buffer.exhausted()); }
@Test public void readLeadingContinuationByteReturnsReplacementCharacter() throws Exception { Buffer buffer = new Buffer(); buffer.writeByte(0xbf); assertEquals(REPLACEMENT_CODE_POINT, buffer.readUtf8CodePoint()); assertTrue(buffer.exhausted()); }
@Test public void readMissingContinuationBytesThrowsEofException() throws Exception { Buffer buffer = new Buffer(); buffer.writeByte(0xdf); try { buffer.readUtf8CodePoint(); fail(); } catch (EOFException expected) { } assertFalse(buffer.exhausted()); // Prefix byte wasn't consumed. }
@Test public void readCodePointBeyondUnicodeMaximum() throws Exception { // A 4-byte encoding with data above the U+10ffff Unicode maximum. Buffer buffer = new Buffer(); buffer.write(ByteString.decodeHex("f4908080")); assertEquals(REPLACEMENT_CODE_POINT, buffer.readUtf8CodePoint()); assertTrue(buffer.exhausted()); }
@Test public void readOverlongCodePoint() throws Exception { // Use 2 bytes to encode data that only needs 1 byte. Buffer buffer = new Buffer(); buffer.write(ByteString.decodeHex("c080")); assertEquals(REPLACEMENT_CODE_POINT, buffer.readUtf8CodePoint()); assertTrue(buffer.exhausted()); }
@Test public void readSurrogateCodePoint() throws Exception { Buffer buffer = new Buffer(); buffer.write(ByteString.decodeHex("eda080")); assertEquals(REPLACEMENT_CODE_POINT, buffer.readUtf8CodePoint()); assertTrue(buffer.exhausted()); buffer.write(ByteString.decodeHex("edbfbf")); assertEquals(REPLACEMENT_CODE_POINT, buffer.readUtf8CodePoint()); assertTrue(buffer.exhausted()); }
@Test public void readNonContinuationBytesReturnsReplacementCharacter() throws Exception { // Use a non-continuation byte where a continuation byte is expected. Buffer buffer = new Buffer(); buffer.write(ByteString.decodeHex("df20")); assertEquals(REPLACEMENT_CODE_POINT, buffer.readUtf8CodePoint()); assertEquals(0x20, buffer.readUtf8CodePoint()); // Non-continuation character not consumed. assertTrue(buffer.exhausted()); }
@Test public void readTooLargeCodepointReturnsReplacementCharacter() throws Exception { // 5-byte and 6-byte code points are not supported. Buffer buffer = new Buffer(); buffer.write(ByteString.decodeHex("f888808080")); assertEquals(REPLACEMENT_CODE_POINT, buffer.readUtf8CodePoint()); assertEquals(REPLACEMENT_CODE_POINT, buffer.readUtf8CodePoint()); assertEquals(REPLACEMENT_CODE_POINT, buffer.readUtf8CodePoint()); assertEquals(REPLACEMENT_CODE_POINT, buffer.readUtf8CodePoint()); assertEquals(REPLACEMENT_CODE_POINT, buffer.readUtf8CodePoint()); assertTrue(buffer.exhausted()); }