2

How can I make an xinetd service such that a web browser can reliably show its output?

The service always sees the HTTP GET request on its stdin, and sends its reply to stdout. xinetd handles the tcp connection.

Firefox sometimes correctly shows the output. But sometimes it claims that the server reset the connection while it was still loading the page. Sometimes it shows all output, but keeps waiting for more (and when I then press ESC, it makes a new connection to the server with an empty HTTP request).

The definition for the xinetd service is:

service test
{
    disable = no
    id              = test
    type            = UNLISTED
    port            = 8043
    wait            = no
    socket_type     = stream
    flags           = IPv4
    user            = root
    server          = /usr/local/bin/test.sh
}

The script for this simple test ignores the input, just echoes a minimal html. It causes the same problem as the real thing, eventhough there I added a command to close stdout at the end.

echo 'HTTP/1.1 200 OK'
echo 'Content-Type: text/html; charset=UTF-8'
echo ''
echo '<html>'
echo '<body style="background:#dfd">'
echo '<b>hello, world!</b><br>'
echo `date`
echo '</body>'
echo '</html>'

How is this different from what a web server would do?

Klaus Hartnegg
  • 331
  • 1
  • 7

2 Answers2

2

I Found two possible answers in xinetd 'connection reset by peer':

Turns out I must do both, plus one more:

  • the server must send HTTP/1.0 instead of HTTP/1.1
  • The server must send Content-Length.
  • The output must first be written to a file, and then that must be sent with cat

Does anybody see an easier way? Imho the HTTP/1.1 standard does allow to omit Content-Length and instead close the connection. And where is the difference between one cat and a series of echo commands?

Klaus Hartnegg
  • 331
  • 1
  • 7
2

cat or echo are both acceptable. In both cases, the data goes to standard out.

An HTTP Response can be sent with the following bash function:

#
# The HTTP response
# Syntax:  http_response 200 "Success Message" 
#          http_response 503 "Service Unavailable Message" 
#
http_response () {
    HTTP_CODE=$1
    MESSAGE=${2:-Message Undefined}
    length=${#MESSAGE}
    if [ "$HTTP_CODE" -eq 503 ]; then
      echo -en "HTTP/1.1 503 Service Unavailable\r\n" 
    elif [ "$HTTP_CODE" -eq 200 ]; then
      echo -en "HTTP/1.1 200 OK\r\n" 
    else
      echo -en "HTTP/1.1 ${HTTP_CODE} UNKNOWN\r\n" 
    fi
    echo -en "Content-Type: text/plain\r\n" 
    echo -en "Connection: close\r\n" 
    echo -en "Content-Length: ${length}\r\n" 
    echo -en "\r\n" 
    echo -en "$MESSAGE"
    echo -en "\r\n" 
    sleep 0.1
    exit 0
}

I wrote a mini bash-http service for xinetd that might be helpful.

http://github.com/rglaue/xinetd_bash_http_service

It accepts HTTP/1.0 requests, including the parsing of HTTP headers like the HTTP request and parameters. And it returns an appropriate HTTP response. It is also command-line friendly.

bash~$ echo "GET /weight-value?inverse-weight=0&max-weight=100 HTTP/1.0" | xinetdhttpservice.sh --http-status
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: close
Content-Length: 15

WEIGHT_VALUE=99
Russell E Glaue
  • 921
  • 7
  • 7