0

I'd like to write a simple web server uniquely in bash. Thus I go:

#!/usr/bin/env bash

exec 3<> <(nc -lp 8000)

echo "before the loop"

INDEX="<!DOCTYPE html><html><head><meta charset=\"UTF-8\"></head><body><p>QWERTY</p></body></html>"

while read -u 3 line; do
  echo "line: ${line}" #why can one not encapsulate ${line} in single quotes, for one thing ?
  xxd -pr <<<"$line"
  if [[ "$line" == "\r\n" ]]; then
    echo -en "HTTP/1.1 OK\r\nContent-Type: text/html\r\nContent-Length: $(wc -c <<<"${INDEX}" )\r\n\r\n${INDEX}" >&3
    echo "printed"
    sleep 1
  fi
done

echo "efter the loop, line '${line}'"

exec 3>&-

but it does not work for me. Supposedly, since I've opened the pipe wrongly, but how to do it properly?

unegare
  • 2,197
  • 1
  • 11
  • 25
  • 1
    `<(.,.)` is only an input file. `>(...)` is only an output file. Actually create two fifos to communicate and use two FDs. Or actually use `coproc`. – KamilCuk Feb 10 '21 at 10:53
  • @KamilCuk, how to create two fifos fow one child ? – unegare Feb 10 '21 at 10:57
  • 1
    I do not ..? `mkfifo onefifo; mkfifo twofifo; child twofifo`. But use `coproc` - it's an utility specifically designed for this. and anyway, if you use gnu-netcat, then use `--exec` option to run your script. See https://stackoverflow.com/questions/16640054/minimal-web-server-using-netcat . – KamilCuk Feb 10 '21 at 10:59
  • @KamilCuk, but they are named and consequently they create files in the current directory. How to perform it without this side effect? – unegare Feb 10 '21 at 11:01
  • 1
    Use `coproc`..... – KamilCuk Feb 10 '21 at 11:01
  • Thank you for pointing out the `coproc` keyword, I twigged the idea. It's amazing and I'm going to follow it. Having said that, I would appreciate your telling me if there is a way to do it via `fifo`s / `fd`s without resorting to `coproc` and touching fs for creating associated files for `fifo`s etc. – unegare Feb 10 '21 at 11:05
  • @KamilCuk, just learnt that there is a `mktemp` command, hence it is a probable way round with `fifo`s. That said, there is no way without `fifo`s at all, is it? I ask in self-education purpose. – unegare Feb 10 '21 at 11:13
  • 1
    There is a certain need in shell to do stuff without "temporary files". Don't go there. Temporary files is _the way_ to work in shell. It's like dynamic allocation in C - you have to cleanup after use. `there is no way without fifos at all, is it?` There is shared memory. There is `socat`. You can use one fifo - `nc ... < fifo | your program > fifo`. You can write a shell builtin or a python script that will spawn `nc` and `your_program` and call `dup2` to connect file descriptors together. Sky's the limit. But use `nc --exec` - right now, your script can only service one client at a time. – KamilCuk Feb 10 '21 at 11:14
  • @KamilCuk, so it is not possible to tackle several clients in one process written in bash? without other childs barring `netcat`? As there is no way to bind/listen/epoll via bash, is it? – unegare Feb 10 '21 at 11:32
  • 1
    As mentioned, there is `socat` and `netcat --exec`.... `is no way to bind/listen/epoll via bash` there is `/dev/tcp//`, but I have no experience with it, never worked for me reliably. – KamilCuk Feb 10 '21 at 11:34
  • @KamilCuk, `/dev/tcp//` WoW!!! – unegare Feb 10 '21 at 11:39
  • 1
    note that bash's `coproc` is quite *buggy*. see https://lists.gnu.org/archive/html/bug-bash/2016-04/msg00014.html – pynexj Feb 10 '21 at 11:42
  • @KamilCuk, and one last thing ... Why can I not write `echo "line: \"${line}\""` in the line commented above ? It prints `"line: "GET ....`, as you can see the double quotes are not in order. – unegare Feb 10 '21 at 11:44
  • `see the double quotes are not in order` The input has CR character and uses dos line endings. Handle this character or remove them or use `declare -p line` or `printf "%q" "$line"` to print the variable value unambiguously. – KamilCuk Feb 10 '21 at 11:54

1 Answers1

1

how to do it properly?

You have some options:

  • Use two pipes, preferably created inside mkdir -d.
  • Use one pipe, and connect output with pipe `nc ... <pipe | { your_script } >pipe
  • In simple cases I recommend to use bash thing coproc that was just designed for it.
  • I recommend to use external utility, which will allow to handle multiple clients at the same time. In my experience nc doesn't behave properly/great when connection closes. I strongly recommend socat or at least GNU-netcat with it's --exec option.
KamilCuk
  • 120,984
  • 8
  • 59
  • 111