2013-05-19 1 views
62

Я пытаюсь настроить минимальный веб-сервер, используя netcat (nc). Например, когда браузер вызывает localhost: 1500, он должен показать результат функции (date в приведенном ниже примере, но в конечном итоге это будет программа python или c, которая даст некоторые данные). Мой маленький Netcat веб-сервер должен быть в то время как истинный цикл в Баш, возможно, так просто, как это:Минимальный веб-сервер с использованием netcat

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

Когда я пытаюсь это браузер показывает доступные в настоящее время данные в момент, когда начинается пс. Я хочу, чтобы браузер отображал данные в тот момент, когда браузер запрашивает его. Как я могу это достичь?

+0

Спасибо всем за предложения, которые приводят меня к еще большему поиску. Как это случилось, я нашел совершенно другое решение в [link] (http://www.emacswiki.org/emacs/EmacsEchoServer). Я не могу использовать python или C, но я уже тестировал его на всех моих целевых платформах. Проблема с netcat заключается в том, что вокруг существует так много разных версий. Некоторые из них не позволяют использовать параметры -e, -c или -q. – andwagon

ответ

2

LOL, супер хромой хак, но, по крайней мере, скручиваются и светлячок принимает его:

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

Вы лучше в ближайшее время заменить его чем-то правильное!

Ах да, мои nc были не такими же, как ваши, ему не понравилась опция -p.

+0

Этот ответ работает с netcat на OS X 10.10.1. Супер классно! – HairOfTheDog

11

Добавить -q 1 в netcat командной строки:

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

'-q' 1 не работает в' CentOS' 6.x, что нужно использовать для 'CentOS' 6.x, где он говорит:' nc: недействительный параметр - 'q''. 'while true; do tail -f /usr/local/freeswitch/log/freeswitch.log | nc -l 9999; done & ' – YumYumYum

+0

@YumYumYum Я нахожусь на OS X и не имею freeswitch. Каково содержимое '/ usr/local/freeswitch/log/freeswitch.log'? – HairOfTheDog

2

Тип в н.д. -h и посмотреть, если у Вас есть опция -e доступны. Если да, то вы можете создать сценарий, например:

script.sh

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

и запустить его так:

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

Обратите внимание, что -e опция должна быть включенным при компиляции.

15

Проблема, с которой вы сталкиваетесь, заключается в том, что nc не знает, когда веб-клиент выполнил свой запрос, чтобы он мог ответить на запрос.
Веб-сессия должна проходить примерно так.

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. 

Строка, начинающаяся с «\ п» являются просто пустыми строками даже без пространства и не содержит ничего, кроме новой строки.

У меня есть мой bash httpd, запущенный xinetd, xinetd tutorial. Он также регистрирует дату, время, IP-адрес браузера и весь запрос браузера к файлу журнала и вычисляет Content-Length для ответа заголовка сервера.

[email protected]:/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" 

Чтобы добавить дополнительную функциональность, вы можете включить.

  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 

Удачное избиение!

4
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 
+0

как это работает? 'read line fentas

27

Попробуйте это:

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

-c делает Netcat выполнить заданную команду в оболочке, так что вы можете использовать эхо. Если вам не нужно эхо, используйте -e. Для получения дополнительной информации об этом попробуйте man nc. Обратите внимание, что при использовании echo для вашей программы нет способа (date -replacement), чтобы получить запрос браузера. Таким образом, вы, вероятно, в конце концов хотите сделать что-то вроде этого:

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

Где yourprogram должны делать вещи, как протокол обработки GET, посылая HTTP 200 и т.д.

+19

OpenBSD netcat работает по-разному, вы можете сделать что-то вроде 'while true; do echo -e "HTTP/1.1 200 OK \ n \ n $ (date) "| nc -l localhost 1500; done' – matlehmann

+2

Из [man for nc] (https://linux.die.net/man/1/nc), -p описание: 'Ошибка использования этой опции в сочетании с опцией -l' – sbeliakov

+0

. Комбинация -l -p исходит из вопроса и, похоже, работает для автора вопроса. Поэтому я не стал подвергать сомнению его, но использовал его –

19

Donno, как и почему, но я смог найти это вокруг и это работает для меня, я была проблема, которую я хотел, чтобы вернуть результат выполнения Баш

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

Примечание: Эта команда была взята из: http://www.razvantudorica.com/08/web-server-in-one-line-of-bash

это выполняет тест Баш скрипт и возвращает результат клиенту браузера, подключенного к серверу выполнения этой команды на порт 8080

Мой скрипт делает этот банкомат

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

и мой веб-браузер показывает

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

просто потрясающе!

+2

лучше делать http 1.0, потому что http 1.1 просто добавляет соединение: keep-alive, что плохо в этом случае –

+1

@ShimonDoodkin Это было бы бессмысленно, так как netcat не понимает HTTP. keep-alive в netcat, передавая флаг '-k', а не добавляя' Connection: keep-alive' в заголовок запроса. –

+1

Работает над странной версией nc на Mac :) – judepereira

9

У меня была такая же проблема/проблема, но ничего здесь не работало для меня (или я не все понимал), так что это мое решение.

Я пост мой minimal_http_server.sh (работает с моим/бен/Баш (4.3.11), но не/бен/ш из-за перенаправления):

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 

И мой a_script.sh (с вашим потребность):

#!/bin/bash 

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

date 
+0

После запуска minimum_http_server.sh, когда мы запрашиваем URL-адрес несколько раз в течение 1 секунды, он отображает страницу не найдена. Но когда мы даем интервал в 1 секунду для каждого запроса, он работает нормально. Также было замечено, что, когда мы держим эту службу запущенной и имеем запрос на завиток из другого сценария оболочки, служба спускается или падает. Любая идея, что может быть неправильным –

+0

@satishjohn Из моих текущих навыков (лучше, чем в то время), я только что исправил два основных дефекта ('read' и' tr') и минор ('[' next elif). Я не воспроизвожу вашу проблему. Я не понимаю, почему минимальный_http_server.sh вызовет эти 1-й интервал. Вы можете определить, является ли это минимальным_http_server.sh или вашим «a_script.sh», который неисправен, если запустить несколько раз (с той же скоростью, что и ваши запросы на завивки) ./a_script.sh после установки переменной среды REQUEST. – syme

0

Я думаю, что проблема, что все решения перечисленная не работает, не является неотъемлемой частью природы HTTP-службы, каждый запрос Учрежденного с другим клиентом, и ответ должен быть обработан в в другом контексте, каждый запрос должен разблокировать новый экземпляр ответа ...

В настоящее время решение, я думаю, что это -e из netcat, но я не знаю, почему не работает ... Может быть, это моя nc версия, что я испытываю на openwrt ...

с socat он работает. ...

Я стараюсь это https://github.com/avleen/bashttpd

и она работает, но я должен запустить скрипт с этой командой.

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

В socat и netcat образцов на GitHub не работает для меня, но socat, что я использовал работу.

3

Вот красота a little bash webserver, я нашел его в Интернете и раздвоенный копию и нарядная его немного - он использует socat или netcat я тестировал с socat - это самодостаточный в одном-скрипта и генерирует его собственный файл конфигурации и значок.

По умолчанию он запускается как браузер с поддержкой веб-браузера, но его легко настроить конфигурационным файлом для любой логики. Для файлов он передает изображения и музыку (mp3), видео (mp4, avi и т. Д.). Я тестировал потоковое воспроизведение различных типов файлов на устройствах Linux, Windows и Android, включая smartwatch!

Я думаю, что это потоки лучше, чем VLC. Я нашел это полезным для передачи файлов удаленным клиентам, у которых нет доступа за пределами веб-браузера, например. Android smartwatch, не беспокоясь о физическом подключении к USB-порту.

Если вы хотите попробовать его просто скопировать и вставить его в файл с именем bashttpd, а затем запустить его на хосте с $> bashttpd -s

Затем вы можете перейти на любой другой компьютер (предполагая, что брандмауэр не блокирует входящие tcp-подключения к порту 8080 - порт по умолчанию, вы можете изменить порт на все, что хотите, используя глобальные переменные в верхней части скрипта). 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: [email protected]" >&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 "< [email protected]" >&2; } 

function send() { ((${VERBOSE})) && echo "> [email protected]" >&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 "[email protected]" 
    serve_dir_with_ls "[email protected]" 
    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}" "[email protected]" || fail_with 403 
    elif [[ -d "${URL_PATH}" ]]; then 
    [[ -x "${URL_PATH}" ]] && \ 
     serve_dir "${URL_PATH}" "[email protected]" || 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 ]] && \ 
    "[email protected]" "${BASH_REMATCH[@]}" 
} 

function unconditionally() { "[email protected]" "$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 
+0

Как вы могли бы изменить это, чтобы принять POST, а также GET? –

+0

@Adam Dymitruk Вам нужно будет добавить логику для обработки сообщений Post (не так сложно), вот ссылка на последний исходный код, посмотрите в функцию 'main', где он говорит' ["$ {REQUEST_METHOD}" = " GET "] || fail_with 405': https://github.com/AdamDanischewski/bashttpd/blob/master/bashttpd –

3

Другой способ сделать это

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 

Давайте протестируем его с запросом 2 HTTP с помощью завиток

В этом примере 172.16.2.6 является IP-адрес сервера.

Server Side

[email protected]:~$ 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 Side

[email protected]:~$ curl 172.16.2.6:8080 

     My website has date function 
     Tue Jun 13 18:00:19 UTC 2017 

[email protected]:~$ curl 172.16.2.6:8080 

     My website has date function 
     Tue Jun 13 18:00:24 UTC 2017 

[email protected]:~$ 

Если вы хотите, чтобы выполнить другую команду, не стесняйтесь заменить $ (дата).

Смежные вопросы