bash - Servidor web mínimo usando netcat
webserver (12)
Estoy tratando de configurar un servidor web mínimo usando netcat (nc). Cuando el navegador activa localhost: 1500, por ejemplo, debe mostrar el resultado de una función ( fecha en el ejemplo a continuación, pero eventualmente será un programa python o c que arroje algunos datos). Mi pequeño servidor web netcat necesita ser un verdadero bucle en bash, posiblemente tan simple como esto:
while true ; do echo -e "HTTP/1.1 200 OK/n/n $(date)" | nc -l -p 1500 ; done
Cuando intento esto, el navegador muestra los datos actualmente disponibles durante el momento en que se inicia nc. Sin embargo, quiero que el navegador muestre los datos durante el momento en que el navegador lo solicite. ¿Cómo puedo conseguir esto?
Agregue -q 1
a la línea de comando de netcat
:
while true; do
echo -e "HTTP/1.1 200 OK/n/n $(date)" | nc -l -p 1500 -q 1
done
Aquí hay una belleza de un pequeño servidor web bash , lo encontré en línea y bifurqué una copia y lo arreglé un poco - usa socat
o netcat
lo he probado con socat
- es autónomo en un script y genera su propio archivo de configuración y favicon.
De forma predeterminada, se iniciará como un explorador de archivos habilitado para web, pero el archivo de configuración lo configurará fácilmente para cualquier lógica. Para archivos, transmite imágenes y música (mp3), video (mp4''s, avi, etc.). He probado la transmisión de varios tipos de archivos a dispositivos Linux, Windows y Android, ¡incluido un reloj inteligente!
Creo que fluye mejor que VLC en realidad. Lo he encontrado útil para transferir archivos a clientes remotos que no tienen acceso más allá de un navegador web, por ejemplo, un reloj inteligente Android sin necesidad de preocuparse por la conexión física a un puerto USB.
Si quiere probarlo simplemente cópielo y péguelo en un archivo llamado bashttpd, luego inícielo en el host con $> bashttpd -s
Luego puede ir a cualquier otra computadora (suponiendo que el firewall no esté bloqueando las conexiones de tcp entrantes al puerto 8080, el puerto predeterminado, puede cambiar el puerto a lo que desee utilizando las variables globales en la parte superior del script). http://bashttpd_server_ip:8080
#!/usr/bin/env bash
#############################################################################
###########################################################################
### bashttpd v 1.12
###
### Original author: Avleen Vig, 2012
### Reworked by: Josh Cartwright, 2012
### Modified by: A.M.Danischewski, 2015
### Issues: If you find any issues leave me a comment at
### http://scriptsandoneliners.blogspot.com/2015/04/bashttpd-self-contained-bash-webserver.html
###
### This is a simple Bash based webserver. By default it will browse files and allows for
### retrieving binary files.
###
### It has been tested successfully to view and stream files including images, mp3s,
### mp4s and downloading files of any type including binary and compressed files via
### any web browser.
###
### Successfully tested on various browsers on Windows, Linux and Android devices (including the
### Android Smartwatch ZGPAX S8).
###
### It handles favicon requests by hardcoded favicon image -- by default a marathon
### runner; change it to whatever you want! By base64 encoding your favorit favicon
### and changing the global variable below this header.
###
### Make sure if you have a firewall it allows connections to the port you plan to
### listen on (8080 by default).
###
### By default this program will allow for the browsing of files from the
### computer where it is run.
###
### Make sure you are allowed connections to the port you plan to listen on
### (8080 by default). Then just drop it on a host machine (that has bash)
### and start it up like this:
###
### $192.168.1.101> bashttpd -s
###
### On the remote machine you should be able to browse and download files from the host
### server via any web browser by visiting:
###
### http://192.168.1.101:8080
###
#### This program requires (to work to full capacity) by default:
### socat or netcat (w/ ''-e'' option - on Ubuntu netcat-traditional)
### tree - useful for pretty directory listings
### If you are using socat, you can type: bashttpd -s
###
### to start listening on the LISTEN_PORT (default is 8080), you can change
### the port below.
### E.g. nc -lp 8080 -e ./bashttpd ## <-- If your nc has the -e option.
### E.g. nc.traditional -lp 8080 -e ./bashttpd
### E.g. bashttpd -s -or- socat TCP4-LISTEN:8080,fork EXEC:bashttpd
###
### Copyright (C) 2012, Avleen Vig <[email protected]>
###
### Permission is hereby granted, free of charge, to any person obtaining a copy of
### this software and associated documentation files (the "Software"), to deal in
### the Software without restriction, including without limitation the rights to
### use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
### the Software, and to permit persons to whom the Software is furnished to do so,
### subject to the following conditions:
###
### The above copyright notice and this permission notice shall be included in all
### copies or substantial portions of the Software.
###
### THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
### IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
### FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
### COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
### IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
### CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
###
###########################################################################
#############################################################################
### CHANGE THIS TO WHERE YOU WANT THE CONFIGURATION FILE TO RESIDE
declare -r BASHTTPD_CONF="/tmp/bashttpd.conf"
### CHANGE THIS IF YOU WOULD LIKE TO LISTEN ON A DIFFERENT PORT
declare -i LISTEN_PORT=8080
## If you are on AIX, IRIX, Solaris, or a hardened system redirecting
## to /dev/random will probably break, you can change it to /dev/null.
declare -a DUMP_DEV="/dev/random"
## Just base64 encode your favorite favicon and change this to whatever you want.
declare -r FAVICON="AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAADg4+3/srjc/5KV2P+ortn/xMrj/6Ch1P+Vl9f/jIzc/3572f+CgNr/fnzP/3l01f+Ih9r/h4TZ/8fN4//P1Oj/3uPr/7O+1v+xu9X/u8XY/9bi6v+UmdD/XV26/3F1x/+GitT/VVXC/3x/x/+HjNT/lp3Z/6633f/E0eD/2ePr/+bt8v/U4+v/0uLp/9Xj6//Z5e3/oKbX/0pJt/9maML/cHLF/3p8x//T3+n/3Ofu/9vo7//W5Oz/0uHq/9zn7f/j6vD/1OLs/8/f6P/R4Oj/1OPr/7jA4f9KSbf/Skm3/3p/yf/U4ez/1ePq/9rn7//Z5e3/0uHp/87e5//a5Ov/5Ovw/9Hf6v/T4uv/1OLp/9bj6/+kq9r/Skq3/0pJt/+cotb/zdnp/9jl7f/a5u//1+Ts/9Pi6v/O3ub/2uXr/+bt8P/Q3un/0eDq/9bj7P/Z5u7/r7jd/0tKt/9NTLf/S0u2/8zW6v/c5+//2+fv/9bj6//S4un/zt3m/9zm7P/k7PD/1OPr/9Li7P/V5Oz/2OXt/9jl7v+HjM3/lZvT/0tKt/+6w+L/2ebu/9fk7P/V4+v/0uHq/83d5v/a5ev/5ezw/9Pi6v/U4+z/1eXs/9bj6//b5+//vsjj/1hYvP9JSLb/horM/9nk7P/X5e3/1eTs/9Pi6v/P3uf/2eXr/+Tr7//O3+n/0uLr/9Xk7P/Y5e3/w8/k/7XA3/9JR7f/SEe3/2lrw//G0OX/1uLr/9Xi7P/T4ev/0N/o/9zn7f/k7PD/zN3p/8rd5v/T4ur/1ePt/5We0/+0w9//SEe3/0pKt/9OTrf/p7HZ/7fD3//T4uv/0N/o/9Hg6f/d5+3/5ezw/9Li6//T4uv/2ubu/8PQ5f9+hsr/ucff/4eOzv+Ei8z/rLja/8zc6P/I1+b/0OLq/8/f6P/Q4Oj/3eft/+bs8f/R4On/0+Lq/9Tj6v/T4Ov/wM7h/9Df6f/M2uf/z97q/9Dg6f/Q4On/1OPr/9Tj6//S4ur/0ODp/93o7f/n7vH/0N/o/8/f5//P3+b/2OXt/9zo8P/c6fH/zdjn/7fB3/+3weD/1eLs/9nn7//V5Oz/0+Lr/9Pi6//e6O7/5u3x/9Pi6v/S4en/0uLp/9Tj6//W4+v/3Ojw/9rm7v9vccT/wcvm/9rn7//X5Oz/0uHq/9Hg6f/S4er/3uju/+bt8f/R4On/0uHp/9Xk6//Y5u7/1OTs/9bk7P/W5Ov/XFy9/2lrwf/a5+//1uPr/9Pi6v/U4er/0eHq/93o7v/v8vT/5ezw/+bt8f/o7vL/6e/z/+jv8v/p7/L/6e/y/9XZ6//IzOX/6e7y/+nv8v/o7vL/5+7x/+ft8f/r8PP/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
declare -i DEBUG=1
declare -i VERBOSE=0
declare -a REQUEST_HEADERS
declare REQUEST_URI=""
declare -a HTTP_RESPONSE=(
[200]="OK"
[400]="Bad Request"
[403]="Forbidden"
[404]="Not Found"
[405]="Method Not Allowed"
[500]="Internal Server Error")
declare DATE=$(date +"%a, %d %b %Y %H:%M:%S %Z")
declare -a RESPONSE_HEADERS=(
"Date: $DATE"
"Expires: $DATE"
"Server: Slash Bin Slash Bash"
)
function warn() { ((${VERBOSE})) && echo "WARNING: $@" >&2; }
function chk_conf_file() {
[ -r "${BASHTTPD_CONF}" ] || {
cat >"${BASHTTPD_CONF}" <<''EOF''
#
# bashttpd.conf - configuration for bashttpd
#
# The behavior of bashttpd is dictated by the evaluation
# of rules specified in this configuration file. Each rule
# is evaluated until one is matched. If no rule is matched,
# bashttpd will serve a 500 Internal Server Error.
#
# The format of the rules are:
# on_uri_match REGEX command [args]
# unconditionally command [args]
#
# on_uri_match:
# On an incoming request, the URI is checked against the specified
# (bash-supported extended) regular expression, and if encounters a match the
# specified command is executed with the specified arguments.
#
# For additional flexibility, on_uri_match will also pass the results of the
# regular expression match, ${BASH_REMATCH[@]} as additional arguments to the
# command.
#
# unconditionally:
# Always serve via the specified command. Useful for catchall rules.
#
# The following commands are available for use:
#
# serve_file FILE
# Statically serves a single file.
#
# serve_dir_with_tree DIRECTORY
# Statically serves the specified directory using ''tree''. It must be
# installed and in the PATH.
#
# serve_dir_with_ls DIRECTORY
# Statically serves the specified directory using ''ls -al''.
#
# serve_dir DIRECTORY
# Statically serves a single directory listing. Will use ''tree'' if it is
# installed and in the PATH, otherwise, ''ls -al''
#
# serve_dir_or_file_from DIRECTORY
# Serves either a directory listing (using serve_dir) or a file (using
# serve_file). Constructs local path by appending the specified root
# directory, and the URI portion of the client request.
#
# serve_static_string STRING
# Serves the specified static string with Content-Type text/plain.
#
# Examples of rules:
#
# on_uri_match ''^/issue$'' serve_file "/etc/issue"
#
# When a client''s requested URI matches the string ''/issue'', serve them the
# contents of /etc/issue
#
# on_uri_match ''root'' serve_dir /
#
# When a client''s requested URI has the word ''root'' in it, serve up
# a directory listing of /
#
# DOCROOT=/var/www/html
# on_uri_match ''/(.*)'' serve_dir_or_file_from "$DOCROOT"
# When any URI request is made, attempt to serve a directory listing
# or file content based on the request URI, by mapping URI''s to local
# paths relative to the specified "$DOCROOT"
#
#unconditionally serve_static_string ''Hello, world! You can configure bashttpd by modifying bashttpd.conf.''
DOCROOT=/
on_uri_match ''/(.*)'' serve_dir_or_file_from
# More about commands:
#
# It is possible to somewhat easily write your own commands. An example
# may help. The following example will serve "Hello, $x!" whenever
# a client sends a request with the URI /say_hello_to/$x:
#
# serve_hello() {
# add_response_header "Content-Type" "text/plain"
# send_response_ok_exit <<< "Hello, $2!"
# }
# on_uri_match ''^/say_hello_to/(.*)$'' serve_hello
#
# Like mentioned before, the contents of ${BASH_REMATCH[@]} are passed
# to your command, so its possible to use regular expression groups
# to pull out info.
#
# With this example, when the requested URI is /say_hello_to/Josh, serve_hello
# is invoked with the arguments ''/say_hello_to/Josh'' ''Josh'',
# (${BASH_REMATCH[0]} is always the full match)
EOF
warn "Created bashttpd.conf using defaults. Please review and configure bashttpd.conf before running bashttpd again."
# exit 1
}
}
function recv() { ((${VERBOSE})) && echo "< $@" >&2; }
function send() { ((${VERBOSE})) && echo "> $@" >&2; echo "$*"; }
function add_response_header() { RESPONSE_HEADERS+=("$1: $2"); }
function send_response_binary() {
local code="$1"
local file="${2}"
local transfer_stats=""
local tmp_stat_file="/tmp/_send_response_$$_"
send "HTTP/1.0 $1 ${HTTP_RESPONSE[$1]}"
for i in "${RESPONSE_HEADERS[@]}"; do
send "$i"
done
send
if ((${VERBOSE})); then
## Use dd since it handles null bytes
dd 2>"${tmp_stat_file}" < "${file}"
transfer_stats=$(<"${tmp_stat_file}")
echo -en ">> Transferred: ${file}/n>> $(awk ''/copied/{print}'' <<< "${transfer_stats}")/n" >&2
rm "${tmp_stat_file}"
else
## Use dd since it handles null bytes
dd 2>"${DUMP_DEV}" < "${file}"
fi
}
function send_response() {
local code="$1"
send "HTTP/1.0 $1 ${HTTP_RESPONSE[$1]}"
for i in "${RESPONSE_HEADERS[@]}"; do
send "$i"
done
send
while IFS= read -r line; do
send "${line}"
done
}
function send_response_ok_exit() { send_response 200; exit 0; }
function send_response_ok_exit_binary() { send_response_binary 200 "${1}"; exit 0; }
function fail_with() { send_response "$1" <<< "$1 ${HTTP_RESPONSE[$1]}"; exit 1; }
function serve_file() {
local file="$1"
local CONTENT_TYPE=""
case "${file}" in
*/.css)
CONTENT_TYPE="text/css"
;;
*/.js)
CONTENT_TYPE="text/javascript"
;;
*)
CONTENT_TYPE=$(file -b --mime-type "${file}")
;;
esac
add_response_header "Content-Type" "${CONTENT_TYPE}"
CONTENT_LENGTH=$(stat -c''%s'' "${file}")
add_response_header "Content-Length" "${CONTENT_LENGTH}"
## Use binary safe transfer method since text doesn''t break.
send_response_ok_exit_binary "${file}"
}
function serve_dir_with_tree() {
local dir="$1" tree_vers tree_opts basehref x
## HTML 5 compatible way to avoid tree html from generating favicon
## requests in certain browsers, such as browsers in android smartwatches. =)
local no_favicon=" <link href=/"data:image/x-icon;base64,${FAVICON}/" rel=/"icon/" type=/"image/x-icon/" />"
local tree_page=""
local base_server_path="/${2%/}"
[ "$base_server_path" = "/" ] && base_server_path=".."
local tree_opts="--du -h -a --dirsfirst"
add_response_header "Content-Type" "text/html"
# The --du option was added in 1.6.0. "/${2%/*}"
read _ tree_vers x < <(tree --version)
tree_page=$(tree -H "$base_server_path" -L 1 "${tree_opts}" -D "${dir}")
tree_page=$(sed "5 i ${no_favicon}" <<< "${tree_page}")
[[ "${tree_vers}" == v1.6* ]]
send_response_ok_exit <<< "${tree_page}"
}
function serve_dir_with_ls() {
local dir="$1"
add_response_header "Content-Type" "text/plain"
send_response_ok_exit < /
<(ls -la "${dir}")
}
function serve_dir() {
local dir="$1"
# If `tree` is installed, use that for pretty output.
which tree &>"${DUMP_DEV}" && /
serve_dir_with_tree "$@"
serve_dir_with_ls "$@"
fail_with 500
}
function urldecode() { [ "${1%/}" = "" ] && echo "/" || echo -e "$(sed ''s/%/([[:xdigit:]]/{2/}/)////x/1/g'' <<< "${1%/}")"; }
function serve_dir_or_file_from() {
local URL_PATH="${1}/${3}"
shift
URL_PATH=$(urldecode "${URL_PATH}")
[[ $URL_PATH == *..* ]] && fail_with 400
# Serve index file if exists in requested directory
[[ -d "${URL_PATH}" && -f "${URL_PATH}/index.html" && -r "${URL_PATH}/index.html" ]] && /
URL_PATH="${URL_PATH}/index.html"
if [[ -f "${URL_PATH}" ]]; then
[[ -r "${URL_PATH}" ]] && /
serve_file "${URL_PATH}" "$@" || fail_with 403
elif [[ -d "${URL_PATH}" ]]; then
[[ -x "${URL_PATH}" ]] && /
serve_dir "${URL_PATH}" "$@" || fail_with 403
fi
fail_with 404
}
function serve_static_string() {
add_response_header "Content-Type" "text/plain"
send_response_ok_exit <<< "$1"
}
function on_uri_match() {
local regex="$1"
shift
[[ "${REQUEST_URI}" =~ $regex ]] && /
"$@" "${BASH_REMATCH[@]}"
}
function unconditionally() { "$@" "$REQUEST_URI"; }
function main() {
local recv=""
local line=""
local REQUEST_METHOD=""
local REQUEST_HTTP_VERSION=""
chk_conf_file
[[ ${UID} = 0 ]] && warn "It is not recommended to run bashttpd as root."
# Request-Line HTTP RFC 2616 $5.1
read -r line || fail_with 400
line=${line%%$''/r''}
recv "${line}"
read -r REQUEST_METHOD REQUEST_URI REQUEST_HTTP_VERSION <<< "${line}"
[ -n "${REQUEST_METHOD}" ] && [ -n "${REQUEST_URI}" ] && /
[ -n "${REQUEST_HTTP_VERSION}" ] || fail_with 400
# Only GET is supported at this time
[ "${REQUEST_METHOD}" = "GET" ] || fail_with 405
while IFS= read -r line; do
line=${line%%$''/r''}
recv "${line}"
# If we''ve reached the end of the headers, break.
[ -z "${line}" ] && break
REQUEST_HEADERS+=("${line}")
done
}
if [[ ! -z "{$1}" ]] && [ "${1}" = "-s" ]; then
socat TCP4-LISTEN:${LISTEN_PORT},fork EXEC:"${0}"
else
main
source "${BASHTTPD_CONF}"
fail_with 500
fi
Creo que el problema de que toda la solución enumerada no funciona, es intrínseca a la naturaleza del servicio http, cada solicitud establecida es con un cliente diferente y la respuesta debe procesarse en un contexto diferente, cada solicitud debe generar un nuevo instancia de respuesta ...
La solución actual, creo que es el -e
de netcat
pero no sé por qué no funciona ... tal vez es mi versión nc
que openwrt
en openwrt
...
con socat
funciona ...
Intento esto https://github.com/avleen/bashttpd
y funciona, pero debo ejecutar el script de shell con este comando.
socat tcp-l:80,reuseaddr,fork EXEC:bashttpd &
Las muestras de socat
y netcat
en github no funcionan para mí, pero el socat
que utilicé funciona.
El problema al que se enfrenta es que nc no sabe cuando el cliente web finaliza su solicitud para que pueda responder a la solicitud.
Una sesión web debería ser algo como esto.
TCP session is established.
Browser Request Header: GET / HTTP/1.1
Browser Request Header: Host: www.google.com
Browser Request Header: /n #Note: Browser is telling Webserver that the request header is complete.
Server Response Header: HTTP/1.1 200 OK
Server Response Header: Content-Type: text/html
Server Response Header: Content-Length: 24
Server Response Header: /n #Note: Webserver is telling browser that response header is complete
Server Message Body: <html>sample html</html>
Server Message Body: /n #Note: Webserver is telling the browser that the requested resource is finished.
The server closes the TCP session.
Las líneas que comienzan con "/ n" son simplemente líneas vacías sin espacio ni contienen nada más que un nuevo carácter de línea.
Tengo mi bash httpd lanzado por xinetd, xinetd tutorial . También registra la fecha, hora, dirección IP del navegador y toda la solicitud del navegador en un archivo de registro, y calcula la longitud del contenido para la respuesta del encabezado del servidor.
user@machine:/usr/local/bin# cat ./bash_httpd
#!/bin/bash
x=0;
Log=$( echo -n "["$(date "+%F %T %Z")"] $REMOTE_HOST ")$(
while read I[$x] && [ ${#I[$x]} -gt 1 ];do
echo -n ''"''${I[$x]} | sed -e''s,.$,",''; let "x = $x + 1";
done ;
); echo $Log >> /var/log/bash_httpd
Message_Body=$(echo -en ''<html>Sample html</html>'')
echo -en "HTTP/1.0 200 OK/nContent-Type: text/html/nContent-Length: ${#Message_Body}/n/n$Message_Body"
Para agregar más funcionalidad, podrías incorporar.
METHOD=$(echo ${I[0]} |cut -d" " -f1)
REQUEST=$(echo ${I[0]} |cut -d" " -f2)
HTTP_VERSION=$(echo ${I[0]} |cut -d" " -f3)
If METHOD = "GET" ]; then
case "$REQUEST" in
"/") Message_Body="HTML formatted home page stuff"
;;
/who) Message_Body="HTML formatted results of who"
;;
/ps) Message_Body="HTML formatted results of ps"
;;
*) Message_Body= "Error Page not found header and content"
;;
esac
fi
¡Maldición feliz!
Escriba nc -h y vea si tiene la opción -e disponible. En caso afirmativo, puede crear un script, por ejemplo:
script.sh
echo -e "HTTP/1.1 200 OK/n/n $(date)"
y ejecutarlo así:
while true ; do nc -l -p 1500 -e script.sh; done
Tenga en cuenta que la opción -e debe estar habilitada en la compilación para estar disponible.
LOL, un hack super lame, pero al menos curl y firefox lo acepta:
while true ; do (dd if=/dev/zero count=10000;echo -e "HTTP/1.1/n/n $(date)") | nc -l 1500 ; done
¡Será mejor que lo reemplace pronto con algo apropiado!
Ah, sí, mi nc
no era exactamente lo mismo que el tuyo, no me gustó la opción -p
.
No sé cómo ni por qué, pero logro encontrar esto y me funciona, tuve el problema que quería devolver el resultado de ejecutar un golpe
$ while true; do { echo -e ''HTTP/1.1 200 OK/r/n''; sh test; } | nc -l 8080; done
NOTA: Este comando fue tomado de: http://www.razvantudorica.com/08/web-server-in-one-line-of-bash
esto ejecuta la prueba del script bash y devuelve el resultado a un cliente del navegador que se conecta al servidor que ejecuta este comando en el puerto 8080
Mi script hace este cajero automático
$ nano test
#!/bin/bash
echo "************PRINT SOME TEXT***************/n"
echo "Hello World!!!"
echo "/n"
echo "Resources:"
vmstat -S M
echo "/n"
echo "Addresses:"
echo "$(ifconfig)"
echo "/n"
echo "$(gpio readall)"
y mi navegador web está mostrando
************PRINT SOME TEXT***************
Hello World!!!
Resources:
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
0 0 0 314 18 78 0 0 2 1 306 31 0 0 100 0
Addresses:
eth0 Link encap:Ethernet HWaddr b8:27:eb:86:e8:c5
inet addr:192.168.1.83 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:27734 errors:0 dropped:0 overruns:0 frame:0
TX packets:26393 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1924720 (1.8 MiB) TX bytes:3841998 (3.6 MiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
GPIOs:
+----------+-Rev2-+------+--------+------+-------+
| wiringPi | GPIO | Phys | Name | Mode | Value |
+----------+------+------+--------+------+-------+
| 0 | 17 | 11 | GPIO 0 | IN | Low |
| 1 | 18 | 12 | GPIO 1 | IN | Low |
| 2 | 27 | 13 | GPIO 2 | IN | Low |
| 3 | 22 | 15 | GPIO 3 | IN | Low |
| 4 | 23 | 16 | GPIO 4 | IN | Low |
| 5 | 24 | 18 | GPIO 5 | IN | Low |
| 6 | 25 | 22 | GPIO 6 | IN | Low |
| 7 | 4 | 7 | GPIO 7 | IN | Low |
| 8 | 2 | 3 | SDA | IN | High |
| 9 | 3 | 5 | SCL | IN | High |
| 10 | 8 | 24 | CE0 | IN | Low |
| 11 | 7 | 26 | CE1 | IN | Low |
| 12 | 10 | 19 | MOSI | IN | Low |
| 13 | 9 | 21 | MISO | IN | Low |
| 14 | 11 | 23 | SCLK | IN | Low |
| 15 | 14 | 8 | TxD | ALT0 | High |
| 16 | 15 | 10 | RxD | ALT0 | High |
| 17 | 28 | 3 | GPIO 8 | ALT2 | Low |
| 18 | 29 | 4 | GPIO 9 | ALT2 | Low |
| 19 | 30 | 5 | GPIO10 | ALT2 | Low |
| 20 | 31 | 6 | GPIO11 | ALT2 | Low |
+----------+------+------+--------+------+-------+
¡simplemente asombroso!
Otra forma de hacer esto
while true; do (echo -e ''HTTP/1.1 200 OK/r/n''; echo -e "/n/tMy website has date function" ; echo -e "/t$(date)/n") | nc -lp 8080; done
Probémoslo con 2 solicitudes HTTP usando curl
En este ejemplo, 172.16.2.6 es la dirección IP del servidor.
Lado del servidor
admin@server:~$ while true; do (echo -e ''HTTP/1.1 200 OK/r/n''; echo -e "/n/tMy website has date function" ; echo -e "/t$(date)/n") | nc -lp 8080; done
GET / HTTP/1.1 Host: 172.16.2.6:8080 User-Agent: curl/7.48.0 Accept:
*/*
GET / HTTP/1.1 Host: 172.16.2.6:8080 User-Agent: curl/7.48.0 Accept:
*/*
Lado del cliente
user@client:~$ curl 172.16.2.6:8080
My website has date function
Tue Jun 13 18:00:19 UTC 2017
user@client:~$ curl 172.16.2.6:8080
My website has date function
Tue Jun 13 18:00:24 UTC 2017
user@client:~$
Si desea ejecutar otro comando, puede reemplazar $ (fecha).
Prueba esto:
while true ; do nc -l -p 1500 -c ''echo -e "HTTP/1.1 200 OK/n/n $(date)"''; done
El -c
hace que netcat ejecute el comando dado en un intérprete de comandos, por lo que puede usar echo. Si no necesita eco, use -e
. Para más información sobre esto, prueba man nc
. Tenga en cuenta que al usar echo
no hay forma de que su programa (el reemplazo de date
) obtenga la solicitud del navegador. Entonces, probablemente, finalmente quieras hacer algo como esto:
while true ; do nc -l -p 1500 -e /path/to/yourprogram ; done
Donde su yourprogram
debe hacer el protocolo, como manejar GET, enviar HTTP 200, etc.
Si está utilizando Apline Linux, el netcat BusyBox es ligeramente diferente:
while true; do nc -l -p 8080 -e sh -c ''echo -e "HTTP/1.1 200 OK/n/n$(date)"''; done
Tenía la misma necesidad / problema, pero aquí no funcionó nada (o no entendí todo), así que esta es mi solución.
Publiqué mi minimal_http_server.sh (trabajando con mi / bin / bash (4.3.11) pero no / bin / sh debido a la redirección):
rm -f out
mkfifo out
trap "rm -f out" EXIT
while true
do
cat out | nc -l 1500 > >( # parse the netcat output, to build the answer redirected to the pipe "out".
export REQUEST=
while read -r line
do
line=$(echo "$line" | tr -d ''/r/n'')
if echo "$line" | grep -qE ''^GET /'' # if line starts with "GET /"
then
REQUEST=$(echo "$line" | cut -d '' '' -f2) # extract the request
elif [ -z "$line" ] # empty line / end of request
then
# call a script here
# Note: REQUEST is exported, so the script can parse it (to answer 200/403/404 status code + content)
./a_script.sh > out
fi
done
)
done
Y mi a_script.sh (con su necesidad):
#!/bin/bash
echo -e "HTTP/1.1 200 OK/r"
echo "Content-type: text/html"
echo
date
mkfifo pipe;
while true ;
do
#use read line from pipe to make it blocks before request comes in,
#this is the key.
{ read line<pipe;echo -e "HTTP/1.1 200 OK/r/n";echo $(date);
} | nc -l -q 0 -p 8080 > pipe;
done