Android 当文件大小大于可恢复上载区块大小时,文档列表API文件上载失败

Android 当文件大小大于可恢复上载区块大小时,文档列表API文件上载失败,android,google-docs-api,google-drive-api,Android,Google Docs Api,Google Drive Api,我正在尝试使用文档列表API让Android应用程序与Google Docs/Drive交互: 我在使用GData可恢复上载协议上载文件时遇到了一些问题,即: 我使用的是512KB的块大小。小于区块大小的文件上载成功,但大于区块大小的文件将在第一个区块完成之前失败。即使我将块大小增加到1MiB或2MiB,这也是正确的。768KiB文件将在块大小为512KiB时失败,但在块大小为1MiB时成功 大于数据块大小的文件确实通过了第一步,即将XML发布到“可恢复创建媒体”链接。然后,我看到用于发送区块

我正在尝试使用文档列表API让Android应用程序与Google Docs/Drive交互:

我在使用GData可恢复上载协议上载文件时遇到了一些问题,即:

我使用的是512KB的块大小。小于区块大小的文件上载成功,但大于区块大小的文件将在第一个区块完成之前失败。即使我将块大小增加到1MiB或2MiB,这也是正确的。768KiB文件将在块大小为512KiB时失败,但在块大小为1MiB时成功

大于数据块大小的文件确实通过了第一步,即将XML发布到“可恢复创建媒体”链接。然后,我看到用于发送区块的HttpContent实现的writeTo()方法中抛出了一个SSLException。此异常发生在第一个块的中间,例如:

javax.net.ssl.SSLException: Write error: ssl=0x2a6318: I/O error during system call, Broken pipe
    at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_write(Native Method)
    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:713)
    at libcore.net.http.FixedLengthOutputStream.write(FixedLengthOutputStream.java:41)
    at com.google.api.client.http.AbstractInputStreamContent.writeTo(AbstractInputStreamContent.java:89)
请注意,要查看上述内容,我必须在writeTo()方法中捕获IOExceptions(在记录它们之后重新调用它们)。否则,由于内容被突然切断,我只会看到一个通用的“400错误请求”响应

我试过几种不同的测试设备,例如Galaxy Nexus(VZW/CDMA,4.0.2,股票),Droid4(Moto 2.3.6,股票)DroidX(股票)

上载第一个区块的请求上的标题:

Accept-Encoding: gzip
Authorization: GoogleLogin auth=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Content-Length: 524288
Content-Range: 0-524287/1635085
Content-Type: image/png
GData-Version: 3.0
User-Agent: XXXXXXXXXXXXXX
谢谢你的建议

更新:添加代码段,这是放置下一个块的位

private boolean putNext() 
throws CancelException, DirectoryException {
    try {
        ByteArrayContent content = new ByteArrayContent(mediaType, buffer, 0, bufferLength);

        HttpRequest request = conn.getHttpRequestFactory().buildPutRequest(new GenericUrl(nextLocation), content);

        HttpHeaders requestHeaders = request.getHeaders();
        requestHeaders.setContentLength(String.valueOf(bufferLength));
        requestHeaders.setContentType(mediaType);

        if (sent != 0 || bufferLength != size) {
            // Only set content range when file will span multiple chunks.
            requestHeaders.setContentRange(sent + "-" + (sent + bufferLength - 1) + "/" + size);
        }

        HttpResponse response = request.execute();

        sent += bufferLength;
        bufferLength = 0;

        HttpHeaders responseHeaders = response.getHeaders();

        int statusCode = response.getStatusCode();
        if (statusCode == GoogleDriveConnection.RESPONSE_308_RESUME_INCOMPLETE) {
            nextLocation = responseHeaders.getLocation();
            return false;
        } else if (statusCode >= 200 && statusCode < 400) {
            Document responseDom = DomUtil.load(response.getContent());
            return true;
        } else {
            Log.w(LOG_TAG, "Google Drive upload error: Invalid response code to upload request: " + statusCode);
            throw DirectoryException.networkErrorHost(null, catalog.getHostName());
        }
    } catch (IOException ex) {
        Log.w(LOG_TAG, "Google Drive write error.", ex);
        throw DirectoryException.networkErrorHost(ex, catalog.getHostName());
    } catch (SAXException ex) {
        throw DirectoryException.networkErrorHost(ex, catalog.getHostName());
    }
}
private boolean putNext()
抛出CancelException,DirectoryException{
试一试{
ByteArrayContent内容=新的ByteArrayContent(mediaType,buffer,0,bufferLength);
HttpRequest请求=conn.getHttpRequestFactory().buildPutRequest(新的GenericUrl(nextLocation),content);
HttpHeaders requestHeaders=request.getHeaders();
requestHeaders.setContentLength(String.valueOf(bufferLength));
requestHeaders.setContentType(mediaType);
如果(已发送!=0 | |缓冲长度!=大小){
//仅当文件将跨越多个块时设置内容范围。
setContentRange(发送+“-”+(发送+缓冲长度-1)+“/”+大小);
}
HttpResponse response=request.execute();
发送+=缓冲区长度;
缓冲长度=0;
HttpHeaders-responseHeaders=response.getHeaders();
int statusCode=response.getStatusCode();
如果(statusCode==GoogleDriveConnection.RESPONSE\u 308\u RESUME\u Complete){
nextLocation=responseHeaders.getLocation();
返回false;
}否则如果(状态代码>=200&&statusCode<400){
documentresponsedom=DomUtil.load(response.getContent());
返回true;
}否则{
Log.w(Log_标签,“谷歌硬盘上传错误:上传请求的响应代码无效:“+statusCode”);
抛出DirectoryException.networkErrorHost(null,catalog.getHostName());
}
}捕获(IOEX异常){
Log.w(Log_标签,“谷歌硬盘写入错误”,ex);
抛出DirectoryException.networkErrorHost(例如catalog.getHostName());
}捕获(SAXEx异常){
抛出DirectoryException.networkErrorHost(例如catalog.getHostName());
}
}
另一个可能很重要的注意事项是:SSLException失败是由Content Range标头的存在触发的。如果我省略它,第一个大于块大小的文件块将毫无例外地成功上载。服务器返回一个201创建的文件,该文件被创建为一个被截断的512KB大小

