Máy chủ web tối thiểu sử dụng netcat


129

Tôi đang cố gắng thiết lập một máy chủ web tối thiểu bằng netcat (nc). Ví dụ, khi trình duyệt gọi localhost: 1500, nó sẽ hiển thị kết quả của một hàm ( ngày trong ví dụ bên dưới, nhưng cuối cùng nó sẽ là một chương trình python hoặc c mang lại một số dữ liệu). Máy chủ web netcat nhỏ của tôi cần phải là một vòng lặp thực sự trong bash, có thể đơn giản như thế này:

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

Khi tôi thử điều này, trình duyệt hiển thị dữ liệu hiện có trong thời điểm nc bắt đầu. Tuy nhiên, tôi muốn trình duyệt hiển thị dữ liệu trong thời điểm trình duyệt yêu cầu. Làm thế nào tôi có thể đạt được điều này?


Cảm ơn tất cả mọi người vì những gợi ý dẫn tôi đến một số người khác. Khi nó xảy ra, tôi đã gặp một giải pháp hoàn toàn khác tại liên kết . Tôi không thể sử dụng python hoặc C, nhưng tôi đã thử nghiệm nó trên tất cả các nền tảng mục tiêu của mình. Rắc rối với netcat là có rất nhiều phiên bản khác nhau xung quanh. Một số trong số họ không cho phép tùy chọn -e, -c hoặc -q.
andwagon

Câu trả lời:


51

Thử cái này:

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

Làm -ccho netcat thực thi lệnh đã cho trong một shell, vì vậy bạn có thể sử dụng echo. Nếu bạn không cần tiếng vang, hãy sử dụng -e. Để biết thêm thông tin về điều này, hãy thử man nc. Lưu ý rằng khi sử dụng echo, không có cách nào để chương trình của bạn (vị trí datethay thế) nhận được yêu cầu trình duyệt. Vì vậy, cuối cùng bạn có thể muốn làm một cái gì đó như thế này:

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

Trường hợp yourprogramphải thực hiện các công cụ giao thức như xử lý GET, gửi HTTP 200, v.v.


33
OpenBSD netcat hoạt động khác nhau, bạn có thể làm một cái gì đó nhưwhile true; do echo -e "HTTP/1.1 200 OK\n\n $(date)" | nc -l localhost 1500; done
matlehmann

2
Từ người đàn ông cho nc , mô tả -p:It is an error to use this option in conjunction with the -l option
sbeliakov

1
Sự kết hợp -l -p xuất phát từ câu hỏi và dường như có tác dụng đối với tác giả của câu hỏi. Vì vậy, tôi đã không hỏi nó, nhưng sử dụng nó.
Constantin Berhard

2
Mặc dù trang nc tôi thấy cũng nói rằng việc sử dụng -ptùy chọn cùng với -lmột lỗi là một lỗi, trang web netcat chính thức sử dụng cả hai tùy chọn trong các ví dụ của nó. Xem: nc110.sourceforge.net
LS

2
Có ít nhất 3 hương vị chính của người Viking về nc: Hobbit (bản gốc), BSD / Mac OS XGNU (bản cũ nhất trong nhóm, và không còn được duy trì). Ngoài ra còn có Ncat của Nmap . Tôi đưa ra điều này bởi vì tôi nghĩ rằng đáng chú ý rằng các cờ -l-pcờ cùng nhau chỉ được coi là một lỗi trong hương vị BSD của nc, do đó cú pháp thay thế được đưa ra bởi @matlehmann
Mark G.

39

Donno làm thế nào hoặc tại sao nhưng tôi quản lý để tìm thấy điều này xung quanh và nó hoạt động với tôi, tôi có vấn đề tôi muốn trả lại kết quả của việc thực hiện một bash

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

LƯU Ý: Lệnh này được lấy từ: http://www.razaugeudorica.com/08/web-server-in-one-line-of-bash

điều này thực thi kiểm tra tập lệnh bash và trả kết quả cho máy khách trình duyệt kết nối với máy chủ đang chạy lệnh này trên cổng 8080

Kịch bản của tôi làm ATM này

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

và trình duyệt web của tôi đang hiển thị

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

đơn giản là tuyệt vời!


2
tốt hơn nên làm http 1.0 vì http 1.1 chỉ cần thêm kết nối: giữ nguyên tình trạng xấu trong trường hợp này.
Shimon Doodkin

