Parse the base64 data before creating the data stream.

This will ensure that we do not parse the data in chunks when passing it to the
LoadListener. Decoding in chunks can lead to incomplete sequences which will
lead to a failed decode.

Check for a cancelled LoadListener in StreamLoader and stop the load. This is
just a shortcut for downloaded or failed resources.

Cleanup some of the LoadListener code around resetting a few member variables.
Reset them in the status callback since that indicates a new response from the
server (or StreamLoader).
This commit is contained in:
Patrick Scott
2009-04-29 10:21:57 -04:00
parent 42fba356cf
commit e82dc42052
3 changed files with 26 additions and 37 deletions

View File

@@ -16,12 +16,10 @@
package android.webkit;
import org.apache.http.protocol.HTTP;
import android.net.http.Headers;
import java.io.ByteArrayInputStream;
import org.apache.harmony.luni.util.Base64;
/**
* This class is a concrete implementation of StreamLoader that uses the
* content supplied as a URL as the source for the stream. The mimetype
@@ -30,8 +28,6 @@ import java.io.ByteArrayInputStream;
*/
class DataLoader extends StreamLoader {
private String mContentType; // Content mimetype, if supplied in URL
/**
* Constructor uses the dataURL as the source for an InputStream
* @param dataUrl data: URL string optionally containing a mimetype
@@ -41,16 +37,20 @@ class DataLoader extends StreamLoader {
super(loadListener);
String url = dataUrl.substring("data:".length());
String content;
byte[] data = null;
int commaIndex = url.indexOf(',');
if (commaIndex != -1) {
mContentType = url.substring(0, commaIndex);
content = url.substring(commaIndex + 1);
String contentType = url.substring(0, commaIndex);
data = url.substring(commaIndex + 1).getBytes();
loadListener.parseContentTypeHeader(contentType);
if (loadListener.transferEncoding().equals("base64")) {
data = Base64.decode(data);
}
} else {
content = url;
data = url.getBytes();
}
mDataStream = new ByteArrayInputStream(content.getBytes());
mContentLength = content.length();
mDataStream = new ByteArrayInputStream(data);
mContentLength = data.length;
}
@Override
@@ -60,10 +60,7 @@ class DataLoader extends StreamLoader {
}
@Override
protected void buildHeaders(Headers headers) {
if (mContentType != null) {
headers.setContentType(mContentType);
}
protected void buildHeaders(android.net.http.Headers h) {
}
/**

View File

@@ -43,8 +43,6 @@ import java.util.Vector;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import org.apache.commons.codec.binary.Base64;
class LoadListener extends Handler implements EventHandler {
private static final String LOGTAG = "webkit";
@@ -140,8 +138,6 @@ class LoadListener extends Handler implements EventHandler {
mBrowserFrame = frame;
setUrl(url);
mNativeLoader = nativeLoader;
mMimeType = "";
mEncoding = "";
mSynchronous = synchronous;
if (synchronous) {
mMessageQueue = new Vector<Message>();
@@ -292,8 +288,6 @@ class LoadListener extends Handler implements EventHandler {
private void handleHeaders(Headers headers) {
if (mCancelled) return;
mHeaders = headers;
mMimeType = "";
mEncoding = "";
ArrayList<String> cookies = headers.getSetCookie();
for (int i = 0; i < cookies.size(); ++i) {
@@ -442,6 +436,9 @@ class LoadListener extends Handler implements EventHandler {
status.put("reason", reasonPhrase);
// New status means new data. Clear the old.
mDataBuilder.clear();
mMimeType = "";
mEncoding = "";
mTransferEncoding = "";
sendMessageInternal(obtainMessage(MSG_STATUS, status));
}
@@ -517,19 +514,6 @@ class LoadListener extends Handler implements EventHandler {
Log.v(LOGTAG, "LoadListener.data(): url: " + url());
}
// Decode base64 data
// Note: It's fine that we only decode base64 here and not in the other
// data call because the only caller of the stream version is not
// base64 encoded.
if ("base64".equals(mTransferEncoding)) {
if (length < data.length) {
byte[] trimmedData = new byte[length];
System.arraycopy(data, 0, trimmedData, 0, length);
data = trimmedData;
}
data = Base64.decodeBase64(data);
length = data.length;
}
// Synchronize on mData because commitLoad may write mData to WebCore
// and we don't want to replace mData or mDataLength at the same time
// as a write.
@@ -904,6 +888,10 @@ class LoadListener extends Handler implements EventHandler {
return mMimeType;
}
String transferEncoding() {
return mTransferEncoding;
}
/*
* Return the size of the content being downloaded. This represents the
* full content size, even under the situation where the download has been
@@ -1198,7 +1186,7 @@ class LoadListener extends Handler implements EventHandler {
private static final Pattern CONTENT_TYPE_PATTERN =
Pattern.compile("^((?:[xX]-)?[a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$");
private void parseContentTypeHeader(String contentType) {
/* package */ void parseContentTypeHeader(String contentType) {
if (WebView.LOGV_ENABLED) {
Log.v(LOGTAG, "LoadListener.parseContentTypeHeader: " +
"contentType: " + contentType);

View File

@@ -102,7 +102,7 @@ abstract class StreamLoader extends Handler {
// to pass data to the loader
mData = new byte[8192];
sendHeaders();
while (!sendData());
while (!sendData() && !mHandler.cancelled());
closeStreamAndSendEndData();
mHandler.loadSynchronousMessages();
}
@@ -116,6 +116,10 @@ abstract class StreamLoader extends Handler {
if (WebView.DEBUG && mHandler.isSynchronous()) {
throw new AssertionError();
}
if (mHandler.cancelled()) {
closeStreamAndSendEndData();
return;
}
switch(msg.what) {
case MSG_STATUS:
if (setupStreamAndSendStatus()) {