再次感谢

更新2

我现在有了一个纯Java应用程序来演示这个问题。这是一个包含库的Eclipse项目,但在其他地方使用起来应该很简单。

需要一个身份验证令牌来测试它。它需要三个命令行参数才能运行:

[文件名][内容/类型][AuthToken]

(我目前正在从real app的调试输出中剪切/粘贴AuthToken)

以下是此应用程序的修剪输出:

TOKEN=********
FILE=/tmp/1199Panigale.jpg
Headers: POST Request
-- User-Agent: DriveUpload
-- GData-Version: 3.0
-- Authorization: GoogleLogin auth=********
-- X-Upload-Content-Type: image/png
-- X-Upload-Content-Length: 1635085
[POST Request] --------------------------------------------------------
<entry xmlns="http://www.w3.org/2005/Atom">
<title>1199Panigale.jpg</title>
</entry>
Executing post request: https://docs.google.com/feeds/upload/create-session/default/private/full/folder%3Aroot/contents?convert=false
Post complete, response=200
Headers: POST Response
-- Server: HTTP Upload Server Built on Apr 23 2012 11:11:29 (1335204689)
-- Location: https://docs.google.com/feeds/upload/create-session/default/private/full/folder%3Aroot/contents?convert=false&upload_id=********2
-- Date: Sat, 28 Apr 2012 04:51:47 GMT
-- Pragma: no-cache
-- Expires: Fri, 01 Jan 1990 00:00:00 GMT
-- Cache-Control: no-cache, no-store, must-revalidate
-- Content-Length: 0
-- Content-Type: text/html
Preparing PUT request #0
Headers: Put Request
-- User-Agent: DriveUpload
-- GData-Version: 3.0
-- Authorization: GoogleLogin auth=********
-- Content-Type: image/png
-- Content-Range: 0-524287/1635085
[writeTo]
[getCotent]
Read: 4096, total: 4096
Read: 4096, total: 8192
Read: 4096, total: 12288
Read: 4096, total: 16384

[---skip a few---]

Read: 4096, total: 270336
Read: 4096, total: 274432
Read: 4096, total: 278528
Read: 4096, total: 282624
Read: 4096, total: 286720
Read: 4096, total: 290816
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: I/O exception (java.net.SocketException) caught when processing request: Broken pipe
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: Retrying request
[writeTo]
[getCotent]
Read: 4096, total: 4096
Read: 4096, total: 8192
Read: 4096, total: 12288
Read: 4096, total: 16384
Read: 4096, total: 20480

[---skip a few---]

Read: 4096, total: 274432
Read: 4096, total: 278528
Read: 4096, total: 282624
Read: 4096, total: 286720
Read: 4096, total: 290816
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: I/O exception (java.net.SocketException) caught when processing request: Broken pipe
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: Retrying request
[writeTo]
[getCotent]
Read: 4096, total: 4096
Read: 4096, total: 8192
Read: 4096, total: 12288
Read: 4096, total: 16384
Read: 4096, total: 20480

