Minimaler Webserver mit Netcat

129

Ich versuche, mit netcat (nc) einen minimalen Webserver einzurichten. Wenn der Browser beispielsweise localhost: 1500 aufruft, sollte er das Ergebnis einer Funktion anzeigen ( Datum im folgenden Beispiel, aber schließlich handelt es sich um ein Python- oder c-Programm, das einige Daten liefert). Mein kleiner Netcat-Webserver muss eine echte Bash-Schleife sein, möglicherweise so einfach:

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

Wenn ich dies versuche, zeigt der Browser die aktuell verfügbaren Daten in dem Moment an, in dem nc startet. Ich möchte, dass der Browser die Daten in dem Moment anzeigt, in dem der Browser sie anfordert. Wie kann ich das erreichen?

andwagon
quelle
Vielen Dank an alle für die Vorschläge, die mich zu etwas mehr googeln geführt haben. Zufällig bin ich bei link auf eine völlig andere Lösung gestoßen . Ich kann weder Python noch C verwenden, habe es jedoch bereits auf allen meinen Zielplattformen getestet. Das Problem mit Netcat ist, dass es so viele verschiedene Versionen gibt. Einige von ihnen erlauben keine Optionen -e, -c oder -q.
andwagon

Antworten:

51

Versuche dies:

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

Die -cMarken NETcat den gegebenen Befehl in einer Shell ausführen, so dass Sie Echo verwenden können. Wenn Sie kein Echo benötigen, verwenden Sie -e. Weitere Informationen hierzu finden Sie unter man nc. Beachten Sie, dass echoIhr Programm (die dateErsetzung) bei Verwendung keine Möglichkeit hat , die Browseranforderung abzurufen. Sie möchten also wahrscheinlich endlich so etwas tun:

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

Wo yourprogrammuss das Protokoll erledigt werden, z. B. GET handhaben, HTTP 200 senden usw.

Constantin Berhard
quelle
33
OpenBSD Netcat funktioniert anders, Sie können so etwas tunwhile true; do echo -e "HTTP/1.1 200 OK\n\n $(date)" | nc -l localhost 1500; done
Matlehmann
2
Vom Mann für nc , -p Beschreibung:It is an error to use this option in conjunction with the -l option
sbeliakov
1
Die Kombination -l -p stammt aus der Frage und scheint für den Autor der Frage zu funktionieren. Also habe ich es nicht in Frage gestellt, sondern benutzt.
Constantin Berhard
2
Obwohl die nc-Manpage, die ich sehe, auch besagt, dass die Verwendung der -pOption zusammen mit der -leinen Fehler ist, verwendet die offizielle Netcat-Website in ihren Beispielen beide Optionen. Siehe: nc110.sourceforge.net
LS
2
Es gibt mindestens drei Hauptvarianten nc: Hobbit (das Original), BSD / Mac OS X und GNU (das älteste der Reihe und nicht mehr gewartet). Es gibt auch Nmaps Ncat . Ich spreche das an, weil ich denke, dass es erwähnenswert ist, dass die -lund -pFlags zusammen nur als Fehler in der BSD- Variante von nc angesehen werden, daher die alternative Syntax von @matlehmann
Mark G.
39

Donno wie oder warum, aber ich schaffe es, dies zu finden und es funktioniert für mich. Ich hatte das Problem, dass ich das Ergebnis der Ausführung einer Bash zurückgeben wollte

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

HINWEIS: Dieser Befehl stammt von: http://www.razvantudorica.com/08/web-server-in-one-line-of-bash

Dadurch wird ein Bash-Skript-Test ausgeführt und das Ergebnis an einen Browser-Client zurückgegeben, der eine Verbindung zum Server herstellt, auf dem dieser Befehl an Port 8080 ausgeführt wird

Mein Skript macht diesen Geldautomaten

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

und mein Webbrowser wird angezeigt

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

einfach unglaublich!

maco1717
quelle
2
Machen Sie besser http 1.0, weil http 1.1 nur eine Verbindung hinzufügt: Keep-Alive, das ist in diesem Fall schlecht.
Shimon Doodkin
3
@ShimonDoodkin Das wäre sinnlos, da Netcat HTTP nicht versteht. Sie aktivieren Keep-Alive in Netcat, indem Sie das -kFlag übergeben und nicht Connection: keep-alivezum Anforderungsheader hinzufügen .
Braden Best
1
Funktioniert auch mit der seltsamen NC-Version auf dem Mac :)
Judepereira
28

