Search code examples
groovyheadermultipartform-data

Multipart headers seem to be ignored


I have the following code which is supposed to send a POST request to some service and basically post a file.

This request is multipart/form-data. And it consists of:

  • JSON
  • Base64 file

The code is below:

sendMultipartPost();

def sendMultipartPost() 
{
  def URLToGo = 'http://127.0.0.1:8080/sd/services/rest/find/';
  def httpRequest = new HTTPBuilder(URLToGo);
  def authToken = 'AR-JWT ' + 'TOKEN';

  def headers = ['Authorization' : authToken, 'Content-Type' : 'multipart/form-data; boundary=W3NByNRZZYy4ALu6xeZzvWXU3NVmYUxoRB'];  
  httpRequest.setHeaders(headers);

  def body = ["values":["Incident Number":'testSC',"Work Log Type":"General Information","Description":"File has been added TESTFile","z2AF Work Log01":'Test File title']];

  httpRequest.request(Method.POST) 
  {
      req ->

      MultipartEntity multiPartContent = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, 'W3NByNRZZYy4ALu6xeZzvWXU3NVmYUxoRB', Charset.forName("UTF-8"));

      Gson gson = new Gson(); 
      String jsonObj = gson.toJson(body);

      multiPartContent.addPart('entry', new StringBody(jsonObj, ContentType.APPLICATION_JSON));
      multiPartContent.addPart('attach-z2AF Work Log01', new ByteArrayBody(Base64.encodeBase64("let's createBase64 let's createBase64 let's createBase64 let's createBase64 let's createBase64".getBytes()), ContentType.APPLICATION_OCTET_STREAM, 'test file title'));

      req.setEntity(multiPartContent);

      response.success = { resp ->

          if (resp.statusLine.statusCode == 200) {

                    // response handling

                     }
              }

       response.failure = { resp, json ->
        result = groovy.json.JsonOutput.toJson(['state':resp.status])
          }
  }
}

However, whenever I send a request, it seems that some headers are missed or not specified:

The generated request's body

But the "perfect" request looks like this:

The perfect request

Now we can conclude that the following headers of JSON:

  • Content-Type for JSON is missing (although you can see that the first part, which is json, is of ContentType.APPLICATION_JSON)
  • charset is not specified automatically
  • Content-Transfer-Encoding is not specified automatically

As of base64:

  • Content-Transfer-Encoding is not specified automatically

Consequently, I have 2 questions:

  • Why is the header Content-Type of JSON absent whilst I actually set it?
  • How do I specify the headers which are not present at all?

Thanks in advance


Solution

  • Why is the header Content-Type of JSON absent whilst I actually set it?

    because you are using HttpMultipartMode.BROWSER_COMPATIBLE mode. remove it and you'll get the content-type header.

    How do I specify the headers which are not present at all?

    the only way in this library - to use FormBodyPart to wrap any body and to add required headers.

    Here is a code example that you could run in groovyconsole

    @Grab(group='org.apache.httpcomponents', module='httpmime', version='4.5.10')
    import org.apache.http.entity.mime.MultipartEntityBuilder
    import org.apache.http.entity.ContentType
    import org.apache.http.entity.mime.content.StringBody
    //import org.apache.http.entity.mime.content.ByteArrayBody
    import org.apache.http.entity.mime.FormBodyPartBuilder
    
    //form part has ability to specify additional part headers
    def form(Map m){
        def p = FormBodyPartBuilder.create(m.remove('name'), m.remove('body'))
        m.each{ k,v-> p.addField(k,v.toString()) } //all other keys assume to be headers
        return p.build()
    }
    
    def json = '{"aaa":111,"bbb":222,"ccc":333}'
    
    def multipart = MultipartEntityBuilder.create()
            .addTextBody( "foo", 'bar' ) //transfer text with default encoding
            .addTextBody( "theJson", json, ContentType.APPLICATION_JSON ) //text with content type
            .addPart(form(
                    //add part with headers
                    name:'TheJsonWithHdrs', 
                    body:new StringBody(json.getBytes("UTF-8").encodeBase64().toString(),ContentType.APPLICATION_JSON), 
                    'Content-transfer-encoding':'base64',
                ))
            .build()
    
    //print result
    def b = new ByteArrayOutputStream()
    multipart.writeTo(b)
    println b.toString("ASCII")
    

    results

    --s89LGRZ8HCJ4Gimdis8AH2pXpUQyEpvalzB
    Content-Disposition: form-data; name="foo"
    Content-Type: text/plain; charset=ISO-8859-1
    Content-Transfer-Encoding: 8bit
    
    bar
    --s89LGRZ8HCJ4Gimdis8AH2pXpUQyEpvalzB
    Content-Disposition: form-data; name="theJson"
    Content-Type: application/json; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    {"aaa":111,"bbb":222,"ccc":333}
    --s89LGRZ8HCJ4Gimdis8AH2pXpUQyEpvalzB
    Content-transfer-encoding: base64
    Content-Disposition: form-data; name="TheJsonWithHdrs"
    Content-Type: application/json; charset=UTF-8
    
    eyJhYWEiOjExMSwiYmJiIjoyMjIsImNjYyI6MzMzfQ==
    --s89LGRZ8HCJ4Gimdis8AH2pXpUQyEpvalzB--