ericcartman, CompletableFuture.supplyAsync() выполнит лямбда-выражение не асинхронно, а параллельно, в отдельном потоке.
Я советую вам написать с нуля свой http-сервер. Сначала однопоточный на сокетах. Потом сделать его многопоточным. Потом переписать в асинхронном варианте с java.nio.channels. Потом переписать ещё раз на Netty. Потом вдумчиво изучить Servlet API. Это даст вам базу, чтобы понимать как там все происходит.
ericcartman, вы неправильно и поверхностно представляете процесс сетевого взаимодействия. Это мешает вам понять, что Java-программа может быть сервером сама по себе, в том числе асинхронным, и может принимать и обрабатывать запросы самостоятельно.
Всё верно, умные программисты, которые писали браузер, добавили в него код, который делает URL encoding за вас. Вам в вашей программе надо сделать то же самое.
Terras, это для вас. Я знаю людей годами клепающих сайты на всяких там Битриксах, Вордпрессах и Джумлах, которые ни черта не знают о стеке вызовов, ссылочных и примитивных типах, сокетах, ООП и прочем. Более того, для них это всё неподъёмно сложная область знаний.