Skip to content

Commit b5e3d41

Browse files
GTMSessionUploadFetcher - Handle empty and non-existing files to upload (issue #140) (#141)
Handle empty files to upload; fail with an error on non-existing file upload
1 parent ada7367 commit b5e3d41

File tree

2 files changed

+105
-4
lines changed

2 files changed

+105
-4
lines changed

Source/GTMSessionUploadFetcher.m

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,11 +1455,13 @@ - (void)chunkFetcher:(GTMSessionFetcher *)chunkFetcher
14551455

14561456
// TODO
14571457
// Maybe here we can check to see if the request had x goog content length set. (the file length one).
1458-
int64_t previousContentLength =
1459-
[[chunkFetcher.request valueForHTTPHeaderField:@"Content-Length"] longLongValue];
1458+
NSString *previousContentLengthValue =
1459+
[chunkFetcher.request valueForHTTPHeaderField:@"Content-Length"];
14601460
// The Content-Length header may not be present if the chunk fetcher was recreated from
14611461
// a background session.
1462-
BOOL hasKnownChunkSize = (previousContentLength > 0);
1462+
BOOL hasKnownChunkSize = (previousContentLengthValue != nil);
1463+
int64_t previousContentLength = [previousContentLengthValue longLongValue];
1464+
14631465
BOOL needsQuery = (!hasKnownChunkSize && !isUploadStatusStopped);
14641466

14651467
if (error || (needsQuery && !isQueryFetch)) {
@@ -1504,7 +1506,9 @@ - (void)chunkFetcher:(GTMSessionFetcher *)chunkFetcher
15041506
chunkFetcher, chunkFetcher.request.allHTTPHeaderFields,
15051507
responseHeaders);
15061508
#endif
1507-
if (isUploadStatusStopped || (_currentOffset > _uploadFileLength && _uploadFileLength > 0)) {
1509+
if (isUploadStatusStopped ||
1510+
_uploadFileLength == 0 ||
1511+
(_currentOffset > _uploadFileLength && _uploadFileLength > 0)) {
15081512
// This was the last chunk.
15091513
if (error == nil && uploadStatus == kStatusCancelled) {
15101514
// Report cancelled status as an error.

Source/UnitTests/GTMSessionFetcherChunkedUploadTest.m

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,103 @@ - (void)testBigFileURLQueryCanceledUploadFetch {
963963
[self removeTemporaryFileURL:bigFileURL];
964964
}
965965

966+
- (void)testEmptyFileURLUploadFetch {
967+
// Like the previous, but we upload in a single chunk, needed for an out-of-process upload.
968+
FetcherNotificationsCounter *fnctr = [[FetcherNotificationsCounter alloc] init];
969+
970+
NSURL *emptyFileURL =
971+
[self fileToUploadURLWithData:[NSData data] baseName:NSStringFromSelector(_cmd)];
972+
973+
NSURLRequest *request = [self validUploadFileRequest];
974+
GTMSessionUploadFetcher *fetcher =
975+
[GTMSessionUploadFetcher uploadFetcherWithRequest:request
976+
uploadMIMEType:@"text/plain"
977+
chunkSize:kGTMSessionUploadFetcherStandardChunkSize
978+
fetcherService:_service];
979+
fetcher.uploadFileURL = emptyFileURL;
980+
fetcher.useBackgroundSession = NO;
981+
fetcher.allowLocalhostRequest = YES;
982+
983+
XCTestExpectation *expectation = [self expectationWithDescription:@"fetched"];
984+
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
985+
// Test that server result is returned (success or failure).
986+
// The current test server don't accept POST requests with empty body.
987+
XCTAssertNil(data);
988+
XCTAssertEqual(error.code, 503);
989+
[expectation fulfill];
990+
}];
991+
992+
[self waitForExpectationsWithTimeout:_timeoutInterval handler:nil];
993+
[self assertCallbacksReleasedForFetcher:fetcher];
994+
995+
// Check that we uploaded the expected chunks.
996+
NSArray *expectedURLStrings = @[ @"/gettysburgaddress.txt.upload" ];
997+
NSArray *expectedCommands = @[ @"finalize" ];
998+
NSArray *expectedOffsets = @[ @0 ];
999+
NSArray *expectedLengths = @[ @0 ];
1000+
XCTAssertEqualObjects(fnctr.uploadChunkRequestPaths, expectedURLStrings);
1001+
XCTAssertEqualObjects(fnctr.uploadChunkCommands, expectedCommands);
1002+
XCTAssertEqualObjects(fnctr.uploadChunkOffsets, expectedOffsets);
1003+
XCTAssertEqualObjects(fnctr.uploadChunkLengths, expectedLengths);
1004+
1005+
XCTAssertEqual(fnctr.fetchStarted, 2);
1006+
XCTAssertEqual(fnctr.fetchStopped, 2);
1007+
XCTAssertEqual(fnctr.uploadChunkFetchStarted, 1);
1008+
XCTAssertEqual(fnctr.uploadChunkFetchStopped, 1);
1009+
XCTAssertEqual(fnctr.retryDelayStarted, 0);
1010+
XCTAssertEqual(fnctr.retryDelayStopped, 0);
1011+
XCTAssertEqual(fnctr.uploadLocationObtained, 1);
1012+
1013+
[self removeTemporaryFileURL:emptyFileURL];
1014+
}
1015+
1016+
- (void)testNonExistingFileURLUploadFetch {
1017+
// Like the previous, but we upload in a single chunk, needed for an out-of-process upload.
1018+
FetcherNotificationsCounter *fnctr = [[FetcherNotificationsCounter alloc] init];
1019+
1020+
NSURL *nonExistingFileURL = [NSURL fileURLWithPath:@"some/file"];
1021+
1022+
NSURLRequest *request = [self validUploadFileRequest];
1023+
GTMSessionUploadFetcher *fetcher =
1024+
[GTMSessionUploadFetcher uploadFetcherWithRequest:request
1025+
uploadMIMEType:@"text/plain"
1026+
chunkSize:kGTMSessionUploadFetcherStandardChunkSize
1027+
fetcherService:_service];
1028+
fetcher.uploadFileURL = nonExistingFileURL;
1029+
fetcher.useBackgroundSession = NO;
1030+
fetcher.allowLocalhostRequest = YES;
1031+
1032+
XCTestExpectation *expectation = [self expectationWithDescription:@"fetched"];
1033+
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
1034+
// The current test server don't accept POST requests with empty body.
1035+
XCTAssertNil(data);
1036+
XCTAssertEqual(error.code, 260);
1037+
[expectation fulfill];
1038+
}];
1039+
1040+
[self waitForExpectationsWithTimeout:_timeoutInterval handler:nil];
1041+
1042+
[self assertCallbacksReleasedForFetcher:fetcher];
1043+
1044+
// Check that we uploaded the expected chunks.
1045+
NSArray *expectedURLStrings = @[];
1046+
NSArray *expectedCommands = @[];
1047+
NSArray *expectedOffsets = @[];
1048+
NSArray *expectedLengths = @[];
1049+
XCTAssertEqualObjects(fnctr.uploadChunkRequestPaths, expectedURLStrings);
1050+
XCTAssertEqualObjects(fnctr.uploadChunkCommands, expectedCommands);
1051+
XCTAssertEqualObjects(fnctr.uploadChunkOffsets, expectedOffsets);
1052+
XCTAssertEqualObjects(fnctr.uploadChunkLengths, expectedLengths);
1053+
1054+
XCTAssertEqual(fnctr.fetchStarted, 1);
1055+
XCTAssertEqual(fnctr.fetchStopped, 1);
1056+
XCTAssertEqual(fnctr.uploadChunkFetchStarted, 0);
1057+
XCTAssertEqual(fnctr.uploadChunkFetchStopped, 0);
1058+
XCTAssertEqual(fnctr.retryDelayStarted, 0);
1059+
XCTAssertEqual(fnctr.retryDelayStopped, 0);
1060+
XCTAssertEqual(fnctr.uploadLocationObtained, 1);
1061+
}
1062+
9661063
- (void)testBigDataChunkedUploadFetch {
9671064
FetcherNotificationsCounter *fnctr = [[FetcherNotificationsCounter alloc] init];
9681065

0 commit comments

Comments
 (0)