javagoogle-app-engineblobstore

What is the Correct Approach for Uploading Files to Google App Engine Blobstore Without a Browser?


I'm working on a file upload feature in a Java web application running on Google App Engine (GAE). The application uses the Blobstore API for handling file uploads. However, when trying to upload a file, I'm encountering a NullPointerException (NPE) that I'm unable to debug due to the lack of source code for the com.google.appengine.api.blobstore.dev.UploadBlobServlet class in the 'appengine-api-stubs' version 1.9.88.

Error Message:

java.lang.NullPointerException
    at com.google.appengine.api.blobstore.dev.UploadBlobServlet.handleUpload(UploadBlobServlet.java:432)

The NPE points to line 432 in UploadBlobServlet, since I don't have access to the exact source code, I'm deducing this based on the overall structure of the servlet.

Relevant Code Snippets:

This line 432 from https://github.com/GoogleCloudPlatform/appengine-java-standard/blob/8380dd6b475a49b45112e6c4a20acbb922c28c5e/api_dev/src/main/java/com/google/appengine/api/blobstore/dev/UploadBlobServlet.java#L432 suggest this code block:

Upload Servlet Method Snippet:

public final class UploadBlobServlet extends HttpServlet {
    @Override
    public Enumeration<String> getParameterNames() {
        List<String> allNames = new ArrayList<>();
        Enumeration<String> names = super.getParameterNames();
        while (names.hasMoreElements()) {
            allNames.add(names.nextElement());
        }
        // Additional code for handling other parameters
        return Collections.enumeration(allNames);
    }
}

Although this seems counter-intuitive since the method that is throwing should be handleUpload

File Upload Client Code:

public class FileUploader {
    public String getUploadUrl(String callbackPath) throws URISyntaxException, IOException {
        // Setup Remote API
        BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
        String uploadUrl = blobstoreService.createUploadUrl(callbackPath);
        return uploadUrl;
    }

    public String uploadFile(String url, String partName, String filename, String mimeType, byte[] contents) throws IOException {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost post = new HttpPost(url);
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            ByteArrayBody contentBody = new ByteArrayBody(contents, ContentType.create(mimeType), filename);
            builder.addPart(partName, contentBody);
            post.setEntity(builder.build());
            HttpResponse response = httpClient.execute(post);
            return EntityUtils.toString(response.getEntity());
        }
    }
}

Test Method:

@Test
public void shouldBeAbleToUpload) throws Exception {
    FileUploader fileUploader = new FileUploader();
    String uploadUrl = fileUploader.getUploadUrl("path/to/some/blob");
    InputStream sample = getClass().getResourceAsStream("/100mb.bin");
    byte[] fileContent = readFileToByteArray(sample);
    fileUploader.uploadFile(uploadUrl, "file", "sample.html", "application/octet-stream", fileContent);
}

Main Issue: The main issue is the NPE during the file upload process. I suspect the issue might be related to how parameters are handled or possibly an incorrect setup in my upload logic. However, without access to the source code for UploadBlobServlet, I'm at a loss for how to proceed with debugging.

Questions:

  1. Has anyone encountered a similar issue with file uploads to GAE Blobstore and can provide insight into what might be going wrong?
  2. Are there known issues with the UploadBlobServlet handling multipart form data that could lead to an NPE?
  3. Any suggestions on how to debug or workaround this problem, especially considering the lack of source code for the servlet?

I've confirmed that the upload URL generated is correct and accessible, and the application is running on the local development server provided by GAE.

Any help or guidance would be greatly appreciated. Thank you!


Solution

  • The NPE error is thrown by the UploadBlobServlet if the callback URL doesn't have a forward slash "/". To avoid this error, ensure that the callback URL has a forward slash.

    This will throw:

    String uploadUrl = fileUploader.getUploadUrl("callback");
    

    And this will not:

    String uploadUrl = fileUploader.getUploadUrl("/callback");