3
@ShimonDoodkin Điều đó là vô nghĩa, vì netcat không hiểu HTTP. Bạn kích hoạt keep-live trong netcat bằng cách chuyển -kcờ, không phải bằng cách thêm Connection: keep-alivevào tiêu đề yêu cầu.
Braden hay nhất

1
Hoạt động trên phiên bản nc kỳ lạ trên Mac cũng vậy :)
judepereira

28

Thêm -q 1vào netcatdòng lệnh:

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

3
-q1 không hoạt động trong CentOS6.x nên sử dụng cái gì cho CentOS6.x khi nó nói : nc: invalid option -- 'q'. while true; do tail -f /usr/local/freeswitch/log/freeswitch.log | nc -l 9999; done &

@YumYumYum Tôi đang dùng OS X và không có freeswitch. Nội dung của là /usr/local/freeswitch/log/freeswitch.loggì?
HairOfTheDog

3
Thêm -q 1công việc cho tôi trên Ubuntu 18.04. Mong rằng sẽ giúp.
EmpathicSage

20

Vấn đề bạn gặp phải là nc không biết khi nào máy khách được thực hiện với yêu cầu của nó để nó có thể đáp ứng yêu cầu.
Một phiên web nên đi một cái gì đó như thế này.

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.

Các dòng bắt đầu bằng "\ n" chỉ đơn giản là các dòng trống thậm chí không có khoảng trắng và không chứa gì nhiều hơn một ký tự dòng mới.

Tôi có bash httpd của tôi được khởi chạy bởi xinetd, hướng dẫn xinetd . Nó cũng ghi nhật ký ngày, thời gian, địa chỉ IP của trình duyệt và toàn bộ yêu cầu trình duyệt vào một tệp nhật ký và tính toán Độ dài nội dung cho phản hồi tiêu đề Máy chủ.

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"

Để thêm nhiều chức năng, bạn có thể kết hợp.

            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

Chúc mừng sinh nhật!


11

Tôi có cùng nhu cầu / vấn đề nhưng không có gì ở đây làm việc cho tôi (hoặc tôi không hiểu mọi thứ), vì vậy đây là giải pháp của tôi.

Tôi đăng Minimal_http_server.sh của tôi (làm việc với / bin / bash (4.3.11) nhưng không / bin / sh vì chuyển hướng):

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

Và a_script.sh của tôi (với nhu cầu của bạn):

#!/bin/bash

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

date

Sau khi chạy Minimal_http_server.sh khi chúng tôi truy vấn url nhiều lần trong vòng 1 giây, nó sẽ hiển thị trang không tìm thấy. Nhưng khi chúng tôi đưa ra khoảng thời gian 1 giây cho mỗi yêu cầu thì nó hoạt động tốt. Cũng lưu ý rằng khi chúng tôi giữ dịch vụ này chạy và có yêu cầu cuộn tròn từ một tập lệnh shell khác, dịch vụ sẽ bị hỏng hoặc gặp sự cố. Bất cứ ý tưởng nào có thể sai
satish john

