Search code examples
iosafnetworking-2file-transferbackgroundinggcdwebserver

GCDWebServer handlers for background file transfer (Not GCDWebUploader)


Has anybody already tried to implement an handler for GET requests (the same question for POST method) without using the included (and cool) GCDWebUploader?

I need the server to respond to a GET request http://local/download/filename.ext uploading the file to the client.

I am conforming the request to the code "BackgroundSessionManager" (available here: AFNetworking 2.0 and background transfers) and it get sent and triggered no worries.

The log I'm getting server side reads so:

[DEBUG] Did start background task
[DEBUG] Connection received 248 bytes on socket 14
[DEBUG] Connection on socket 14 preflighting request "GET /download/file.ext with 248 bytes body
[DEBUG] Connection on socket 14 processing request "GET /download/file.ext" with 248 bytes body
[EXCEPTION] *** +[NSJSONSerialization dataWithJSONObject:options:error:]: value parameter is nil
[DEBUG] Did close connection on socket 14

I cannot work out how to set up the handler in order not to care about non-existent query to parse from JSON.

[webServer addHandlerForMethod:@"GET" path:@"/download" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
        __strong AppDelegate* strongSelf = weakSelf;
        NSLog(@"request for download is %@", request);

        return [strongSelf downloadFile:request];
    }];

Solution

  • I had this code removed in order to make it work:

    /*
     // Add a handler to respond to GET requests
    [webServer addDefaultHandlerForMethod:@"GET"
                                 requestClass:[GCDWebServerRequest class]
                            asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
    
                                __strong AppDelegate* strongSelf = weakSelf;
    .....
    */
    
    [webServer addHandlerForMethod:@"GET" path:@"/download" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
        __strong AppDelegate* strongSelf = weakSelf;
        NSLog(@"request for download is %@", request);
    
        return [strongSelf downloadFile:request];
    }];
    

    Commented out the default handler that was taking over and expecting a JSON packet anyhow.

    UPDATE

    To achieve background file transfer with GCDWebServer and NSURLSessions (even with AFNetworking) best way to me was to instantiate a GET handler with MatchBlock as follows:

    [webServer addHandlerWithMatchBlock:^GCDWebServerRequest *(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) {
    
            if (![requestMethod isEqualToString:@"GET"]) {
                return nil;
            }
            if (![urlPath hasPrefix:@"/download"]) {
                return nil;
            }
            return [[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery];
    
        } processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
    
            GCDWebServerResponse* response = nil;
    
            NSString* filePath = [[weakSelf applicationDocumentsDirectory] stringByAppendingPathComponent:[[request.path stringByRemovingPercentEncoding]];
            NSString* fileType = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:NULL] fileType];
            if (fileType) {
                if ([fileType isEqualToString:NSFileTypeRegular]) {
                        // always allow ranges in our requests
                        response = [GCDWebServerFileResponse responseWithFile:filePath byteRange:request.byteRange];
                        [response setValue:@"bytes" forAdditionalHeader:@"Accept-Ranges"];
                }
            }
            if (response) {
                response.cacheControlMaxAge = 360;
            } else {
                response = [GCDWebServerResponse responseWithStatusCode:kGCDWebServerHTTPStatusCode_NotFound];
            }
            return response;
    
        }];