diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java index 1b6568e7f1180..6dbf32593a8da 100644 --- a/core/java/android/net/http/Request.java +++ b/core/java/android/net/http/Request.java @@ -82,6 +82,9 @@ class Request { /* Used to synchronize waitUntilComplete() requests */ private final Object mClientResource = new Object(); + /** True if loading should be paused **/ + private boolean mLoadingPaused = false; + /** * Processor used to set content-length and transfer-encoding * headers. @@ -132,6 +135,18 @@ class Request { addHeaders(headers); } + /** + * @param pause True if the load should be paused. + */ + synchronized void setLoadingPaused(boolean pause) { + mLoadingPaused = pause; + + // Wake up the paused thread if we're unpausing the load. + if (!mLoadingPaused) { + notify(); + } + } + /** * @param connection Request served by this connection */ @@ -271,7 +286,24 @@ class Request { int len = 0; int lowWater = buf.length / 2; while (len != -1) { + synchronized(this) { + while (mLoadingPaused) { + // Put this (network loading) thread to sleep if WebCore + // has asked us to. This can happen with plugins for + // example, if we are streaming data but the plugin has + // filled its internal buffers. + try { + wait(); + } catch (InterruptedException e) { + HttpLog.e("Interrupted exception whilst " + + "network thread paused at WebCore's request." + + " " + e.getMessage()); + } + } + } + len = nis.read(buf, count, buf.length - count); + if (len != -1) { count += len; } @@ -316,10 +348,16 @@ class Request { * * Called by RequestHandle from non-network thread */ - void cancel() { + synchronized void cancel() { if (HttpLog.LOGV) { HttpLog.v("Request.cancel(): " + getUri()); } + + // Ensure that the network thread is not blocked by a hanging request from WebCore to + // pause the load. + mLoadingPaused = false; + notify(); + mCancelled = true; if (mConnection != null) { mConnection.cancel(); diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java index 77cd544550231..1a3a28994734e 100644 --- a/core/java/android/net/http/RequestHandle.java +++ b/core/java/android/net/http/RequestHandle.java @@ -100,6 +100,16 @@ public class RequestHandle { } } + /** + * Pauses the loading of this request. For example, called from the WebCore thread + * when the plugin can take no more data. + */ + public void pauseRequest(boolean pause) { + if (mRequest != null) { + mRequest.setLoadingPaused(pause); + } + } + /** * Handles SSL error(s) on the way down from the user (the user * has already provided their feedback). diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java index dc7723ffd3192..2c247577d8f69 100644 --- a/core/java/android/webkit/LoadListener.java +++ b/core/java/android/webkit/LoadListener.java @@ -1197,6 +1197,16 @@ class LoadListener extends Handler implements EventHandler { } } + /** + * Pause the load. For example, if a plugin is unable to accept more data, + * we pause reading from the request. Called directly from the WebCore thread. + */ + void pauseLoad(boolean pause) { + if (mRequestHandle != null) { + mRequestHandle.pauseRequest(pause); + } + } + /** * Cancel a request. * FIXME: This will only work if the request has yet to be handled. This