Search code examples
javatomcat7cxfapache-httpclient-4.xservlet-3.0

HTTP 400 When executing a multi part request from Apache HTTP Client


I'm trying to forward a request coming to a Servlet to the actual backend implemented in CXF implementation of JAX-RS running on tomcat 7.

Following is my code,

protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
    HttpPost postRequest = new HttpPost(targetURL);
    if (ServletFileUpload.isMultipartContent(req)) {
        ServletFileUpload servletFileUpload = new ServletFileUpload(new DiskFileItemFactory());
        List<FileItem> fileItemList = servletFileUpload.parseRequest(req);
        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
        entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        for (FileItem item: fileItemList) {
            entityBuilder.addPart(item.getFieldName(), new ByteArrayBody(item.get(), ContentType.create(item.getContentType()), item.getName()));
        }
        postRequest.setEntity(entityBuilder.build());
    } else {
        if (StringUtils.isNotEmpty(req.getHeader(HttpHeaders.CONTENT_LENGTH)) || StringUtils.isNotEmpty(req.getHeader(HttpHeaders.TRANSFER_ENCODING))) {
            InputStreamEntity entity = new InputStreamEntity(req.getInputStream(), Long.parseLong(req.getHeader(HttpHeaders.CONTENT_LENGTH)));
            postRequest.setEntity(entity);
        }
    }
    postRequest.setHeader(postRequest.getEntity().getContentType());
    postRequest.setHeader(HttpHeaders.AUTHORIZATION, "ACCESS-TOKEN");
    try (CloseableHttpClient client = HttpClients.createDefault()) {
        HttpResponse response = client.execute(httpRequest);
    }
}

Above code runs without an issue for non-multipart requests. However, getting "HTTP 400 Bad Request" response whenever I try a multipart request. The request does not get delivered to the actual implementation as well (No errors in the backend)

HttpResponseProxy{HTTP/1.1 400 Bad Request [X-Frame-Options: DENY, X-Content-Type-Options: nosniff, X-XSS-Protection: 1; mode=block, Access-Control-Allow-Origin: *, Access-Control-Allow-Methods: GET, POST, DELETE, PUT, Access-Control-Allow-Headers: Content-Type, Date: Fri, 21 Jun 2019 01:27:59 GMT, Content-Length: 0, Connection: close] [Content-Length: 0,Chunked: false]}

I tried to preserve the incoming content-type header with the original boundary and then the backend throws the following error.

Caused by: org.apache.cxf.interceptor.Fault: Couldn't find MIME boundary: ----------------------------282428552532940822247758
at org.apache.cxf.interceptor.AttachmentInInterceptor.handleMessage(AttachmentInInterceptor.java:60)
at org.apache.cxf.jaxrs.ext.MessageContextImpl.createAttachments(MessageContextImpl.java:268)
at org.apache.cxf.jaxrs.ext.MessageContextImpl.get(MessageContextImpl.java:77)

Any idea What I am doing wrong here?


Solution

  • postRequest.setHeader(postRequest.getEntity().getContentType());
    

    Do not do that. HttpClient automatically generates Content-Type header for the request message body based on properties of the enclosed HttpEntity.