0

From the AFNetworking documentation I get the following code while trying to upload a file in a REST server which with other clients work fine but with my implementation it crashes with Internal Server Error.

The code is the following:

- (BOOL)uploadFile:(NSString *)path apiKey:(NSString *)apiKey
{
    NSData *symbolsData = [NSData dataWithContentsOfFile:path];

    if (!symbolsData) {
        NSLog(@"Symbols file at %@ does not exist.", path);
        return NO;
    }

    if ([symbolsData length] > 33554432) {
        NSLog(@"Symbols file at %@ is too large to upload.", path);
        return NO;
    }

    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:[NSString stringWithFormat:@"%@/upload/thefile", BaseURL] parameters:nil constructingBodyWithBlock:
        ^(id<AFMultipartFormData> formData)
            {
            [formData appendPartWithFileData:symbolsData name:@"file" fileName:[path lastPathComponent] mimeType:@"application/zip"];
            }
        error:nil];
    [request setValue:apiKey forHTTPHeaderField:@"X-theapikey"];

    AFURLSessionManager* manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

    NSURLSessionUploadTask* uploadTask = [manager uploadTaskWithStreamedRequest:request progress:nil completionHandler:
        ^(NSURLResponse *response, id responseObject, NSError *error)
            {
            if (!error)
                {
                NSLog(@"Successfully uploade file: %@\r\nwith Response: %@", [path lastPathComponent], (NSString*)responseObject);
                }
            else
                {
                NSLog(@"There was an error while uploading the file: %@", [error description]);
                }
            }];

    [uploadTask resume];

    return YES;
}

The error:

There was an error while uploading file: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0x6000000e8700 {NSUnderlyingError=0x60000005c0e0 "The request timed out.", NSErrorFailingURLStringKey=http://IP_ADDRESS:3000/upload/thefile, NSErrorFailingURLKey=http://IP_ADDRESS:3000/upload/thefile, NSLocalizedDescription=The request timed out.}

After searchnig for this in the internet I've seen a lot of implementations, MIME type changed to application/octet-stream and other things but nothing worked.

Also added the AFNetworkActivityLogger and registered to the NSNotificationCenter to examine the request:

Request: <NSMutableURLRequest: 0x600000014680> { URL: http://IP_ADDRESS:3000/upload/thefile }
2014-05-28 03:03:16.112 MyMacApp[5092:303] POST 'http://IP_ADDRESS:3000/upload/thefile': {
    "Accept-Language" = "en;q=1, ja;q=0.9, fr;q=0.8, de;q=0.7, es;q=0.6, it;q=0.5";
    "Content-Length" = 817739;
    "Content-Type" = "multipart/form-data; boundary=Boundary+E25BB25240379DA8";
    "User-Agent" = "MyMacApp/1.1 (Mac OS X Version 10.9.3 (Build 13D65))";
    "X-thapikey" = 9e301234;
} (null)

I can see the Content-Type looks good and there is a Content-Length.

EDIT: The server exception thrown:

java.lang.NullPointerException
  at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:997)
  at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:901)
  at java.io.InputStream.read(InputStream.java:101)
  at org.apache.commons.fileupload.util.Streams.copy(Streams.java:101)
  at org.apache.commons.fileupload.util.Streams.copy(Streams.java:70)
  at org.apache.commons.fileupload.MultipartStream.readBodyData(MultipartStream.java:589)
  at org.apache.commons.fileupload.MultipartStream.discardBodyData(MultipartStream.java:613)
  at org.apache.commons.fileupload.MultipartStream.skipPreamble(MultipartStream.java:630)
  at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:1018)
  at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:998)
  at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:310)
  at ring.middleware.multipart_params$file_item_seq.invoke(multipart_params.clj:39)
  at ring.middleware.multipart_params$parse_multipart_params.invoke(multipart_params.clj:55)
  at ring.middleware.multipart_params$multipart_params_request.doInvoke(multipart_params.clj:81)
  at clojure.lang.RestFn.invoke(RestFn.java:423)
  at ring.middleware.multipart_params$wrap_multipart_params$fn__853.invoke(multipart_params.clj:107)
  at ring.middleware.flash$wrap_flash$fn__1860.invoke(flash.clj:31)
  at ring.middleware.session$wrap_session$fn__1847.invoke(session.clj:85)
  at ring.middleware.json$wrap_json_body$fn__623.invoke(json.clj:21)
  at ring.middleware.json$wrap_json_response$fn__634.invoke(json.clj:42)
  at clojure.lang.Var.invoke(Var.java:415)
  at org.httpkit.server.HttpHandler.run(RingHandler.java:91)
  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
  at java.util.concurrent.FutureTask.run(FutureTask.java:262)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
  at java.lang.Thread.run(Thread.java:744)

Any ideas how to debug and find out why my request is failing?

The server accepts files and it is tested with other clients, POSTman, Cocoa REST Client.

Thanks.

George Taskos
  • 8,324
  • 18
  • 82
  • 147

1 Answers1

2

Found the answer with dropping AFNetworking and using Apple's NSURLRequest, NSURLConnection classes with some searching in the stackoverflow.

I should mention that this might be a server's lacking to support AFNetworking request or the request can't work with all servers.

Working code for me:

- (NSMutableURLRequest *)buildRequest:(NSData *)paramData fileName:(NSString *)name
    {
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/upload/thefile", BaseURL]]];
    [request setHTTPMethod:@"POST"];

    NSString *boundary = @"0xKhTmLbOuNdArY";
    NSString *endBoundary = [NSString stringWithFormat:@"\r\n--%@--", boundary];

    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request addValue:contentType forHTTPHeaderField: @"Content-Type"];

    NSMutableData *tempPostData = [NSMutableData data]; 
    [tempPostData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    // Sample file to send as data
    [tempPostData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n", name] dataUsingEncoding:NSUTF8StringEncoding]];
    [tempPostData appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [tempPostData appendData:paramData];
    [tempPostData appendData:[endBoundary dataUsingEncoding:NSUTF8StringEncoding]];
    [request setHTTPBody:tempPostData];

    return request;
    }

- (BOOL) uploadSymbols:(NSString*)path apiKey:(NSString*)apiKey
    {
    NSData *symbolsData = [NSData dataWithContentsOfFile:path];

    if (!symbolsData) {
        NSLog(@"Symbols file at %@ does not exist.", path);
        return NO;
    }

    if ([symbolsData length] > 33554432) {
        NSLog(@"Symbols file at %@ is too large to upload.", path);
        return NO;
    }

    NSMutableURLRequest* request = [self buildRequest:symbolsData fileName:[path lastPathComponent]];
    [request setValue:apiKey forHTTPHeaderField:@"X-theapikey"];
    [NSURLConnection sendAsynchronousRequest:request queue:self.queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
       NSLog(@"End.");
    }];
    return true;
    }
George Taskos
  • 8,324
  • 18
  • 82
  • 147