How can I filter the unique user on the Java web server?

Main File

public class Main {

    private static final String CONTEXT = "/app";
    private static final int PORT = 5000;

    public static void main(String[] args) throws Exception {

        // Create a new SimpleHttpServer
        Server simpleHttpServer = new Server(PORT, CONTEXT,
                new Request());

        // Start the server
        simpleHttpServer.start();
        System.out.println("Server is started and listening on port "+ PORT);
    }

}

Server.java

import java.io.IOException;
import java.net.InetSocketAddress;

import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class Server {
    private HttpServer httpServer;
    public Server(int port, String context, HttpHandler handler) {
        try {
            //Create HttpServer which is listening on the given port 
            httpServer = HttpServer.create(new InetSocketAddress(port), 0);
            //Create a new context for the given context and handler
            httpServer.createContext(context, handler);
            //Create a default executor
            httpServer.setExecutor(null);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void start() {
        this.httpServer.start();
    }

}

Request.java

import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.util.concurrent.atomic.AtomicInteger;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.Filter;


public class Request implements HttpHandler {

    private static final int HTTP_OK_STATUS = 200;

    AtomicInteger atomicInteger = new AtomicInteger(0);
    public void handle(HttpExchange t) throws IOException {
        int theValue = atomicInteger.get();

        String html = String.format("<html>n" +
                "    <head>n" +
                "        <title>Java Server</title>n" +
                "    </head>n" +
                "    <body>n" +
                "        <p>Visitorsn <b><h1>%d</h1></b></p>n" +
                "    </body>n" +
                "</html>",theValue);
        System.out.println("os: " + html);
        atomicInteger.addAndGet(1);
        t.sendResponseHeaders(HTTP_OK_STATUS, html.getBytes().length);
        //Write the response string
        OutputStream os = t.getResponseBody();
        System.out.println("os: " + html);
        os.write(html.getBytes());
        os.close();
    }

}

I created a simple http server with java. I set the server to run only in the app directory and port 5000, and it only needs to respond to get requests. I have to identify unique users coming to the server I want and print it in html. I’m suppressing the number of visitors to the server, but I don’t know how to filter for unique. How can I filter?

Answer

So far I was able to think up FOUR options.

First Option:

You can do session management: set a cookie and next time check if it’s set.

Set a cookie:

pRequest.getResponseHeaders().add("Set-Cookie", "YOUR_SESSION_ID_NAME=8360724401014372352; HttpOnly; Path=/;");

Provide a random number/String that you store on your server for look-up. Use HashMap<String, User> or some more permanent storage like database or files, if the session is supposed to survive server restarts.

Note: Some frameworks do NOT handle cookies when doing AJAX calls:

  • i.e. they will not pass on the your Set-Cookie header to the browser, so that cookie will NOT get registered in the Browser’s session management, and thus will not send back to the server.
  • Frameworks with this ‘feature’ are the old Angular.js and old versions of jQuery, IIRC. There may be more, but you better test it in each specific constellation.
  • To solve that problem,
    1. some pages, when receiving the session cookie, are (sometimes HTTP-) redirected to a normal static page (so no AJAX context). This hits the browser directly, thus he will do the cookie handling properly, and your session works. From that static page (usually saying ‘login success’) you will get HTML-Meta-redirected to the normal parts of the page again, so the page continues working as expected.
    1. some pages do the cookie detection and registration with the browser ‘manually’, thus there’s no more need for the ‘redirection magic’. Downside is that some specific styles/options of setting cookies do not work.

Retrieve cookie data:

final String data = pRequest.getHeaderOption("Cookie");

and inside data parse for the String of your YOUR_SESSION_ID_NAME.

Second Option:

Do an analysis on the connection. This usually consists of:

  1. The browser info from the HTTP header: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:87.0) Gecko/20100101 Firefox/87.0, retrieve with pRequest.getHeaderOption("User-Agent");
  2. The TCP/IP connection infos, like IP and port (though port will vary with each call, but usually it’s incremental). This has several downsides, because you cannot properly discern between multiple users behind a proxy etc.
  3. Do some JA3 analysis on HTTPS connections. This does not work with normal java Sockets or the sun HttpServer you’re using: https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967

This second option gets you close but it not a 100% precise, and will fail horribly if most the connections come from within the same network (conpany, university etc).

Third Option

(I guess this is NOT what you’re asking for)

Route your connections over a connection provider like google or azure who does all the statistics for you.

Fourth Option:

Instead of cookies, you can also use HTTP parameters to carry your information along. This is sometimes used when cookies are not guaranteed to work.

So whenever you send requests to the server, be it GET or POST requests (or others), you have to carry that parameters with you. However, as you might have guessed already, this can get quite complicated, because either

  • you have to extend all linking/posting pages to carry the parameters
  • or you provide a central preparing/routing mechanism, if you’re using AJAX of some kind

Facebook does this in one occasion, and not for session management per se, but mainly for statistics and ads: when you’re on Facebook and link to an external source, the link will always carry the parameter ?fbclid=..., so the Facebook Client ID

So basically, all this extra work that would have to go into a ‘manual’ parameter-based session management, was the reason that cookies got invented. Because HTTP per se is a stateless protocol. So how do you make it state-ful? By always passing along some identifiers. And this is exactly what cookies do. (Well, of course, they do even more nowadays, like storing user preferences that are not relevant to the server).