This fixes a break caused by the recent try-harder-on-IP-addresses
change, where if the first connect failed we returned rather than
trying until we reached a connection or an error.
I was trying to reproduce a connectivity problem and
I found other related problems along the way:
- We were unnecessarily creating new HttpConnection instances.
- We were using "" as the file instead of "/" for SPDY.
Previously the returned connections required the caller to
do extra work: setting up tunnels (which could require auth)
and performing an SSL handshake. With this change we make a
complete working connection in HttpConnection.connect().
This will make it easier to fix fallback when a single domain
has multiple IP addresses and some of those addresses are not
reachable.
This will also make it easier to do SPDY through HTTP proxies.
We had a bug where the underlying SSLInputStream always returned
0 for InputStream.available(). This prevented us from ever reading
the "end of stream" chunk, which prevented connection recycling.
http://code.google.com/p/android/issues/detail?id=38817
Also fix a nearby bug where we were fast-forwarding the gzipped
stream when we should have been fast-forwarding the transfer
stream when we were preparing to recycle a connection.
Writing this change has led me to believe that the
concurrency here is just plain awful, and I need to
find a better solution than what I have. In particular,
there are too many threads:
- the internal reader thread
- application reader threads
- application writer threads
And too many locks:
- the SpdyWriter I/O write lock
- the SpdyConnection internal state lock
- each SpdyStream's internal state lock
What's currently very wrong is the internal reader thread
is updating state in the SpdyStream, and reading bytes from
the network into a particular stream. It is an error to hold
the SpdyStream's lock while reading, but we're doing it because
we need to hold the state on the buffer, position and limit.
We need to rethink this!
Chrome doesn't run into this problem because it can 'fire and
forget' events. We can't do that because SPDY writes need to
throw IOExceptions if the writes fail.
Although blocking calls don't fit the SPDY model very well, they
make exception transparency easy. In this case, a NOOP or a PING
will throw if it cannot be sent. This is good.
The current status line parsing is lenient and sloppy; a
holdover from an ancient version of this library. The new
code is strict and provides a helpful message if a bogus
status line is encountered.
To make this possible the RawHeaders class needs a hint
about whether it's looking for a request line (from an
HTTP request) or a status line (from an HTTP response).
The old sloppy code used the same APIs for both.
Setting fields and then calling a method is just not as usable
as calling a method that takes arguments.
Also move Settings into their own class, so we can sling them
around without a bunch of ceremony.
SpdyConnection needs to guard its own state separately from
the SpdyWriter, which permits slow blocking calls. Split these
into multiple independent locks.
Also use independent right-sized thread pools for reading (exactly
one thread all the time) delayed writing (0 or 1 threads) and
callbacks (any number of threads).
Though it isn't particularly useful in practice, it's
going to be extremely handy for testing since it makes
a happens-before relationship very easy to create.
We were only returning 'true' once we were already in a tunnel.
This was bogus. In theory a TLS tunnel sending extra data could
be corrupted due to this bug.
Also migrate one of the TLS tunnel tests to use SslContextBuilder
instead of TestSSLContext.
Original AOSP/libcore commit from Vladimir Marko:
Add StrictLineReader for efficient reading of lines
consistent with Streams.readAsciiLine(). Use this to improve
DiskLruCache.readJournal() and initialization of
HttpResponseCache$Entry from InputStream.
(cherry-pick of e03b551079aae1204e505f1dc24f2b986ef82ec0.)
Bug: 6739304
Change-Id: If3083031f1368a9bbbd405c91553d7a205fd4e39
Original AOSP/libcore commit by Brian Carlstrom:
java.lang.Throwable: Explicit termination method 'end' not called
at dalvik.system.CloseGuard.open(CloseGuard.java:184)
at java.util.zip.Inflater.<init>(Inflater.java:82)
at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:96)
at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:81)
at libcore.net.http.HttpEngine.initContentStream(HttpEngine.java:523)
at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:831)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:274)
at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:486)
at ...
Bug: 6602529
Change-Id: I9b49cbca561f8780d08844e566820087fdffc4d7
Original AOSP/libcore commit from Vladimir Marko:
Avoid writing to HttpResponseCache.CacheRequestImpl.cacheOut
one byte at a time via inefficient FilterOutputStream write.
(cherry-picked from 91cc423115fdfa682d9c4cd025dee06aaa145b3c.)
Bug: 6738383
Change-Id: Ia657d7417cc292746968809f6896a5e790f1394d
Original AOSP/libcore commit from Brian Carlstrom:
This fixes an issue where a bad proxy repsonse that included a body
would turn into an IllegalStateException instead of an IOException.
Bug: 6754912
Change-Id: I204ad975820693d6add2780d7b77360463e33710
This is more lenient than necessary; the HTTP spec says this:
10.4.2 401 Unauthorized
The request requires user authentication. The response MUST include a
WWW-Authenticate header field (section 14.47) containing a challenge
applicable to the requested resource.
Not throwing will still cause the request to fail, since the 401
response code triggers an IOException. But this type of failure is
more recoverable and allows the caller to inspect the headers and
response body.
This makes a bunch of sad changes for compatibility:
- Using String.length() rather than String.isEmpty()
- Using String.getBytes(String) rather than String.getBytes(Charset)
- Using new String(..., String) rather than new String(..., Charset)
- Avoiding TimeUnit.DAYS
I've tested this and the HTTP tests run perfectly fine on Froyo.
The HTTPS tests time out due to a bug in Froyo that prevents
its TLS library from working as a server. I manually verified
that TLS works as a client without problem.
I also tested this on Gingerbread. It passes all tests except
for testConnectViaHttpProxyToHttpsUsingProxySystemProperty, which
fails because of a bug in Gingerbread's java.net.ProxySelector.
This change introduces caching reflective objects for NPN access.
That'll make clients that make multiple SSL connections slightly
more efficient.
Because there are no platform APIs to generate certificates,
this needs a third party library (bouncy castle) to do the
heavy lifting.
Each target platform has its own built-in crypto library:
- The JVM has its own internal crypto library. It uses
key stores like "JCA".
- Android has its own internal crypto library that's
based on bouncy castle. It is repackaged in com.android
and is not used by this code.
With this change, okhttp brings its own copy of bouncy castle
for cert generation. Once the certificate is generated we're
done with bouncy castle, and use the platform libraries for TLS.
This approach allows us to use one codebase on either platform.