0

Batch request returns 400 Bad Request.

I convert Japanese character to Shift-JIS: "description": 譌・ (shift_jis)

This is what it contains:

 --batch_request
Content-Type:multipart/mixed;boundary=changeset_1

--changeset_1
Content-Type: application/http
Content-Transfer-Encoding:binary
Content-Id: 1

POST https://.... HTTP/1.1
Accept: application/json
Content-Type: application/json  

{\"objectId\":\"5f6851c3-99cc-4a89-936d-4bb44fa78a34\",\"description\":\"譌・\"}

--changeset_1--
--batch_request--

Client:

public async Task<List<string>> POSTBatch(string endpoint, string contentbody)
        {
            HttpResponseMessage response = null;
            HttpRequestMessage batchRequest = null;
            HttpContent httpContent = null;           
            try
            {               
                    var requestcontent = new DemoRequestContent(contentbody);
                    httpContent = requestcontent.GetHttpContent(Encoding.UTF8, text/plain);
                    httpContent.Headers.Add(DemoConst.CSRF_NONCE, getCSRF_NONE().Result);
                    httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/mixed;boundary=batch_request");
                    var method = new HttpMethod("POST");
                    batchRequest = new HttpRequestMessage(method, baseURL + endpoint);
                    batchRequest.Content = httpContent;
                    response = await httpClient.SendAsync(batchRequest);                
                .............
                
                // Spilt response 
                var multipartRespMsgs = getMultiPart(response);
               ...............
               
            }
            catch (Exception ex)
            {
               
            }
          
        }

The key is to add a new content type "msgtype" header to the response:

private async Task<List<HttpResponseMessage>> getMultiPart(HttpResponseMessage response){
    var multipartContent = await response.Content.ReadAsMultipartAsync();
    var multipartRespMsgs = new List<HttpResponseMessage>();
    foreach (HttpContent currentContent in multipartContent.Contents) {
        // Two cases:
        // 1. a "single" response
        if (currentContent.Headers.ContentType.MediaType.Equals("application/http", StringComparison.OrdinalIgnoreCase)) {
            if (!currentContent.Headers.ContentType.Parameters.Any(parameter => parameter.Name.Equals("msgtype", StringComparison.OrdinalIgnoreCase) && parameter.Value.Equals("response", StringComparison.OrdinalIgnoreCase))) {
                currentContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("msgtype", "response"));
            }
            multipartRespMsgs.Add(await currentContent.ReadAsHttpResponseMessageAsync());
            // The single object in multipartRespMsgs contains a classic exploitable HttpResponseMessage (with IsSuccessStatusCode, Content.ReadAsStringAsync().Result, etc.)
        }
        // 2. a changeset response, which is an embedded multipart content
        else {
            var subMultipartContent = await currentContent.ReadAsMultipartAsync();
            foreach (HttpContent currentSubContent in subMultipartContent.Contents) {
                currentSubContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("msgtype", "response"));
                multipartRespMsgs.Add(await currentSubContent.ReadAsHttpResponseMessageAsync());
                // Same here, the objects in multipartRespMsgs contain classic exploitable HttpResponseMessages
            }
        }
    }
}

In my example, testString contains:

