WiFiServer - Connection reset by peer on ESP8266 after responding with HTTP 200

I have just flashed a sketch that has been working unchanged a couple of months ago onto my Wemos D1 mini and I observe that it breaks the connection with client right after it responds with HTTP 200 (OK).

Here’s the full code:

#include <ESP8266WiFi.h>

const char* ssid = "******";
const char* password = "******";

WiFiServer server(80);

void setup()
{
  Serial.begin(115200);
  Serial.println();

  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connected");

  server.begin();
  Serial.printf("Web server started, open %s in a web browser\n", WiFi.localIP().toString().c_str());
}


// prepare a web page to be send to a client (web browser)
String prepareHtmlPage()
{
  String htmlPage =
     String("HTTP/1.1 200 OK\r\n") +
            "Content-Type: text/html\r\n" +
            "Connection: close\r\n" +  // the connection will be closed after completion of the response
            "\r\n" +
            "<!DOCTYPE HTML>" +
            "<html>TEST</html>" +
            "\r\n";
  return htmlPage;
}


void loop()
{
  WiFiClient client = server.available();
  // wait for a client (web browser) to connect
  if (client)
  {
    Serial.println("\n[Client connected]");
    while (client.connected())
    {
      // read line by line what the client (web browser) is requesting
      if (client.available())
      {
        String line = client.readStringUntil('\r');
        Serial.print(line);
        // wait for end of client's request, that is marked with an empty line
        if (line.length() == 1 && line[0] == '\n')
        {
          client.println(prepareHtmlPage());
          break;
        }
      }
    }
    delay(1); // give the web browser time to receive the data

    // close the connection:
    client.stop();
    Serial.println("[Client disonnected]");
  }
}

and here’s what the console with all debugging info says upon opening the IP address in web browser:

Connecting to ***** ....... connected
Web server started, open 192.168.0.102 in a web browser

:ur 1
WS:dis
:del
WS:ac
:ref 1
WS:av
:ref 2
:ur 2

[Client connected]
:rn 338
GET / HTTP/1.1
Host: 192.168.0.102
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:70.0) Gecko/20100101 Firefox/70.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: pl,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
:wr 97 0
:wrc 97 97 0
:wr 2 0
:wrc 2 2 0
:ack 97
:ack 2
:close
[Client disonnected]
:ur 1
WS:dis
:del

The web browser says “Connection interrupted, try again”.

Now, I am more than sure this worked before. After some time I have installed the newer Arduino IDE, downloaded the boards definitions and that’s pretty much all.

When I try to wget 192.168.0.2 I get:

 wget 192.168.0.102
--2019-11-03 21:49:13--  http://192.168.0.102/
Connecting to 192.168.0.102:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: 'index.html'

index.html                            [ <=>                                                       ]      36  --.-KB/s    in 0.001s  

2019-11-03 21:49:13 (28.2 KB/s) - Read error at byte 36 (Connection reset by peer).Retrying.

--2019-11-03 21:49:14--  (try: 2)  http://192.168.0.102/
Connecting to 192.168.0.102:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: 'index.html'

index.html                            [ <=>                                                       ]      36  --.-KB/s    in 0.001s  

2019-11-03 21:49:14 (29.4 KB/s) - Read error at byte 36 (Connection reset by peer).Retrying.

but the index.html file DOES contain the desired HTTP response:

$ cat index.html 
<!DOCTYPE HTML><html>TEST</html>

Do you have any idea what is wrong? I have checked the router config, I have even set up another AP on my Android phone and repeated all steps with the very same results.
I have used Arduino 1.8.1, which I believe was close to what I was using in the past, still the same…

empty line in HTTP is \r\n