javahttpjwebserver

Why is jwebserver not responding to a simple manual HTTP request sent from the terminal?


If you have a php -S localhost:8888 server running, and then type the following commands on your terminal:

exec 3<> /dev/tcp/localhost/8888
echo -e "GET /hello.html HTTP/1.1\nHost: localhost\n" >& 3
cat <& 3

The php server will happily accept the request, and give back a response.

However, if I try the same exercise with jwebserver, jwebserver never receives this manual request. It only seems to respond to requests made from the webbrowser.

Any idea why?

UPDATE: adding more details as requested.

when the above bash scriptis run while a php -S localserver:8888 server is running, the bash script returns:

HTTP/1.1 200 OK
Host: localhost
Date: Mon, 11 Nov 2024 15:24:25 GMT
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 127

<html>
  <head>
    <title>Simple Hello page!</title>
  </head>

  <body>
    This is a very simple webpage!
  </body>
</html>

(where the HTTP body corresponds to the contents of the 'hello.html' file specified).

When the jwebserver is run on the same directory, e.g. as jwebserver -b localhost -p 8888, the bash script exits (after a noticeable delay) without returning anything, and there's no indication on the jwebserver process that any connection has been attempted in terms of output.

If I monitor each attempt using sudo tcpdump -i any port 8888 then I get the following output for the php one:

tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
15:24:25.791267 lo    In  IP view-localhost.47000 > view-localhost.8888: Flags [S], seq 1728240080, win 65495, options [mss 65495,sackOK,TS val 1603759113 ecr 0,nop,wscale 7], length 0
15:24:25.791295 lo    In  IP view-localhost.8888 > view-localhost.47000: Flags [S.], seq 239897535, ack 1728240081, win 65483, options [mss 65495,sackOK,TS val 1603759113 ecr 1603759113,nop,wscale 7], length 0
15:24:25.791316 lo    In  IP view-localhost.47000 > view-localhost.8888: Flags [.], ack 1, win 512, options [nop,nop,TS val 1603759113 ecr 1603759113], length 0
15:24:25.791424 lo    In  IP view-localhost.47000 > view-localhost.8888: Flags [P.], seq 1:26, ack 1, win 512, options [nop,nop,TS val 1603759114 ecr 1603759113], length 25
15:24:25.791437 lo    In  IP view-localhost.8888 > view-localhost.47000: Flags [.], ack 26, win 512, options [nop,nop,TS val 1603759114 ecr 1603759114], length 0
15:24:25.791454 lo    In  IP view-localhost.47000 > view-localhost.8888: Flags [P.], seq 26:42, ack 1, win 512, options [nop,nop,TS val 1603759114 ecr 1603759114], length 16
15:24:25.791460 lo    In  IP view-localhost.8888 > view-localhost.47000: Flags [.], ack 42, win 512, options [nop,nop,TS val 1603759114 ecr 1603759114], length 0
15:24:25.791473 lo    In  IP view-localhost.47000 > view-localhost.8888: Flags [P.], seq 42:43, ack 1, win 512, options [nop,nop,TS val 1603759114 ecr 1603759114], length 1
15:24:25.791479 lo    In  IP view-localhost.8888 > view-localhost.47000: Flags [.], ack 43, win 512, options [nop,nop,TS val 1603759114 ecr 1603759114], length 0
15:24:25.791549 lo    In  IP view-localhost.8888 > view-localhost.47000: Flags [P.], seq 1:154, ack 43, win 512, options [nop,nop,TS val 1603759114 ecr 1603759114], length 153
15:24:25.791562 lo    In  IP view-localhost.47000 > view-localhost.8888: Flags [.], ack 154, win 511, options [nop,nop,TS val 1603759114 ecr 1603759114], length 0
15:24:25.791586 lo    In  IP view-localhost.8888 > view-localhost.47000: Flags [P.], seq 154:281, ack 43, win 512, options [nop,nop,TS val 1603759114 ecr 1603759114], length 127
15:24:25.791593 lo    In  IP view-localhost.47000 > view-localhost.8888: Flags [.], ack 281, win 511, options [nop,nop,TS val 1603759114 ecr 1603759114], length 0
15:24:25.791626 lo    In  IP view-localhost.8888 > view-localhost.47000: Flags [F.], seq 281, ack 43, win 512, options [nop,nop,TS val 1603759114 ecr 1603759114], length 0
15:24:25.793618 lo    In  IP view-localhost.47000 > view-localhost.8888: Flags [F.], seq 43, ack 282, win 512, options [nop,nop,TS val 1603759116 ecr 1603759114], length 0
15:24:25.793653 lo    In  IP view-localhost.8888 > view-localhost.47000: Flags [.], ack 44, win 512, options [nop,nop,TS val 1603759116 ecr 1603759116], length 0
^C
16 packets captured
32 packets received by filter
0 packets dropped by kernel

whereas I get the following in the jwebserver scenario:

tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
15:24:55.964177 lo    In  IP view-localhost.32904 > view-localhost.8888: Flags [S], seq 4267327301, win 65495, options [mss 65495,sackOK,TS val 1603789286 ecr 0,nop,wscale 7], length 0
15:24:55.964198 lo    In  IP view-localhost.8888 > view-localhost.32904: Flags [S.], seq 3040620199, ack 4267327302, win 65483, options [mss 65495,sackOK,TS val 1603789286 ecr 1603789286,nop,wscale 7], length 0
15:24:55.964218 lo    In  IP view-localhost.32904 > view-localhost.8888: Flags [.], ack 1, win 512, options [nop,nop,TS val 1603789286 ecr 1603789286], length 0
15:24:55.964302 lo    In  IP view-localhost.32904 > view-localhost.8888: Flags [P.], seq 1:26, ack 1, win 512, options [nop,nop,TS val 1603789286 ecr 1603789286], length 25
15:24:55.964310 lo    In  IP view-localhost.8888 > view-localhost.32904: Flags [.], ack 26, win 512, options [nop,nop,TS val 1603789286 ecr 1603789286], length 0
15:24:55.964322 lo    In  IP view-localhost.32904 > view-localhost.8888: Flags [P.], seq 26:42, ack 1, win 512, options [nop,nop,TS val 1603789286 ecr 1603789286], length 16
15:24:55.964328 lo    In  IP view-localhost.8888 > view-localhost.32904: Flags [.], ack 42, win 512, options [nop,nop,TS val 1603789286 ecr 1603789286], length 0
15:24:55.964336 lo    In  IP view-localhost.32904 > view-localhost.8888: Flags [P.], seq 42:43, ack 1, win 512, options [nop,nop,TS val 1603789286 ecr 1603789286], length 1
15:24:55.964340 lo    In  IP view-localhost.8888 > view-localhost.32904: Flags [.], ack 43, win 512, options [nop,nop,TS val 1603789286 ecr 1603789286], length 0
^C
9 packets captured
19 packets received by filter

Whereas if I try to interact with the jwebserver on a normal browser, by going to location localhost:8888/hello.html, I get a normal response from the jwebserver, with terminal output indicating the request was received and responded to, and a tcpdump output of:

tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
15:32:47.505277 lo    In  IP view-localhost.45798 > view-localhost.8888: Flags [P.], seq 687846126:687846634, ack 397941893, win 512, options [nop,nop,TS val 1604260827 ecr 1604254275], length 508
15:32:47.508648 lo    In  IP view-localhost.8888 > view-localhost.45798: Flags [P.], seq 1:149, ack 508, win 512, options [nop,nop,TS val 1604260831 ecr 1604260827], length 148
15:32:47.508661 lo    In  IP view-localhost.45798 > view-localhost.8888: Flags [.], ack 149, win 511, options [nop,nop,TS val 1604260831 ecr 1604260831], length 0
15:32:47.520045 lo    In  IP view-localhost.8888 > view-localhost.45798: Flags [P.], seq 149:276, ack 508, win 512, options [nop,nop,TS val 1604260842 ecr 1604260831], length 127
15:32:47.520065 lo    In  IP view-localhost.45798 > view-localhost.8888: Flags [.], ack 276, win 511, options [nop,nop,TS val 1604260842 ecr 1604260842], length 0
^C
5 packets captured
10 packets received by filter

Solution

  • \r\n

    Your HTTP request is malformed.

    This Comment by dave_thompson_085 explains the issue: Use \r\n rather than \n.

    Change this line of your bash script:

    echo -e "GET /hello.html HTTP/1.1\nHost: localhost\n" >& 3
    

    … to this:

    echo -e "GET /hello.html HTTP/1.1\r\nHost: localhost\r\n" >& 3
    

    The HTTP/1.1 specification in RFC 2616 requires the use of CARRIAGE RETURN + LINE FEED (CRLF) as line terminator. To quote:

    HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all protocol elements except the entity-body

    More specifically, the spec explicitly says each message-header must be followed by a CRLF. To quote:

       generic-message = start-line
                         *(message-header CRLF)
                         CRLF
                         [ message-body ]                    
    

    Apparently your PHP implementation fails to comply with the specification, while the jwebserver (JEP 408) implementation complies correctly.

    Demonstration

    Using Java 23.0.1 on macOS Sonoma 14.7.1, in Terminal.app, I launch jwebserver with:

    jwebserver -p 8888
    

    Incorrect request

    In another Terminal.app window I switch my shell to bash. (zsh did not like your script.)

    I run your exact text including its incorrect headers with \n.

    exec 3<> /dev/tcp/localhost/8888
    echo -e "GET /hello.html HTTP/1.1\nHost: localhost\n" >& 3
    cat <& 3
    

    After a long moment, the command-line simply returns.

    bash-3.2$ exec 3<> /dev/tcp/localhost/8888
    bash-3.2$ echo -e "GET /hello.html HTTP/1.1\nHost: localhost\n" >& 3
    bash-3.2$ cat <& 3
    bash-3.2$ 
    

    No content, no error, on the client side. Meanwhile, the server window does nothing, no error, no message. Apparently jwebserver simply discards the invalid request.

    Correct request

    I open another Terminal.app window for another client request, switching to bash.

    This time I include the required \r\n rather than mere \n. This works! I get the content of my little web page displayed on the console.

    bash-3.2$ exec 3<> /dev/tcp/localhost/8888
    bash-3.2$ echo -e "GET /hello.html HTTP/1.1\r\nHost: localhost\r\n" >& 3
    bash-3.2$ cat <& 3
    HTTP/1.1 200 OK
    Date: Tue, 12 Nov 2024 04:33:17 GMT
    Last-modified: Tue, 12 Nov 2024 03:54:39 GMT
    Content-type: text/html
    Content-length: 290
    
    <!doctype html>
    <html lang="en">
        <head>
            <meta charset="utf-8" />
            <title>title</title>
        </head>
        <body>
            <h1>Bonjour</h1>
            <p>Wazzup?</p>
        </body>
    </html>
    bash-3.2$ 
    

    Meanwhile, in the Terminal.app window for the running jwebserver, I see a line appear reporting the activity:

    127.0.0.1 - - [12/Nov/2024:04:32:37 +0000] "GET /hello.html HTTP/1.1" 200 -
    

    Solution: Fix your request

    So the problem is your invalid request that fails to comply with the HTTP 1.1 spec. Fix your request to comply, and jwebserver will serve you.

    And file a bug report with your PHP server implementation for failing to follow the HTTP specification.