In -q 1in die netcatBefehlszeile ein :

while true; do 
  echo -e "HTTP/1.1 200 OK\n\n $(date)" | nc -l -p 1500 -q 1
done
Ansgar Wiechers
quelle
3
-q1 funktioniert nicht in CentOS6.x, was für CentOS6.x verwendet werden soll, wo es heißt : nc: invalid option -- 'q'. while true; do tail -f /usr/local/freeswitch/log/freeswitch.log | nc -l 9999; done &
@YumYumYum Ich bin unter OS X und habe keinen Freischalter. Was ist der Inhalt von /usr/local/freeswitch/log/freeswitch.log?
HairOfTheDog
3
Das Hinzufügen -q 1funktionierte für mich unter Ubuntu 18.04. Hoffentlich hilft das.
EmpathicSage
20

Das Problem, mit dem Sie konfrontiert sind, ist, dass nc nicht weiß, wann der Webclient mit seiner Anfrage fertig ist, damit er auf die Anfrage antworten kann.
Eine Websitzung sollte ungefähr so ​​aussehen.

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.

Zeilen, die mit "\ n" beginnen, sind einfach leere Zeilen ohne Leerzeichen und enthalten lediglich ein neues Zeilenzeichen.

Ich habe meine Bash httpd von xinetd, xinetd Tutorial gestartet . Außerdem werden Datum, Uhrzeit, Browser-IP-Adresse und die gesamte Browseranforderung in einer Protokolldatei protokolliert und die Inhaltslänge für die Server-Header-Antwort berechnet.

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"

Um weitere Funktionen hinzuzufügen, können Sie diese integrieren.

            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

Viel Spaß beim Bashing!

Keith Reynolds
quelle
11

Ich hatte das gleiche Bedürfnis / Problem, aber hier hat nichts für mich funktioniert (oder ich habe nicht alles verstanden), also ist dies meine Lösung.

Ich poste meine minimal_http_server.sh (arbeite mit meiner / bin / bash (4.3.11), aber nicht mit / bin / sh wegen der Umleitung):

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

Und meine a_script.sh (mit Ihrem Bedarf):

#!/bin/bash

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

