swagger-api / swagger-api/swagger-codegen

[JAVA] Bug generating request body for array of files upload

Open
#9,195 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Mustache
Stars
17.8k
Forks
6k
PR merge metrics
No merged PRs in 30d

Description

Java code generated for request body for multi-part form data does not put the content of the files in request body, instead it places the file path and name in the request body.

Git clone and build Swagger-codegen version 3.0.5 via instructions on Github README
Swagger yaml openapi-upload-files.yaml
openapi: 3.0.0
info:
  title: OpenApi file upload request body
  version: "1.0.0"
  contact:
    name: Walt Shands
    email: jshands@ucsc.edu
tags:
        - name: upload_test
          description: test multipart upload
paths:
  /runs:
    post:
      summary: Upload an array of files.
      description: >-
        This endpoint uploads an array of files.

      operationId: UploadFiles
      responses:
        '200':
          description: ''
        '400':
          description: The request is malformed.
        '401':
          description: The request is unauthorized.
        '403':
          description: The requester is not authorized to perform this action.
        '500':
          description: An unexpected error occurred.

      tags:
        - UploadFilesService
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file_list:
                  type: array
                  items:
                    type: string
                    format: binary

Build client from OpenApi yaml with Swagger Codegen
java -jar <path>/swagger-codegen-cli.jar generate -l java -i <path>/openapi-upload-files.yaml
Java class used for generation of POST request
package io.arrayoffiles;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import io.swagger.client.ApiClient;
import io.swagger.client.ApiException;
import io.swagger.client.api.UploadFilesServiceApi;

public class PostArrayOfFiles {
    public static void main(String[] args) {
        UploadFilesServiceApi apiInstance = new UploadFilesServiceApi();
        try {
            ApiClient apiClient = apiInstance.getApiClient();
            //apiClient.setBasePath("http://0.0.0.0:8080");
            apiClient.setBasePath("http://swagger.io");

            List<File> uploadFileList = new ArrayList<File>();
            File testfile = new File("Users/waltershands/junk/test1.txt");
            uploadFileList.add(testfile);
            testfile = new File("Users/waltershands/junk/test2.txt");
            uploadFileList.add(testfile);

            apiInstance.uploadFiles(uploadFileList);
        } catch (ApiException var4) {
            System.err.println("Exception when calling uploadFileList");
            var4.printStackTrace();
        }
    }
}
Compile test program
javac -cp <path to generated swagger client>/target/swagger-java-client-1.0.0.jar <path>/src/main/java/io/arrayoffiles/PostArrayOfFiles.java 
Monitor POST requests in another terminal window
sudo tcpdump -A -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
Run test program
java -debug -cp <path to PostArrayOfFiles class>/target/classes:<path to generated swagger client>target/*:<path to other needed swagger jars>/target/lib/*  io.arrayoffiles.PostArrayOfFiles
Produces this POST request body (seen in tcpdump window):
....    wU5POST /runs HTTP/1.1
User-Agent: Swagger-Codegen/1.0.0/java
Content-Type: multipart/form-data; boundary=e2b790d8-0149-47ac-8740-755c53c982c3
Content-Length: 223
Host: swagger.io
Connection: Keep-Alive
Accept-Encoding: gzip

--e2b790d8-0149-47ac-8740-755c53c982c3
Content-Disposition: form-data; name="file_list"
Content-Length: 67

Users/waltershands/junk/test1.txt,Users/waltershands/junk/test2.txt
--e2b790d8-0149-47ac-8740-755c53c982c3--
...

There should have been two bodies with Content-Disposition that included a 'filename="test<#>.txt" and the contents of the file

ApiClient.java creates a correct body only if the instance of the formParams Object is a File, but in the test case it is a List of Files and so the correct body is not created.

...
1109     public RequestBody buildRequestBodyMultipart(Map<String, Object> formParams) {$
1110         MultipartBuilder mpBuilder = new MultipartBuilder().type(MultipartBuilder.FORM);$
1111         for (Entry<String, Object> param : formParams.entrySet()) {$
1112             if (param.getValue() instanceof File) {$
1113                 File file = (File) param.getValue();$
1114                 Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"" + param.getKey() + "\"; filename=\"" + fi     le.getName() + "\"");$
1115                 MediaType mediaType = MediaType.parse(guessContentTypeFromFile(file));$
1116                 mpBuilder.addPart(partHeaders, RequestBody.create(mediaType, file));$

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the issue with openapi-upload-files.yaml and the generated Java client, then inspect ApiClient.java in buildRequestBodyMultipart around lines 1109-1116. Confirm the multipart handling for a List; done means the request contains separate file parts with filenames and file contents instead of comma-joined file paths.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, openapi
Domain
api, backend-api-design
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.