Open
Description
Related problem
I was trying to create an HTTP server using only nushell and nmap's ncat, but because ncat doesn't send EOFs after each request, my request handler hung forever. I ended up having to use bash to separate the requests. 😢
Bash solution
main.sh
#!/usr/bin/env sh
# Spin up the HTTP server
ncat -lk -p 8080 -c './request_handler.sh' -v
request_handler.sh
#!/usr/bin/env sh
# Read lines until we hit an empty line
REQUEST=""
NL=$'\n'
while read -r line; do
trline=$(echo "$line" | tr -d '\r\n')
if [ -z "$trline" ]; then
break
fi
REQUEST="${REQUEST}${trline}${NL}"
done
# Ignore the request body because I didn't need it for my use case.
echo "$REQUEST" | mod.nu
mod.nu
#!/usr/bin/env -S nu --stdin
# Actually handle the http requests
def main [] {
let request = $in;
let url = (
'http://localhost'
+ (
$request | lines | first | split row ' ' | get 1
)
) | url parse
if ($request | authorized) {
respond 200 (handle $url)
} else {
respond 401 ({ message: "Unauthorized" })
}
}
def authorized []: string -> bool {
let headers = ($in | lines | skip 1 | take until { |line| $line == "" })
$headers | any { $in =~ $"[aA]uthorization: Bearer ($env.SOME_SECRET_KEY)"}
}
def handle [
url: record
] {
# business code ellided...
}
def respond [
code: int
body: any
] {
$'HTTP/1.1 ($code) ($code | code to string)
Content-Type: application/json
($body | to json)'
}
def "code to string" []: int -> string {
match $in {
200 => 'OK'
401 => 'Unauthorized'
}
}
Describe the solution you'd like
I'd like to be able to read from stdin (either line-by-line or one byte at a time) without having to wait for an EOF byte. It seems that there is currently no way to do this.
Describe alternatives you've considered
- I tried reading from
$in
, but that appears to collect the results. It works with a minimal example, but doesn't appear to work if you keep the buffer open.
> 'foo
bar' | ./in_example.nu
foo
bar
in_example.nu
#!/usr/bin/env -S nu --stdin
def main [] {
$in
}
- I tried reading with `input -u '\n', but that only accepted interactive input, not piped input.
> 'foo
bar' | ./input_example.nu
# Hangs forever
input_example.nu
#!/usr/bin/env -S nu --stdin
# input_example.nu
input -u '\n'
Additional context and details
My discord conversation (in #help)