date
Syme
quelle
Nach dem Ausführen der Datei minimal_http_server.sh wird die Seite nicht gefunden, wenn die URL innerhalb von 1 Sekunde mehrmals abgefragt wird. Wenn wir jedoch für jede Anforderung ein Intervall von 1 Sekunde angeben, funktioniert dies einwandfrei. Beachten Sie auch, dass der Dienst ausfällt oder abstürzt, wenn wir diesen Dienst weiter ausführen und eine Curl-Anforderung von einem anderen Shell-Skript erhalten. Irgendeine Idee, was falsch sein könnte
satish john
@satishjohn Von meinen derzeitigen Fähigkeiten (besser als zu der Zeit) habe ich gerade zwei Hauptfehler ( readund tr) und einen [Nebenfehler ( nach elif) korrigiert. Ich reproduziere dein Problem nicht. Ich verstehe nicht, warum die Datei minimal_http_server.sh diese 1-Sekunden-Intervalle verursachen würde. Sie können feststellen, ob minimal_http_server.sh oder Ihr "a_script.sh" fehlerhaft ist, indem Sie es mehrmals ausführen (mit der gleichen Geschwindigkeit wie Ihre Curl-Anforderungen) ./a_script.sh, nachdem Sie die Umgebungsvariable REQUEST festgelegt haben.
Syme
11

Ein anderer Weg, dies zu tun

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

Testen wir es mit 2 HTTP-Anfragen mit Curl

In diesem Beispiel ist 172.16.2.6 die Server-IP-Adresse.

Serverseite

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

Client-Seite

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:~$

Wenn Sie einen anderen Befehl ausführen möchten, können Sie $ (Datum) ersetzen.

Charlotte Russell
quelle
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
eeeyes
quelle
wie funktioniert es? read line<pipewird warten bis ncwird schreiben pipe? Aber an diesem Punkt würde ich denken, dass die Anfrage erledigt ist, bevor die Antwort geschrieben wird ..?
Fentas
mkfifo erstellt eine blockierende Pipe, was bedeutet, dass Echo-Befehle erst ausgeführt werden, wenn nc eine Anforderung liest.
InvisibleWolf
5

Hier ist die Schönheit eines kleinen Bash-Webservers . Ich habe ihn online gefunden und eine Kopie gegabelt und ein wenig aufgepeppt - er verwendet socatoder netcatich habe ihn getestetsocat - er ist in einem Skript enthalten und generiert eine eigene Konfigurationsdatei und Favicon.

Standardmäßig wird es als webfähiger Dateibrowser gestartet, kann jedoch von der Konfigurationsdatei problemlos für jede Logik konfiguriert werden. Für Dateien werden Bilder und Musik (MP3s), Videos (MP4s, AVI usw.) gestreamt. Ich habe das Streaming verschiedener Dateitypen auf Linux-, Windows- und Android-Geräte getestet, einschließlich einer Smartwatch!

Ich denke, es strömt besser als VLC. Ich fand es nützlich, um Dateien auf Remote-Clients zu übertragen, die keinen Zugriff über einen Webbrowser hinaus haben, z. B. Android Smartwatch, ohne sich um die physische Verbindung mit einem USB-Anschluss kümmern zu müssen.

Wenn Sie es ausprobieren möchten, kopieren Sie es einfach und fügen Sie es in eine Datei mit dem Namen bashttpd ein. Starten Sie es dann auf dem Host mit $> bashttpd -s

Dann können Sie zu jedem anderen Computer wechseln (vorausgesetzt, die Firewall blockiert keine eingehenden TCP-Verbindungen zu Port 8080 - dem Standardport können Sie den Port mithilfe der globalen Variablen oben im Skript nach Belieben ändern). 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 
Janus Troelsen
quelle
Wie würden Sie dies ändern, um sowohl POST als auch GET zu akzeptieren?
Adam Dymitruk
@Adam Dymitruk Sie müssten Logik hinzufügen, um Post-Anfragen zu bearbeiten (nicht so schwer). Hier ist ein Link zum neuesten Quellcode. Schauen Sie in die mainFunktion, in der es heißt [ "${REQUEST_METHOD}" = "GET" ] || fail_with 405: github.com/AdamDanischewski/bashttpd/blob/master/bashttpd
4

LOL, ein super lahmer Hack, aber zumindest Curl und Firefox akzeptieren ihn:

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

Ersetzen Sie es besser bald durch etwas Richtiges!

Ah ja, meine ncwaren nicht genau die gleichen wie deine, die -pOption gefiel mir nicht .

Mogul
quelle
1
Diese Antwort funktioniert mit Netcat unter OS X 10.10.1. Sehr toll!
HairOfTheDog
4

Wenn Sie Apline Linux verwenden, unterscheidet sich der BusyBox-Netcat geringfügig:

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

Geben Sie in nc h und sehen , ob Sie haben -e verfügbare Option. Wenn ja, können Sie ein Skript erstellen, zum Beispiel:

script.sh

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

und führen Sie es so aus:

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

Beachten Sie, dass die Option -e bei der Kompilierung aktiviert sein muss, um verfügbar zu sein.

Majkel
quelle
1

Ich denke, das Problem, dass alle aufgelisteten Lösungen nicht funktionieren, liegt in der Natur des http-Dienstes, jede eingerichtete Anfrage hat einen anderen Client und die Antwort muss in einem anderen Kontext verarbeitet werden, jede Anfrage muss eine neue geben Instanz der Antwort ...

Die aktuelle Lösung, von der ich denke, ist die -evon, netcataber ich weiß nicht, warum sie nicht funktioniert. Vielleicht ist es meine ncVersion, auf der ich testeopenwrt ...

mit socat es funktioniert ....

Ich versuche dies https://github.com/avleen/bashttpd

und es funktioniert, aber ich muss das Shell-Skript mit diesem Befehl ausführen.

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

Das socatund netcatSamples auf Github funktioniert bei mir nicht, aber das socat, was ich verwendet habe, funktioniert.

Amerigo Stevani
quelle
mit reuseaddrFlagge hast du meinen Tag gemacht! DANKE
WBAR
1

Der beste Weg, um die Verbindung ordnungsgemäß zu schließen, besteht darin, den Content-LengthHeader wie folgt zu senden . Client (wie curlschließt die Verbindung nach dem Empfang der Daten.

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;
user1067920
quelle