@satishjohn Từ những kỹ năng hiện tại của tôi (tốt hơn so với thời điểm đó), tôi vừa sửa hai khuyết điểm lớn ( readtr) và một lỗi nhỏ ( [sau elif). Tôi không tái tạo vấn đề của bạn. Tôi không thấy lý do tại sao Minimal_http_server.sh sẽ gây ra các khoảng thời gian 1 giây này. Bạn có thể xác định xem đó là Minimal_http_server.sh hoặc "a_script.sh" của bạn bị lỗi bằng cách chạy nhiều lần (với cùng tốc độ với các yêu cầu curl của bạn) ./a_script.sh sau khi đặt biến môi trường REQUEST.
Syme

11

Một cách khác để làm điều này

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

Hãy thử nghiệm nó với 2 yêu cầu HTTP bằng cách sử dụng curl

Trong ví dụ này, 172.16.2.6 là Địa chỉ IP của máy chủ.

Phía máy chủ

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

Phía khách hàng

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

Nếu bạn muốn thực thi một lệnh khác, vui lòng thay thế $ (ngày).


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

làm thế nào nó hoạt động? read line<pipeSẽ đợi đến khi nào ncsẽ viết vào pipe? Nhưng tại thời điểm này, tôi sẽ nghĩ rằng yêu cầu được thực hiện trước khi phản hồi được viết ..?
fentas

mkfifo tạo ra một đường ống chặn, điều đó có nghĩa là các lệnh echo sẽ không được thực thi cho đến khi nc đọc một yêu cầu.
InvisibleWolf

5

Đây là một nét đẹp của một máy chủ web bash nhỏ , tôi tìm thấy nó trực tuyến và chia một bản sao và tạo ra một chút - nó sử dụng socathoặc netcattôi đã thử nghiệm nó socat- nó được chứa trong một tập lệnh và tạo tệp cấu hình của riêng nó và favicon.

Theo mặc định, nó sẽ khởi động như một trình duyệt tệp kích hoạt web nhưng được cấu hình dễ dàng bởi tệp cấu hình cho bất kỳ logic nào. Đối với các tệp, nó truyền hình ảnh và âm nhạc (mp3), video (mp4, avi, v.v.) - Tôi đã thử nghiệm truyền các loại tệp khác nhau đến các thiết bị Linux, Windows và Android bao gồm cả smartwatch!

Tôi nghĩ rằng nó truyền phát tốt hơn VLC thực sự. Tôi đã thấy hữu ích khi chuyển tệp đến các máy khách từ xa không có quyền truy cập ngoài trình duyệt web, ví dụ như smartwatch Android mà không cần phải lo lắng về việc kết nối vật lý với cổng USB.

Nếu bạn muốn dùng thử, chỉ cần sao chép và dán nó vào một tệp có tên bashttpd, sau đó khởi động nó trên máy chủ với $> bashttpd -s

Sau đó, bạn có thể truy cập vào bất kỳ máy tính nào khác (giả sử tường lửa không chặn các kết nối tcp gửi đến cổng 8080 - cổng mặc định, bạn có thể thay đổi cổng thành bất cứ điều gì bạn muốn bằng cách sử dụng các biến toàn cục ở đầu tập lệnh). 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 

Làm thế nào bạn sẽ sửa đổi điều này để chấp nhận POST cũng như GET?
Adam Dymitruk

@Adam Dymitruk Bạn sẽ phải thêm logic để xử lý các yêu cầu Đăng (không khó lắm), đây là một liên kết đến mã nguồn mới nhất, hãy tìm trong mainhàm có ghi [ "${REQUEST_METHOD}" = "GET" ] || fail_with 405: github.com/AdamDanischewski/bashttpd/blob/master/bashttp

4

LOL, một bản hack siêu khập khiễng, nhưng ít nhất là curl và firefox chấp nhận nó:

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

Bạn nên thay thế nó sớm bằng một cái gì đó thích hợp!

À đúng rồi, người sói của tôi nckhông giống hệt bạn, nó không thích -ptùy chọn này.


1
Câu trả lời này hoạt động với netcat trên OS X 10.10.1. Siêu tuyệt vời!
HairOfTheDog

4

Nếu bạn đang sử dụng Apline Linux, netcat BusyBox hơi khác một chút:

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

2

Nhập vào nc -h và xem nếu bạn có sẵn tùy chọn -e . Nếu có, bạn có thể tạo một tập lệnh, ví dụ:

script.sh

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

và chạy nó như thế này:

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

Lưu ý rằng tùy chọn -e cần được bật khi biên dịch có sẵn.


1

Tôi nghĩ rằng vấn đề mà tất cả các giải pháp được liệt kê không hoạt động, là bản chất của dịch vụ http, mọi yêu cầu được thiết lập là với một khách hàng khác nhau và phản hồi cần được xử lý trong một bối cảnh khác nhau, mọi yêu cầu phải rẽ nhánh mới ví dụ phản hồi ...

Giải pháp hiện tại tôi nghĩ là -ecủa netcatnhưng tôi không biết tại sao nó không hoạt động ... có thể là ncphiên bản của tôi mà tôi đã thử nghiệmopenwrt ...

với socatnó hoạt động ....

Tôi dùng thử https://github.com/avleen/bashttpd

và nó hoạt động, nhưng tôi phải chạy script shell bằng lệnh này.

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

Các mẫu socatnetcatmẫu trên github không hoạt động với tôi, nhưng mẫu socatmà tôi đã sử dụng hoạt động.


với reuseaddrcờ bạn đã làm cho ngày của tôi! CẢM ƠN BẠN
WBAR

1

Trên thực tế, cách tốt nhất để đóng kết nối một cách duyên dáng là gửi Content-Lengthtiêu đề như sau. Khách hàng (thích curlsẽ đóng kết nối sau khi nhận được dữ liệu.

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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.