diff --git a/okhttp/src/main/java/com/squareup/okhttp/HttpResponseCache.java b/okhttp/src/main/java/com/squareup/okhttp/HttpResponseCache.java index a18f42097..a6d380abf 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/HttpResponseCache.java +++ b/okhttp/src/main/java/com/squareup/okhttp/HttpResponseCache.java @@ -490,7 +490,7 @@ public final class HttpResponseCache extends ResponseCache { if (isHttps()) { String blank = reader.readLine(); - if (!blank.isEmpty()) { + if (blank.length() > 0) { throw new IOException("expected \"\" but was \"" + blank + "\""); } cipherSuite = reader.readLine(); @@ -575,7 +575,7 @@ public final class HttpResponseCache extends ResponseCache { } return result; } catch (CertificateException e) { - throw new IOException(e); + throw new IOException(e.getMessage()); } } @@ -592,7 +592,7 @@ public final class HttpResponseCache extends ResponseCache { writer.write(line + '\n'); } } catch (CertificateEncodingException e) { - throw new IOException(e); + throw new IOException(e.getMessage()); } } diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/StrictLineReader.java b/okhttp/src/main/java/com/squareup/okhttp/internal/StrictLineReader.java index 93f17540d..3ddc693c4 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/StrictLineReader.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/StrictLineReader.java @@ -21,26 +21,23 @@ import java.io.Closeable; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; -import static com.squareup.okhttp.internal.Util.ISO_8859_1; -import static com.squareup.okhttp.internal.Util.US_ASCII; -import static com.squareup.okhttp.internal.Util.UTF_8; - /** * Buffers input from an {@link InputStream} for reading lines. * - * This class is used for buffered reading of lines. For purposes of this class, a line ends with + *
This class is used for buffered reading of lines. For purposes of this class, a line ends with * "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated line at * end of input is invalid and will be ignored, the caller may use {@code hasUnterminatedLine()} * to detect it after catching the {@code EOFException}. * - * This class is intended for reading input that strictly consists of lines, such as line-based - * cache entries or cache journal. Unlike the {@link BufferedReader} which in conjunction with - * {@link InputStreamReader} provides similar functionality, this class uses different + *
This class is intended for reading input that strictly consists of lines, such as line-based + * cache entries or cache journal. Unlike the {@link java.io.BufferedReader} which in conjunction + * with {@link java.io.InputStreamReader} provides similar functionality, this class uses different * end-of-input reporting and a more restrictive definition of a line. * - * This class supports only charsets that encode '\r' and '\n' as a single byte with value 13 + *
This class supports only charsets that encode '\r' and '\n' as a single byte with value 13 * and 10, respectively, and the representation of no other character contains these values. * We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1. * The default charset is US_ASCII. @@ -52,42 +49,22 @@ public class StrictLineReader implements Closeable { private final InputStream in; private final Charset charset; - // Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end - // and the data in the range [pos, end) is buffered for reading. At end of input, if there is - // an unterminated line, we set end == -1, otherwise end == pos. If the underlying - // {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1. + /* + * Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end + * and the data in the range [pos, end) is buffered for reading. At end of input, if there is + * an unterminated line, we set end == -1, otherwise end == pos. If the underlying + * {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1. + */ private byte[] buf; private int pos; private int end; - /** - * Constructs a new {@code StrictLineReader} with the default capacity and charset. - * - * @param in the {@code InputStream} to read data from. - * @throws NullPointerException if {@code in} is null. - */ - public StrictLineReader(InputStream in) { - this(in, 8192); - } - - /** - * Constructs a new {@code LineReader} with the specified capacity and the default charset. - * - * @param in the {@code InputStream} to read data from. - * @param capacity the capacity of the buffer. - * @throws NullPointerException if {@code in} is null. - * @throws IllegalArgumentException for negative or zero {@code capacity}. - */ - public StrictLineReader(InputStream in, int capacity) { - this(in, capacity, US_ASCII); - } - /** * Constructs a new {@code LineReader} with the specified charset and the default capacity. * * @param in the {@code InputStream} to read data from. - * @param charset the charset used to decode data. - * Only US-ASCII, UTF-8 and ISO-8859-1 is supported. + * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are + * supported. * @throws NullPointerException if {@code in} or {@code charset} is null. * @throws IllegalArgumentException if the specified charset is not supported. */ @@ -100,11 +77,11 @@ public class StrictLineReader implements Closeable { * * @param in the {@code InputStream} to read data from. * @param capacity the capacity of the buffer. - * @param charset the charset used to decode data. - * Only US-ASCII, UTF-8 and ISO-8859-1 is supported. + * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are + * supported. * @throws NullPointerException if {@code in} or {@code charset} is null. * @throws IllegalArgumentException if {@code capacity} is negative or zero - * or the specified charset is not supported. + * or the specified charset is not supported. */ public StrictLineReader(InputStream in, int capacity, Charset charset) { if (in == null || charset == null) { @@ -113,7 +90,7 @@ public class StrictLineReader implements Closeable { if (capacity < 0) { throw new IllegalArgumentException("capacity <= 0"); } - if (!(charset.equals(US_ASCII) || charset.equals(UTF_8) || charset.equals(ISO_8859_1))) { + if (!(charset.equals(Util.US_ASCII))) { throw new IllegalArgumentException("Unsupported encoding"); } @@ -128,7 +105,6 @@ public class StrictLineReader implements Closeable { * * @throws IOException for errors when closing the underlying {@code InputStream}. */ - @Override public void close() throws IOException { synchronized (in) { if (buf != null) { @@ -162,7 +138,7 @@ public class StrictLineReader implements Closeable { for (int i = pos; i != end; ++i) { if (buf[i] == LF) { int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i; - String res = new String(buf, pos, lineEnd - pos, charset); + String res = new String(buf, pos, lineEnd - pos, charset.name()); pos = i + 1; return res; } @@ -173,7 +149,11 @@ public class StrictLineReader implements Closeable { @Override public String toString() { int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count; - return new String(buf, 0, length, charset); + try { + return new String(buf, 0, length, charset.name()); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); // Since we control the charset this will never happen. + } } }; @@ -215,9 +195,6 @@ public class StrictLineReader implements Closeable { /** * Reads new input data into the buffer. Call only with pos == end or end == -1, * depending on the desired outcome if the function throws. - * - * @throws IOException for underlying {@code InputStream} errors. - * @throws EOFException for the end of source stream. */ private void fillBuf() throws IOException { int result = in.read(buf, 0, buf.length); diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java b/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java index d58b5ded6..5218655e7 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java @@ -153,7 +153,7 @@ public class HttpEngine { try { uri = Platform.get().toUriLenient(policy.getURL()); } catch (URISyntaxException e) { - throw new IOException(e); + throw new IOException(e.getMessage()); } this.requestHeaders = new RequestHeaders(uri, new RawHeaders(requestHeaders)); diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/http/ResponseHeaders.java b/okhttp/src/main/java/com/squareup/okhttp/internal/http/ResponseHeaders.java index e7453bd9b..2ab564dcf 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/http/ResponseHeaders.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/http/ResponseHeaders.java @@ -410,7 +410,8 @@ public final class ResponseHeaders { if (ageMillis + minFreshMillis >= freshMillis) { headers.add("Warning", "110 HttpURLConnection \"Response is stale\""); } - if (ageMillis > TimeUnit.HOURS.toMillis(24) && isFreshnessLifetimeHeuristic()) { + long oneDayMillis = 24 * 60 * 60 * 1000L; + if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) { headers.add("Warning", "113 HttpURLConnection \"Heuristic expiration\""); } return ResponseSource.CACHE; diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/spdy/SpdyReader.java b/okhttp/src/main/java/com/squareup/okhttp/internal/spdy/SpdyReader.java index 7a7b1987b..7d3f2bd56 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/spdy/SpdyReader.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/spdy/SpdyReader.java @@ -21,6 +21,7 @@ import java.io.Closeable; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.net.ProtocolException; import java.util.ArrayList; import java.util.List; @@ -31,39 +32,46 @@ import java.util.zip.InflaterInputStream; /** Read spdy/3 frames. */ final class SpdyReader implements Closeable { - static final byte[] DICTIONARY = ("\u0000\u0000\u0000\u0007options\u0000\u0000\u0000\u0004hea" - + "d\u0000\u0000\u0000\u0004post\u0000\u0000\u0000\u0003put\u0000\u0000\u0000\u0006dele" - + "te\u0000\u0000\u0000\u0005trace\u0000\u0000\u0000\u0006accept\u0000\u0000\u0000" - + "\u000Eaccept-charset\u0000\u0000\u0000\u000Faccept-encoding\u0000\u0000\u0000\u000Fa" - + "ccept-language\u0000\u0000\u0000\raccept-ranges\u0000\u0000\u0000\u0003age\u0000" - + "\u0000\u0000\u0005allow\u0000\u0000\u0000\rauthorization\u0000\u0000\u0000\rcache-co" - + "ntrol\u0000\u0000\u0000\nconnection\u0000\u0000\u0000\fcontent-base\u0000\u0000" - + "\u0000\u0010content-encoding\u0000\u0000\u0000\u0010content-language\u0000\u0000" - + "\u0000\u000Econtent-length\u0000\u0000\u0000\u0010content-location\u0000\u0000\u0000" - + "\u000Bcontent-md5\u0000\u0000\u0000\rcontent-range\u0000\u0000\u0000\fcontent-type" - + "\u0000\u0000\u0000\u0004date\u0000\u0000\u0000\u0004etag\u0000\u0000\u0000\u0006expe" - + "ct\u0000\u0000\u0000\u0007expires\u0000\u0000\u0000\u0004from\u0000\u0000\u0000" - + "\u0004host\u0000\u0000\u0000\bif-match\u0000\u0000\u0000\u0011if-modified-since" - + "\u0000\u0000\u0000\rif-none-match\u0000\u0000\u0000\bif-range\u0000\u0000\u0000" - + "\u0013if-unmodified-since\u0000\u0000\u0000\rlast-modified\u0000\u0000\u0000\blocati" - + "on\u0000\u0000\u0000\fmax-forwards\u0000\u0000\u0000\u0006pragma\u0000\u0000\u0000" - + "\u0012proxy-authenticate\u0000\u0000\u0000\u0013proxy-authorization\u0000\u0000" - + "\u0000\u0005range\u0000\u0000\u0000\u0007referer\u0000\u0000\u0000\u000Bretry-after" - + "\u0000\u0000\u0000\u0006server\u0000\u0000\u0000\u0002te\u0000\u0000\u0000\u0007trai" - + "ler\u0000\u0000\u0000\u0011transfer-encoding\u0000\u0000\u0000\u0007upgrade\u0000" - + "\u0000\u0000\nuser-agent\u0000\u0000\u0000\u0004vary\u0000\u0000\u0000\u0003via" - + "\u0000\u0000\u0000\u0007warning\u0000\u0000\u0000\u0010www-authenticate\u0000\u0000" - + "\u0000\u0006method\u0000\u0000\u0000\u0003get\u0000\u0000\u0000\u0006status\u0000" - + "\u0000\u0000\u0006200 OK\u0000\u0000\u0000\u0007version\u0000\u0000\u0000\bHTTP/1.1" - + "\u0000\u0000\u0000\u0003url\u0000\u0000\u0000\u0006public\u0000\u0000\u0000\nset-coo" - + "kie\u0000\u0000\u0000\nkeep-alive\u0000\u0000\u0000\u0006origin100101201202205206300" - + "302303304305306307402405406407408409410411412413414415416417502504505203 Non-Authori" - + "tative Information204 No Content301 Moved Permanently400 Bad Request401 Unauthorized" - + "403 Forbidden404 Not Found500 Internal Server Error501 Not Implemented503 Service Un" - + "availableJan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec 00:00:00 Mon, Tue, Wed, Th" - + "u, Fri, Sat, Sun, GMTchunked,text/html,image/png,image/jpg,image/gif,application/xml" - + ",application/xhtml+xml,text/plain,text/javascript,publicprivatemax-age=gzip,deflate," - + "sdchcharset=utf-8charset=iso-8859-1,utf-,*,enq=0.").getBytes(Util.UTF_8); + static final byte[] DICTIONARY; + static { + try { + DICTIONARY = ("\u0000\u0000\u0000\u0007options\u0000\u0000\u0000\u0004hea" + + "d\u0000\u0000\u0000\u0004post\u0000\u0000\u0000\u0003put\u0000\u0000\u0000\u0006dele" + + "te\u0000\u0000\u0000\u0005trace\u0000\u0000\u0000\u0006accept\u0000\u0000\u0000" + + "\u000Eaccept-charset\u0000\u0000\u0000\u000Faccept-encoding\u0000\u0000\u0000\u000Fa" + + "ccept-language\u0000\u0000\u0000\raccept-ranges\u0000\u0000\u0000\u0003age\u0000" + + "\u0000\u0000\u0005allow\u0000\u0000\u0000\rauthorization\u0000\u0000\u0000\rcache-co" + + "ntrol\u0000\u0000\u0000\nconnection\u0000\u0000\u0000\fcontent-base\u0000\u0000" + + "\u0000\u0010content-encoding\u0000\u0000\u0000\u0010content-language\u0000\u0000" + + "\u0000\u000Econtent-length\u0000\u0000\u0000\u0010content-location\u0000\u0000\u0000" + + "\u000Bcontent-md5\u0000\u0000\u0000\rcontent-range\u0000\u0000\u0000\fcontent-type" + + "\u0000\u0000\u0000\u0004date\u0000\u0000\u0000\u0004etag\u0000\u0000\u0000\u0006expe" + + "ct\u0000\u0000\u0000\u0007expires\u0000\u0000\u0000\u0004from\u0000\u0000\u0000" + + "\u0004host\u0000\u0000\u0000\bif-match\u0000\u0000\u0000\u0011if-modified-since" + + "\u0000\u0000\u0000\rif-none-match\u0000\u0000\u0000\bif-range\u0000\u0000\u0000" + + "\u0013if-unmodified-since\u0000\u0000\u0000\rlast-modified\u0000\u0000\u0000\blocati" + + "on\u0000\u0000\u0000\fmax-forwards\u0000\u0000\u0000\u0006pragma\u0000\u0000\u0000" + + "\u0012proxy-authenticate\u0000\u0000\u0000\u0013proxy-authorization\u0000\u0000" + + "\u0000\u0005range\u0000\u0000\u0000\u0007referer\u0000\u0000\u0000\u000Bretry-after" + + "\u0000\u0000\u0000\u0006server\u0000\u0000\u0000\u0002te\u0000\u0000\u0000\u0007trai" + + "ler\u0000\u0000\u0000\u0011transfer-encoding\u0000\u0000\u0000\u0007upgrade\u0000" + + "\u0000\u0000\nuser-agent\u0000\u0000\u0000\u0004vary\u0000\u0000\u0000\u0003via" + + "\u0000\u0000\u0000\u0007warning\u0000\u0000\u0000\u0010www-authenticate\u0000\u0000" + + "\u0000\u0006method\u0000\u0000\u0000\u0003get\u0000\u0000\u0000\u0006status\u0000" + + "\u0000\u0000\u0006200 OK\u0000\u0000\u0000\u0007version\u0000\u0000\u0000\bHTTP/1.1" + + "\u0000\u0000\u0000\u0003url\u0000\u0000\u0000\u0006public\u0000\u0000\u0000\nset-coo" + + "kie\u0000\u0000\u0000\nkeep-alive\u0000\u0000\u0000\u0006origin100101201202205206300" + + "302303304305306307402405406407408409410411412413414415416417502504505203 Non-Authori" + + "tative Information204 No Content301 Moved Permanently400 Bad Request401 Unauthorized" + + "403 Forbidden404 Not Found500 Internal Server Error501 Not Implemented503 Service Un" + + "availableJan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec 00:00:00 Mon, Tue, Wed, Th" + + "u, Fri, Sat, Sun, GMTchunked,text/html,image/png,image/jpg,image/gif,application/xml" + + ",application/xhtml+xml,text/plain,text/javascript,publicprivatemax-age=gzip,deflate," + + "sdchcharset=utf-8charset=iso-8859-1,utf-,*,enq=0.").getBytes(Util.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(); + } + } private final DataInputStream in; private final DataInputStream nameValueBlockIn; @@ -252,7 +260,7 @@ final class SpdyReader implements Closeable { return entries; } catch (DataFormatException e) { - throw new IOException(e); + throw new IOException(e.getMessage()); } } diff --git a/okhttp/src/test/java/com/squareup/okhttp/internal/http/RawHeadersTest.java b/okhttp/src/test/java/com/squareup/okhttp/internal/http/RawHeadersTest.java index e5629f094..474e5079e 100644 --- a/okhttp/src/test/java/com/squareup/okhttp/internal/http/RawHeadersTest.java +++ b/okhttp/src/test/java/com/squareup/okhttp/internal/http/RawHeadersTest.java @@ -21,7 +21,6 @@ import java.util.List; import org.junit.Test; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; public final class RawHeadersTest { @Test public void parseNameValueBlock() { @@ -80,7 +79,7 @@ public final class RawHeadersTest { final int version = 1; final int code = 503; rawHeaders.setStatusLine("HTTP/1." + version + " " + code + " "); - assertTrue(rawHeaders.getResponseMessage().isEmpty()); + assertEquals("", rawHeaders.getResponseMessage()); assertEquals(version, rawHeaders.getHttpMinorVersion()); assertEquals(code, rawHeaders.getResponseCode()); } @@ -95,7 +94,7 @@ public final class RawHeadersTest { final int version = 1; final int code = 503; rawHeaders.setStatusLine("HTTP/1." + version + " " + code); - assertTrue(rawHeaders.getResponseMessage().isEmpty()); + assertEquals("", rawHeaders.getResponseMessage()); assertEquals(version, rawHeaders.getHttpMinorVersion()); assertEquals(code, rawHeaders.getResponseCode()); } diff --git a/okhttp/src/test/java/com/squareup/okhttp/internal/http/URLConnectionTest.java b/okhttp/src/test/java/com/squareup/okhttp/internal/http/URLConnectionTest.java index 5de0253f0..619e9964c 100644 --- a/okhttp/src/test/java/com/squareup/okhttp/internal/http/URLConnectionTest.java +++ b/okhttp/src/test/java/com/squareup/okhttp/internal/http/URLConnectionTest.java @@ -1777,7 +1777,7 @@ public final class URLConnectionTest { if (method.equals("GET")) { assertEquals("Page 2", response); } else if (method.equals("HEAD")) { - assertTrue(response.isEmpty()); + assertEquals("", response); } else { // Methods other than GET/HEAD shouldn't follow the redirect if (method.equals("POST")) {