[---skip a few---]

Read: 4096, total: 278528
Read: 4096, total: 282624
Read: 4096, total: 286720
Read: 4096, total: 290816
Read: 4096, total: 294912
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: I/O exception (java.net.SocketException) caught when processing request: Broken pipe
Apr 27, 2012 9:49:02 PM org.apache.http.impl.client.DefaultRequestDirector tryExecute
INFO: Retrying request
[writeTo]
[getCotent]
Read: 4096, total: 4096
Read: 4096, total: 8192
Read: 4096, total: 12288
Read: 4096, total: 16384
Read: 4096, total: 20480

[---skip a few---]

Read: 4096, total: 278528
Read: 4096, total: 282624
Read: 4096, total: 286720
java.net.SocketException: Broken pipe
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
    at sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:314)
    at sun.security.ssl.OutputRecord.write(OutputRecord.java:303)
    at sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:768)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:756)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:108)
    at org.apache.http.impl.io.AbstractSessionOutputBuffer.write(AbstractSessionOutputBuffer.java:153)
    at org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:114)
    at driveupload.UploadStream$1.writeTo(UploadStream.java:149)
    at org.apache.http.entity.HttpEntityWrapper.writeTo(HttpEntityWrapper.java:96)
    at org.apache.http.impl.client.EntityEnclosingRequestWrapper$EntityWrapper.writeTo(EntityEnclosingRequestWrapper.java:108)
    at org.apache.http.impl.entity.EntitySerializer.serialize(EntitySerializer.java:120)
    at org.apache.http.impl.AbstractHttpClientConnection.sendRequestEntity(AbstractHttpClientConnection.java:264)
    at org.apache.http.impl.conn.AbstractClientConnAdapter.sendRequestEntity(AbstractClientConnAdapter.java:224)
    at org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:255)
    at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123)
    at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:647)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:464)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
    at driveupload.DriveUpload.executeRequest(DriveUpload.java:71)
    at driveupload.UploadStream.putNext(UploadStream.java:191)
    at driveupload.UploadStream.write(UploadStream.java:225)
    at java.io.OutputStream.write(OutputStream.java:116)
    at driveupload.DriveUpload.test(DriveUpload.java:127)
    at driveupload.DriveUpload.main(DriveUpload.java:44)
令牌=********
文件=/tmp/1199Panigale.jpg
标题:POST请求
--用户代理:DriveUpload
--GData版本:3.0
--授权:谷歌登录认证=********
--X-Upload-Content-Type:image/png
--X-Upload-Content-Length:1635085
[请求后]--------------------------------------------------------
1199Panigale.jpg
执行post请求:https://docs.google.com/feeds/upload/create-session/default/private/full/folder%3Aroot/contents?convert=false
完成后,响应=200
标题:回复后
--服务器:HTTP上传服务器构建于2012年4月23日11:11:29(1335204689)
--地点:https://docs.google.com/feeds/upload/create-session/default/private/full/folder%3Aroot/contents?convert=false&upload_id=********2
--日期:2012年4月28日星期六04:51:47 GMT
--Pragma:没有缓存
--过期时间:1990年1月1日星期五00:00:00 GMT
--缓存控制:没有缓存,没有存储,必须重新验证
--内容长度:0
--内容类型:text/html
正在准备PUT请求#0
标题:放置请求
--用户代理:DriveUpload
--GData版本:3.0
--授权:谷歌登录认证=********
--内容类型:图像/png
--内容范围:0-524287/1635085
[书面]
[GetCoent]
读:4096,总计:4096
读:4096,总计:8192
读:4096,总计:12288
读:4096,总计:16384
[---跳过几个---]
读:4096,总计:270336
阅读:4096,总计:274432
读:4096,总计:278528
阅读:4096,总计:282624
读:4096,总计:286720
读:4096,总计:290816
2012年4月27日晚上9:49:02 org.apache.http.impl.client.DefaultRequestDirector tryExecute
信息:处理请求时捕获I/O异常(java.net.SocketException):管道断裂
2012年4月27日晚上9:49:02 org.apache.http.impl.client.DefaultRequestDirector tryExecute
信息:重试请求
[书面]
[GetCoent]
读:4096,总计:4096
读:4096,总计:8192
读:4096,总计:12288
读:4096,总计:16384
读:4096,总计:20480
[---跳过几个