Search code examples
androidiosweb-servicesmultipartform-dataloopj

Webservice not receiving multipart PUT from android


I am trying to upload a PDF file to a web service through PUT. I achieve this on iOS through a multipart form request.

However when I do the same from Android, the service returns 200 right away, and never actually gets the entire PUT and I cannot figure out why. I have tried constructing this request multiple different ways, all with the same result.

I am currently using the loopj AsyncHTTPClient library to make the request, here is my code:

    MultipartEntityBuilder builder = MultipartEntityBuilder.create();
    builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

    ByteArrayBody body = new ByteArrayBody(bytes, ContentType.create("application/pdf"), "file.pdf");

    builder.addPart("",body);
    HttpEntity form = builder.build();

    AsyncHttpClient client = new AsyncHttpClient();
    client.setBasicAuth(authUser(), authPass());

    client.put(context, url, form, "application/pdf", new AsyncHttpResponseHandler() {
        @Override
        public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {

            Log.d(TAG,"SUCCESS: " + statusCode + " response: " + responseBody.length);
        }

        @Override
        public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
            Log.e(TAG,"FAIL: " + statusCode + " response: " + responseBody + " ERROR: " + error.getMessage());
        }
    });

For reference, here is the code I use on iOS to make the same request - with success. I am using AFNetworking on that end.

    NSString *authStr = [NSString stringWithFormat:@"%@:%@", [self authUser], [self authPass]];
    NSString *authenticationValue = [[authStr dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];

    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"PUT" URLString:url parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        [formData appendPartWithFileData:data
                                    name:@""
                                fileName:@""
                                mimeType:mimeType];
    } error:nil];

    [request setValue:[NSString stringWithFormat:@"Basic %@", authenticationValue] forHTTPHeaderField:@"Authorization"];


    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];

    NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {

        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;

        if(progress.cancelled) {
            completion(nil, (int)httpResponse.statusCode, [NSError errorWithDomain:@"Network.uploadFile" code:500 userInfo:@{NSLocalizedDescriptionKey:@"User Cancelled"}]);
        } else {
            if (error) {
                completion(nil, (int)httpResponse.statusCode, error);
            } else {
                NSDictionary *response = responseObject;
                completion(response, (int)httpResponse.statusCode, nil);
            }
        }
    }];



    _currentUploadTask = uploadTask;
    [uploadTask resume];

Any thoughts are appreciated. Or perhaps point me in a direction for which I could debug this better? Thanks.


Solution

  • I solved this by adding a boundary to the multipart entity and changing the content type of the request to

    multipart/form-data; boundary=
    

    Here is the updated working code

        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
    
        String boundary = "-------------" + System.currentTimeMillis();
        builder.setBoundary(boundary);
    
        ByteArrayBody body = new ByteArrayBody(bytes, ContentType.create("application/pdf"), "file.pdf");
    
        builder.addPart("",body);
        HttpEntity form = builder.build();
    
        AsyncHttpClient client = new AsyncHttpClient();
        client.setBasicAuth(authUser(), authPass());
    
        String type = "multipart/form-data; boundary="+boundary;
    
        client.put(context, url, form, type, new AsyncHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
    
                Log.d(TAG,"SUCCESS: " + statusCode + " response: " + responseBody.length + " headers: " + headers.toString());
            }
    
            @Override
            public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
                Log.e(TAG,"FAIL: " + statusCode + " response: " + responseBody + " ERROR: " + error.getMessage());
            }
        });