Monday, September 26, 2016

Duplicate HTTP/HTTPS Post requests


If you are here that means you are also puzzled by a weird error where same HTTP/HTTPS request is resent to the server, sometimes after few ms or few seconds.

And, it doesn't help that even POST requests are being repeatedly being sent to the server

There are quite a few reports in the wild which report the same thing. One of them is here.

It happened to us also and I was trying to understand this & hoping that I will be able to reproduce this.

Finally, I was able to do it on my localhost and it does confirm what HTTP 1.1 Spec says here.

Exact Steps to reproduce are

  • Install MITMProxy on your localhost
    • This will run on port 8080 by default
    • if you are trying to troubleshoot HTTPS request then ensure that localhost trust store has HTTPS certificate available
  • Install firefox if you don’t have it already
  • Install Wireshark to investigate the traffic on your machine
    • please note that loopback address of 127.0.0.1 can be easily captured by wireshark on mac and linux
    • Windows may require some additional steps. Please refer to wireshark documentation
  • Configure Firefox to proxy all requests (including localhost) to localhost:8080 where MITMProxy is running
  • Use a simple form to post the data - this is to ensure that request has a body
    • Reference is TestPostForm.html
  • Write a Simple Test Http Server which accepts the requests and closes the connection without any response
    • Refer to AnotherTestHttpServer
    • Line # 23 is commented out to ensure that socket is closed without sending any response to client
  • Run test http server by running the java code from above step
  • Launch wireshark and start filtering HTTP traffic by typing http in filter 
  • Load TestPostForm.html in firefox and hit submit
  • You should see 2 requests hitting Java HTTP Server while browse displays “HttpReadDisconnect('Server disconnected',) “ error
  • Wireshark logs will show 2 requests from MITMProxy to HTTPServer while Proxy convey to Browser the error “502 Bad Gateway”

Source Code of AnotherTestHttpServer is as following
import java.io.*;
import java.net.*;
import java.util.Date;

public class AnotherTestHttpServer {

    public static void main(String args[]) throws IOException {
        ServerSocket server = new ServerSocket(8000);
        System.out.println("Listening for connection on port 8000 ....");
        while (true) {
                try (Socket socket = server.accept()) {


                    System.out.println("Creating a socket with port " +
 socket.getPort());

                    System.out.println("Handling request...." + 
 
 System.currentTimeMillis());

                        Date today = new Date();
                        String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + today;
                        //socket.getOutputStream().write(httpResponse.getBytes("UTF-8"));
                    socket.close();
                }
            }
    }
} 

Source Code of TestPostForm.html 

 <HTML>  
 <HEAD>  
       <TITLE>A Sample Form Using POST</TITLE>  
 </HEAD>  
 <BODY BGCOLOR="#FDF5E6">  
 <CENTER>  
 <H2>A Sample Form Using POST</H2>  
 <FORM ACTION="http://localhost:8000"  
    METHOD="POST">  
  First name:  
  <INPUT TYPE="TEXT" NAME="firstName" VALUE="ABC"><BR>  
  Last name:  
  <INPUT TYPE="TEXT" NAME="lastName" VALUE="DEFDFD"><P>  
  <INPUT TYPE="SUBMIT">  
 </FORM>  
 </CENTER>  
 </BODY></HTML>  


How to workaround this problem
try to put a GUID in each request and check your db/cache before executing the request. If GUID is found in the cache/DB then return the same response.

Putting a cache in front of service layer may help otherwise db layer locking may be required 

Helpful References are