{\"objectId\":\"5f6851c3-99cc-4a89-936d-4bb44fa78a34\",\"description\":\"譌・\"}

When go to case 1:

multipartRespMsgs.Add(await currentContent.ReadAsHttpResponseMessageAsync()); // 400 Bad Request

UPDATE: Server log

org.apache.catalina.connector.ClientAbortException: java.io.IOException: An established connection was aborted by the software in your host machine
    at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:372)
    at org.apache.catalina.connector.OutputBuffer.flushByteBuffer(OutputBuffer.java:841)
    at org.apache.catalina.connector.OutputBuffer.append(OutputBuffer.java:746)
    at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:407)
    at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:385)
    at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:96)
    at wt.servlet.ServletRequestMonitor$CountingOutputStream.write(ServletRequestMonitor.java:2388)
    at java.util.zip.GZIPOutputStream.finish(GZIPOutputStream.java:168)
    at wt.servlet.CompressionFilter$GzippingResponse.finish(CompressionFilter.java:623)
    at wt.servlet.CompressionFilter$GzippingResponse.close(CompressionFilter.java:394)
    at wt.servlet.CompressionFilter.doFilter(CompressionFilter.java:302)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at wt.servlet.RequestInterrupter.doFilter(RequestInterrupter.java:335)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at wt.servlet.ServletRequestMonitor.doFilter(ServletRequestMonitor.java:1660)
    at wt.servlet.ServletRequestMonitorFilter.doFilter(ServletRequestMonitorFilter.java:56)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:543)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:524)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:818)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1637)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.IOException: An established connection was aborted by the software in your host machine
    at sun.nio.ch.SocketDispatcher.write0(Native Method)
    at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51)
    at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
    at sun.nio.ch.IOUtil.write(IOUtil.java:65)
    at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471)
    at org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:136)
    at org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:101)
    at org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:157)
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1322)
    at org.apache.tomcat.util.net.SocketWrapperBase.doWrite(SocketWrapperBase.java:692)
    at org.apache.tomcat.util.net.SocketWrapperBase.writeBlocking(SocketWrapperBase.java:485)
    at org.apache.tomcat.util.net.SocketWrapperBase.write(SocketWrapperBase.java:409)
    at org.apache.coyote.ajp.AjpProcessor.writeData(AjpProcessor.java:1390)
    at org.apache.coyote.ajp.AjpProcessor.access$900(AjpProcessor.java:58)
    at org.apache.coyote.ajp.AjpProcessor$SocketOutputBuffer.doWrite(AjpProcessor.java:1508)
    at org.apache.coyote.Response.doWrite(Response.java:600)
    at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:360)
    ... 35 more

Please give me the solution to this problem. Thank you

  • 2
    Are you sending binary or unicode? Is data a mime attachment or just add data to the body. You cannot send unicode data directly in the body. You either have to either convert to Base 64 stream or compress to GZIP stream. For unicode parameters in URL see : https://stackoverflow.com/questions/27955978/python-requests-url-with-unicode-parameters – jdweng Oct 30 '20 at 10:26
  • In the body I use : requestContent.GetHttpContent(Encoding.UTF8, "text/plain" ) – Scofield Michael Oct 30 '20 at 10:32
  • Does it enter that "If" block, just before currentContent.ReadAsHttpResponseMessageAsync line ? Also do you have an example client-side code that send the multipart batch request? It'd be nice to add it to the question. – AntiqTech Oct 30 '20 at 10:37
  • @AntiqTech Yes, I had update code client – Scofield Michael Nov 02 '20 at 01:50
  • Check your server log – shingo Nov 02 '20 at 03:46
  • @shingo I had updated server log – Scofield Michael Nov 02 '20 at 07:48
  • This means the post data is accepted, but there is some wrong when returns from the server. It can be a timeout issue, but most possible a server application error. – shingo Nov 02 '20 at 08:09
  • @shingo Yes, when Post data then status code 202, but get part of response message from the server status code 400. I had try use Postman send data then success, not error, but use source code then error – Scofield Michael Nov 02 '20 at 08:34
  • I generally see examples of multipart content , using a stream provider object. https://www.strathweb.com/2012/08/a-guide-to-asynchronous-file-uploads-in-asp-net-web-api-rtm/ Is there a significance / specific reason that you didn't use a provider on "response.Content.ReadAsMultipartAsync();" ? – AntiqTech Nov 02 '20 at 09:27
  • Also, what type does "requestcontent.GetHttpContent(Encoding.UTF8, text/plain)" returns? is it MultipartFormDataContent type? – AntiqTech Nov 02 '20 at 09:33

0 Answers0