Serveur Web minimal utilisant netcat


129

J'essaye de mettre en place un serveur Web minimal en utilisant netcat (nc). Lorsque le navigateur appelle localhost: 1500, par exemple, il devrait afficher le résultat d'une fonction ( date dans l'exemple ci-dessous, mais ce sera finalement un programme python ou c qui produira des données). Mon petit serveur Web netcat doit être une boucle while true dans bash, peut-être aussi simple que ceci:

while true ; do  echo -e "HTTP/1.1 200 OK\n\n $(date)" | nc -l -p 1500  ; done

Lorsque j'essaye cela, le navigateur affiche les données actuellement disponibles au moment où nc démarre. Je veux que le navigateur affiche les données au moment où le navigateur le demande, cependant. Comment puis-je atteindre cet objectif?


Merci à tous pour les suggestions qui m'ont amené à aller plus loin sur Google. En l'occurrence, je suis tombé sur une solution complètement différente chez link . Je ne peux pas utiliser python ou C, mais je l'ai déjà testé sur toutes mes plateformes cibles. Le problème avec netcat est qu'il existe tellement de versions différentes. Certains d'entre eux n'autorisent pas les options -e, -c ou -q.
andwagon

Réponses:


52

Essaye ça:

while true ; do nc -l -p 1500 -c 'echo -e "HTTP/1.1 200 OK\n\n $(date)"'; done

Le -cfait que netcat exécute la commande donnée dans un shell, vous pouvez donc utiliser echo. Si vous n'avez pas besoin d'écho, utilisez -e. Pour plus d'informations à ce sujet, essayez man nc. Notez que lors de l'utilisation, echoil n'y a aucun moyen pour votre programme (le dateremplacement) d'obtenir la requête du navigateur. Donc, vous voulez probablement enfin faire quelque chose comme ceci:

while true ; do nc -l -p 1500 -e /path/to/yourprogram ; done

yourprogramfaut-il faire les choses de protocole comme gérer GET, envoyer HTTP 200, etc.


33
OpenBSD netcat fonctionne différemment, vous pouvez faire quelque chose commewhile true; do echo -e "HTTP/1.1 200 OK\n\n $(date)" | nc -l localhost 1500; done
matlehmann

2
De man for nc , -p description:It is an error to use this option in conjunction with the -l option
sbeliakov

1
La combinaison -l -p vient de la question et semble fonctionner pour l'auteur de la question. Je ne l'ai donc pas remis en question, mais je l'ai utilisé.
Constantin Berhard

2
Bien que la page de manuel nc que je vois indique également que l'utilisation de l' -poption avec celle- -lci est une erreur, le site Web officiel de netcat utilise les deux options dans ses exemples. Voir: nc110.sourceforge.net
LS

2
Il existe au moins 3 «saveurs» principales de nc: Hobbit (l'original), BSD / Mac OS X et GNU (le plus ancien du groupe, et n'est plus maintenu). Il y a aussi Ncat de Nmap . J'évoque cela parce que je pense qu'il vaut la peine de noter que les indicateurs -let -pensemble ne sont considérés comme une erreur que dans la saveur BSD de nc, d'où la syntaxe alternative donnée par @matlehmann
Mark G.

39

Donno comment ou pourquoi mais j'arrive à trouver ça autour et ça marche pour moi, j'ai eu le problème que je voulais retourner le résultat de l'exécution d'un bash

$ while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; sh test; } | nc -l 8080; done

REMARQUE: Cette commande est tirée de: http://www.razvantudorica.com/08/web-server-in-one-line-of-bash

cela exécute le test de script bash et renvoie le résultat à un navigateur client se connectant au serveur exécutant cette commande sur le port 8080

Mon script fait ce guichet automatique

$ 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)"

et mon navigateur Web affiche

************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   |
+----------+------+------+--------+------+-------+

simplement extraordinaire!


2
mieux vaut faire http 1.0 parce que http 1.1 vient d'ajouter une connexion: keep-alive qui est mauvais dans ce cas.
Shimon Doodkin

3
@ShimonDoodkin Ce serait inutile, car netcat ne comprend pas HTTP. Vous activez keep-alive dans netcat en passant l' -kindicateur, pas en l'ajoutant Connection: keep-aliveà l'en-tête de la demande.
Braden Best

1
Fonctionne également sur la version bizarre de nc sur Mac :)
judepereira

28

Ajoutez -q 1à la netcatligne de commande:

while true; do 
  echo -e "HTTP/1.1 200 OK\n\n $(date)" | nc -l -p 1500 -q 1
done

3
-q1 ne fonctionne pas dans CentOS6.x ce qui devrait être utilisé pour CentOS6.x où il dit: nc: invalid option -- 'q'. while true; do tail -f /usr/local/freeswitch/log/freeswitch.log | nc -l 9999; done &

@YumYumYum Je suis sous OS X et je n'ai pas de freeswitch. Quel est le contenu de /usr/local/freeswitch/log/freeswitch.log?
HairOfTheDog

3
L'ajout a -q 1fonctionné pour moi sur Ubuntu 18.04. J'espère que cela pourra aider.
EmpathicSage

20

Le problème auquel vous êtes confronté est que nc ne sait pas quand le client Web en a terminé avec sa demande pour pouvoir y répondre.
Une session Web devrait ressembler à quelque chose comme ça.

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.

Les lignes qui commencent par "\ n" sont simplement des lignes vides sans même espace et ne contiennent rien de plus qu'un caractère de nouvelle ligne.

J'ai mon bash httpd lancé par xinetd, tutoriel xinetd . Il enregistre également la date, l'heure, l'adresse IP du navigateur et l'ensemble de la demande du navigateur dans un fichier journal, et calcule Content-Length pour la réponse d'en-tête du serveur.

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"

Pour ajouter plus de fonctionnalités, vous pouvez intégrer.

            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

Bon coup!


11

J'avais le même besoin / problème mais rien ici n'a fonctionné pour moi (ou je n'ai pas tout compris), c'est donc ma solution.

Je poste mon minimal_http_server.sh (travaillant avec mon / bin / bash (4.3.11) mais pas / bin / sh à cause de la redirection):

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

Et mon a_script.sh (avec votre besoin):

#!/bin/bash

echo -e "HTTP/1.1 200 OK\r"
echo "Content-type: text/html"
echo

date

Après avoir exécuté le minimal_http_server.sh lorsque nous interrogeons l'URL plusieurs fois en 1 seconde, il affiche la page introuvable. Mais lorsque nous donnons un intervalle de 1 seconde pour chaque requête, cela fonctionne bien. Nous avons également remarqué que lorsque nous maintenons ce service en cours d'exécution et que nous avons une requête curl d'un autre script shell, le service tombe en panne ou se bloque. N'importe quelle idée de ce qui peut être faux
Satish John

@satishjohn De mes compétences actuelles (meilleures qu'à l'époque), je viens de corriger deux défauts majeurs ( readet tr) et un mineur ( [suivant elif). Je ne reproduis pas votre problème. Je ne vois pas pourquoi le minimal_http_server.sh provoquerait ces intervalles de 1 seconde. Vous pouvez déterminer si c'est minimal_http_server.sh ou votre "a_script.sh" qui est défectueux en exécutant plusieurs fois (au même rythme que vos requêtes curl) ./a_script.sh après avoir défini la variable d'environnement REQUEST.
syme

11

Une autre façon de faire cela

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

Testons-le avec 2 requêtes HTTP utilisant curl

Dans cet exemple, 172.16.2.6 est l'adresse IP du serveur.

Du côté serveur

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:
*/*

Côté client

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 vous souhaitez exécuter une autre commande, n'hésitez pas à remplacer $ (date).


6
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

Comment ça marche? read line<pipeattendra quenc écrire dans pipe? Mais à ce stade, je pense que la demande est faite avant que la réponse ne soit écrite ..?
fentas

mkfifo crée un tube de blocage, ce qui signifie que les commandes d'écho ne seront pas exécutées tant que nc n'aura pas lu une requête.
InvisibleWolf

5

Voici une beauté d' un petit serveur Web bash , je l'ai trouvé en ligne et ai fourché une copie et je l'ai un peu amélioré - il l'utilise socatou netcatje l'ai testé avec socat- il est autonome dans un script et génère son propre fichier de configuration et favicon.

Par défaut, il démarrera en tant que navigateur de fichiers compatible Web tout en étant facilement configuré par le fichier de configuration pour toute logique. Pour les fichiers, il diffuse des images et de la musique (mp3), des vidéos (mp4, avi, etc.) - J'ai testé différents types de fichiers en streaming sur des appareils Linux, Windows et Android, y compris une smartwatch!

Je pense que cela diffuse mieux que VLC en fait. Je l'ai trouvé utile pour transférer des fichiers vers des clients distants qui n'ont pas d'accès au-delà d'un navigateur Web, par exemple une smartwatch Android, sans avoir à se soucier de la connexion physique à un port USB.

Si vous voulez l'essayer, copiez-le et collez-le dans un fichier nommé bashttpd, puis démarrez-le sur l'hôte avec $> bashttpd -s

Ensuite, vous pouvez aller sur n'importe quel autre ordinateur (en supposant que le pare-feu ne bloque pas les connexions TCP entrantes vers le port 8080 - le port par défaut, vous pouvez changer le port en ce que vous voulez en utilisant les variables globales en haut du 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 <avleen@gmail.com>
### 
### 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 

Comment modifieriez-vous cela pour accepter POST ainsi que GET?
Adam Dymitruk

@Adam Dymitruk Vous auriez à ajouter de la logique pour gérer les demandes de publication (pas si difficile), voici un lien vers le dernier code source, regardez dans la mainfonction où il est dit [ "${REQUEST_METHOD}" = "GET" ] || fail_with 405: github.com/AdamDanischewski/bashttpd/blob/master/bashttpd

4

LOL, un hack super boiteux, mais au moins curl et firefox l'accepte:

while true ; do (dd if=/dev/zero count=10000;echo -e "HTTP/1.1\n\n $(date)") | nc -l  1500  ; done

Vous feriez mieux de le remplacer bientôt par quelque chose de convenable!

Ah oui, les miens ncn'étaient pas exactement les mêmes que les vôtres, il n'aimait pas l' -poption.


1
Cette réponse fonctionne avec netcat sur OS X 10.10.1. Super génial!
HairOfTheDog

4

Si vous utilisez Apline Linux, le netcat BusyBox est légèrement différent:

while true; do nc -l -p 8080 -e sh -c 'echo -e "HTTP/1.1 200 OK\n\n$(date)"'; done

2

Tapez nc -h et voyez si vous avez l' option -e disponible. Si oui, vous pouvez créer un script, par exemple:

script.sh

echo -e "HTTP/1.1 200 OK\n\n $(date)"

et exécutez-le comme ceci:

while true ; do nc -l -p 1500 -e script.sh; done

Notez que l' option -e doit être activée lors de la compilation pour être disponible.


1

Je pense que le problème que toute la solution répertoriée ne fonctionne pas, est intrinsèque à la nature du service http, chaque demande établie est avec un client différent et la réponse doit être traitée dans un contexte différent, chaque demande doit créer un nouveau instance de réponse ...

La solution actuelle que je pense est la -ede netcatmais je ne sais pas pourquoi ne fonctionne pas ... c'est peut-être ma ncversion sur laquelle je teste openwrt...

avec socatça marche ...

J'essaye ceci https://github.com/avleen/bashttpd

et cela fonctionne, mais je dois exécuter le script shell avec cette commande.

socat tcp-l:80,reuseaddr,fork EXEC:bashttpd &

Les échantillons socatet netcatsur github ne fonctionnent pas pour moi, mais ceux socatque j'ai utilisés fonctionnent.


avec reuseaddrdrapeau tu as fait ma journée! MERCI
WBAR

1

En fait, la meilleure façon de fermer correctement la connexion est d'envoyer l'en- Content-Lengthtête comme suit. Client (comme curlfermera la connexion après avoir reçu les données.

DATA="Date: $(date)"; 
LENGTH=$(echo $DATA | wc -c);
echo -e "HTTP/1.1 200 OK\nContent-Length: ${LENGTH}\n\n${DATA}" | nc -l -p 8000;
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.