Запуск своих CGI на Wi-Fi-роутере TP-LINK TL-MR3020


Продолжим небольшое программное исследование Wi-Fi-роутера TP-LINK TL-MR3020 под управлением OR-WRT (редакция OpenWrt от робофорума).

Сначала посмотрим те конфигурационные файлы, которые я забыл показать в прошлой статье-исследовании.

login as: root
[email protected]'s password:


BusyBox v1.19.4 (2012-08-21 01:06:25 UTC) built-in shell (ash)
Enter 'help' for a list of built-in commands.

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
----------------------------------------------------------------------
   ____                       ____        __          __  _
  / __ \____  ___  ____      / __ \____  / /_  ____  / /_(_)__________
 / / / / __ \/ _ \/ __ \____/ /_/ / __ \/ __ \/ __ \/ __/ // ___/ ___/
/ /_/ / /_/ /  __/ / / /___/ _, _/ /_/ / /_/ / /_/ / /_/ // /__(__  )
\____/ .___/\___/_/ /_/   /_/ |_|\____/_.___/\____/\__/_/ \___/____/
    /_/
[email protected]:~#


# cat /etc/banner
  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
----------------------------------------------------------------------
   ____                       ____        __          __  _
  / __ \____  ___  ____      / __ \____  / /_  ____  / /_(_)__________
 / / / / __ \/ _ \/ __ \____/ /_/ / __ \/ __ \/ __ \/ __/ // ___/ ___/
/ /_/ / /_/ /  __/ / / /___/ _, _/ /_/ / /_/ / /_/ / /_/ // /__(__  )
\____/ .___/\___/_/ /_/   /_/ |_|\____/_.___/\____/\__/_/ \___/____/
    /_/
~# cat /etc/ser2net.conf
#
# This is an example configuration file for ser2net.  It has the following
# format:
#  ::::
#     TCP port
#            Name   or  number of the TCP/IP port to accept con-
#            nections from for this device.  A port number may
#            be of the form [host,]port, such as 127.0.0.1,2000
#            or localhost,2000.  If this is specified, it will
#            only bind to the IP address specified. Otherwise
#            it will bind to all the ports on the machine.
#
#     state  Either raw or rawlp or telnet or off.  off disables
#            the  port  from  accepting  connections.  It can be
#            turned on later from the control port.  raw enables
#            the port and  transfers  all data as-is between the
#            port  and  the long.  rawlp  enables  the port  and
#            transfers  all input data to device, device is open
#            without  any  termios  setting.  It  allow  to  use
#            /dev/lpX  devices  and  printers connected to them.
#            telnet enables the port and runs the telnet  proto-
#            col  on the port to set up telnet parameters.  This
#            is most useful for using telnet.
#
#     timeout
#            The time (in seconds) before the port will be  dis-
#            connected  if  there  is no activity on it.  A zero
#            value disables this function.
#
#     device The  name  of  the  device   to  connect  to.  This
#            must be in the form of /dev/.
#
#     options
#            Sets  operational  parameters  for the serial port.
#            Options 300, 1200, 2400, 4800, 9600, 19200, 38400,
#            57600, 115200 set the various baud rates.  EVEN,
#            ODD, NONE set the parity.  1STOPBIT, 2STOPBITS set
#            the number of stop bits.  7DATABITS, 8DATABITS set
#            the number of data bits.  [-]XONXOFF turns on (-
#            off) XON/XOFF support.  [-]RTSCTS turns on (- off)
#            hardware flow control, [-]LOCAL turns off (- on)
#            monitoring of the modem lines, and
#            [-]HANGUP_WHEN_DONE turns on (- off) lowering the
#            modem control lines when the connection is done.
#            NOBREAK disables automatic setting of the break
#            setting of the serial port.
#            The "remctl" option allow remote control (ala RFC
#            2217) of serial-port configuration.  A banner name
#            may also be specified, that banner will be printed
#            for the line.  If no banner is given, then no
#            banner is printed.
#            The tw, tr, and tb options take a tracefile name (
#            specified in TRACEFILE that will take all traced data.
#            tw is data written to the device, tr is data read from
#            the device, and tb is both.
#
# or...

#  BANNER::banner
#    This will create a banner, if the banner name is given in the
#    options of a line, that banner will be printed.  This takes the
#    standard "C" \x characters (\r is carraige return, \n is newline,
#    etc.).  It also accepts \d, which prints the device name, \p,
#    which prints the TCP port number, and \s which prints the serial
#    parameters (eg 9600N81).  Banners can span lines if the last
#    character on a line is '\'.  Note that you *must* use \r\n to
#    start a new line.
#
#  TRACEFILE::filename
#    This specifies a filename to trace output into, as tw:/tmp/trace1.
#    This takes a large number of escape sequences, see the man page
#    for details on these options.
#
# Note that the same device can be listed multiple times under different
# ports, this allows the same serial port to have both telnet and raw
# protocols.

BANNER:banner1:Welcome to ser2net TCP port \p device \d\r\n\
second line \
third line\r\n

BANNER:banner2:this is ser2net TCP port \p device \d\r\n\
second line \
third line\r\n

BANNER:banner3:this is ser2net TCP port \p device \d  serial parms \s\r\n

TRACEFILE:tw1:/tmp/tw-\p-\Y-\M-\D-\H:\i:\s.\U
TRACEFILE:tr1:/tmp/tr-\p-\Y-\M-\D-\H:\i:\s.\U

2000:raw:600:/dev/ttyATH0:115200 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS
3000:raw:600:/dev/ttyUSB0:115200 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS
3001:raw:600:/dev/ttyUSB1:115200 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS
3002:raw:600:/dev/ttyUSB2:115200 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS
3003:raw:600:/dev/ttyUSB3:115200 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS
3004:raw:600:/dev/ttyUSB4:115200 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS
3005:raw:600:/dev/ttyUSB5:115200 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS
#2002:raw:600:/dev/ttyS1:9600 NONE 1STOPBIT 8DATABITS XONXOFF LOCAL -RTSCTS
#2003:raw:5:/dev/ttyS2:9600
#2004:raw:5:/dev/ttyS3:115200
#2005:raw:5:/dev/ttyS4:9600
#2006:raw:5:/dev/ttyS5:9600
#2007:raw:5:/dev/ttyS6:9600 tw=tw1 tr=tr1
#3001:telnet:0:/dev/ttyS0:19200 remctl banner1
#3011:telnet:3:/dev/ttyS0:19200 banner2
#3002:telnet:0:/dev/ttyS1:9600
#3003:telnet:0:/dev/ttyS2:9600 banner3
#3004:telnet:0:/dev/ttyS3:115200
#3005:telnet:0:/dev/ttyS4:9600
#3006:telnet:0:/dev/ttyS5:9600
#3007:telnet:0:/dev/ttyS6:9600
#5001:rawlp:10:/dev/lp0
# netstat -ant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:2000            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:53              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:88              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:3000            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:3001            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:3002            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:3003            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:3004            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:3005            0.0.0.0:*               LISTEN
tcp        0    100 192.168.217.1:22        192.168.217.15:1324     ESTABLISHED
netstat: /proc/net/tcp6: No such file or directory
# mount
rootfs on / type rootfs (rw)
/dev/root on /rom type squashfs (ro,relatime)
proc on /proc type proc (rw,noatime)
sysfs on /sys type sysfs (rw,noatime)
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noatime)
tmpfs on /dev type tmpfs (rw,noatime,size=512k,mode=755)
devpts on /dev/pts type devpts (rw,noatime,mode=600)
/dev/mtdblock3 on /overlay type jffs2 (rw,noatime)
overlayfs:/overlay on / type overlayfs (rw,relatime,lowerdir=/,upperdir=/overlay)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
none on /proc/bus/usb type usbfs (rw,relatime)

Смотрим содержимое нашей веб-морды 🙂

# ls -asl /www/
     0 drwxr-xr-x    1 root     root             0 Jan  1 00:15 .
     0 drwxr-xr-x    1 root     root             0 Jan  1 00:00 ..
     0 drwxr-xr-x    2 root     root           112 May 27  2012 admin
     0 drwxr-xr-x    1 root     root             0 Jan  1 00:29 cgi-bin
     5 -rw-r--r--    1 root     root          4946 Jan  1  1970 index.html
     1 -rw-r--r--    1 root     root          1352 Jan  1 00:04 mylua.html
     0 -rw-r--r--    1 root     root            15 Jan  1  1970 nothing.html
     0 drwxr-xr-x    2 root     root            31 Nov 26  2011 res
     0 drwxr-xr-x    2 root     root           763 Sep  1  2012 webcam

# ls -asl /www/cgi-bin/
     0 drwxr-xr-x    1 root     root             0 Jan  1 00:29 .
     0 drwxr-xr-x    1 root     root             0 Jan  1 00:15 ..
     0 drwxr-xr-x    2 root     root           132 Aug 30  2012 admin
     1 -rwxr-xr-x    1 root     root          1284 Jan  1 00:23 mylua.cgi
     0 -rwxr-xr-x    1 root     root           202 Nov 26  2011 restart_webcam.cgi
     0 -rwxr-xr-x    1 root     root           367 May 27  2012 serial.cgi
     0 -rwxr-xr-x    1 root     root           251 Jan  1  1970 uptime
# cat /www/index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>OR-WIFI-ROBOT</title>
    <link rel="stylesheet" type="text/css" href="res/main.css"/>
    <script type="text/javascript">
        var lastTurn = -1;
        var lastPress = -1;
        var lastPos = -1;

        function submitUART(uartString)
        {
            document.getElementById('serialData').value=uartString+"\n";
            document.getElementById('serialForm').submit()
        };

        function scrollCam(val)
        {
            document.getElementById("scr").parentNode.scrollLeft=val;
        };

        function keyPressed(e)
        {
                var keynum
                var keychar
                var numcheck

                if(window.event) // IE
                {
                keynum = e.keyCode
                }
                else if(e.which) // Netscape/Firefox/Opera
                {
                keynum = e.which
                }
                keychar = String.fromCharCode(keynum);
                if(keychar == "w" || keychar == "Ж" || keychar == "W" || keychar == "ж") submitUART("DrvLR=100,100");
                if(keychar == "a" || keychar == "Т" || keychar == "A" || keychar == "т") submitUART("DrvLR=-100,100");
                if(keychar == "s" || keychar == "Ш" || keychar == "S" || keychar == "ш") submitUART("DrvLR=-100,-100");
                if(keychar == "d" || keychar == "Б" || keychar == "D" || keychar == "б") submitUART("DrvLR=100,-100");
                return true;
        };

        function keyUp(e)
        {
                var keynum
                var keychar
                var numcheck

                if(window.event) // IE
                {
                keynum = e.keyCode
                }
                else if(e.which) // Netscape/Firefox/Opera
                {
                keynum = e.which
                }
                keychar = String.fromCharCode(keynum);
                if(keychar == "w" || keychar == "Ж" || keychar == "W" || keychar == "ж") submitUART("DrvLR=0,0");
                if(keychar == "a" || keychar == "Т" || keychar == "A" || keychar == "т") submitUART("DrvLR=0,0");
                if(keychar == "s" || keychar == "Ш" || keychar == "S" || keychar == "ш") submitUART("DrvLR=0,0");
                if(keychar == "d" || keychar == "Б" || keychar == "D" || keychar == "б") submitUART("DrvLR=0,0");
                return true;
        };

        window.setInterval(
                function(){
                        var pos = document.getElementById("scr").parentNode.scrollLeft;
                        if(lastPos!=pos){
                                submitUART("#9 P" +(pos + 700));
                                lastPos=pos;
                        };
                },100
        );

    </script>
</head>
<body onKeyPress="return keyPressed(event)" onKeyUp="keyUp(event)">
<pre class="banner">
********************************************************************************************
*    ____                         ____        __          __  _                            *
*   / __ \____  ___  ____        / __ \____  / /_  ____  / /_(_)__________   _______  __   *
*  / / / / __ \/ _ \/ __ \______/ /_/ / __ \/ __ \/ __ \/ __/ // ___/ ___/  / ___/ / / /   *
* / /_/ / /_/ /  __/ / / /_____/ _, _/ /_/ / /_/ / /_/ / /_/ // /__(__  )_ / /  / /_/ /    *
* \____/ .___/\___/_/ /_/     /_/ |_|\____/_.___/\____/\__/_/ \___/____/(_)_/   \__,_/     *
*     /_/                                                                                  *
* <b>Made by <a href="http://open-robotics.ru/" target="_blank">Open-Robotics.ru</a></b>                                          Powered by <a href="http://openwrt.org" target="_blank">OpenWrt.org</a> *
********************************************************************************************
</pre>
<table>

    <tr>
        <td>
            <script type="text/javascript">
                document.write("<img alt='Robot Eye' class='bot-eye' src='http://" + document.location.host + ":8080/?action=stream'/>")
            </script>
            
            Camera control:
            <button type="button" onclick="scrollCam(0)">Left</button>
            <button type="button" onclick="scrollCam(800)">Center</button>
            <button type="button" onclick="scrollCam(1600)">Right</button>
            
            <div style="width:320px;height: 20px;margin-top: 15px;overflow-x: scroll;display: inline-block;"
                 onscroll="scrollCam(this.scrollLeft)">
                <div id="scr" style="width:1920px;height: 1px;display: block;" ></div>
            </div>
        </td>
    </tr>
    <tr>
        <td>
            <hr style="width: 240px;margin-top: 15px">
            Chassis control: W-Forward, A-Left, S-Backward, D-Right
        </td>
    </tr>
    <tr>
        <td>
            <hr style="width: 240px;margin-top: 15px">
            <form id="serialForm" action="/cgi-bin/serial.cgi" method="POST" target="hidden">
                <label>Serial data:
                    <textarea id="serialData" name="SERIAL_DATA" rows="2" cols="40">TEST SERIAL</textarea>
                </label>
                <input type="submit" value="Send">
            </form>
        </td>
    </tr>
</table>
<hr/>
<iframe name="hidden" src="/nothing.html" style="width: 1px;height: 1px;visibility: hidden"></iframe>

<a href="admin/index.html">Robot administration</a>
</body>
</html>
# cat /www/cgi-bin/serial.cgi
#!/usr/bin/awk -f
function unescape(s)
{
        gsub(/\+/," ",s)
        res = ""
        do {
          p = match(s,/%[0-9a-fA-F]{2}/)
          if(p>0) {
                res = res substr(s,0,p-1) sprintf("%c",0+("0x" substr(s,p+1,2)))
                s = substr(s,p+3)
          }
        } while(p>0)
        return res s
}

BEGIN {
        RS = "&"
        FS = "="
}
{
        if($1 == "SERIAL_DATA" ) print unescape($2) > "/dev/ttyUSB0"
}
END
{
        print "202"
}

админка:

# ls -asl /www/admin/
     0 drwxr-xr-x    2 root     root           112 May 27  2012 .
     0 drwxr-xr-x    1 root     root             0 Jan  1 00:15 ..
     4 -rw-r--r--    1 root     root          3730 May 27  2012 camshow.html
     2 -rw-r--r--    1 root     root          2178 Jan  1  1970 index.html
     2 -rw-r--r--    1 root     root          2203 Jan  1  1970 passwd.html
     3 -rw-r--r--    1 root     root          2890 Jan  1  1970 uhttpd.html
     4 -rw-r--r--    1 root     root          3937 Jan  1  1970 wifishow.html


# ls -asl /www/res/
     0 drwxr-xr-x    2 root     root            31 Nov 26  2011 .
     0 drwxr-xr-x    1 root     root             0 Jan  1 00:15 ..
     1 -rw-r--r--    1 root     root           554 Jan  1 00:47 main.css

# ls -asl /www/webcam/
     0 drwxr-xr-x    2 root     root           763 Sep  1  2012 .
     0 drwxr-xr-x    1 root     root             0 Jan  1 00:15 ..
     2 -rw-r--r--    1 root     root          2281 Aug 21  2012 JQuerySpinBtn.css
     7 -rw-r--r--    1 root     root          6880 Aug 21  2012 JQuerySpinBtn.js
    18 -rw-r--r--    1 root     root         17987 Aug 21  2012 LICENSE.txt
     0 -rw-r--r--    1 root     root           107 Aug 21  2012 bodybg.gif
    39 -rw-r--r--    1 root     root         40289 Aug 21  2012 cambozola.jar
    14 -rw-r--r--    1 root     root         14531 Aug 21  2012 control.htm
     9 -rw-r--r--    1 root     root          8752 Aug 21  2012 example.jpg
     0 -rw-r--r--    1 root     root           318 Aug 21  2012 favicon.ico
     0 -rw-r--r--    1 root     root           233 Aug 21  2012 favicon.png
     0 -rw-r--r--    1 root     root           123 Aug 21  2012 fix.css
     2 -rw-r--r--    1 root     root          2114 Aug 21  2012 functions.js
     3 -rw-r--r--    1 root     root          3058 Aug 21  2012 index.html
     2 -rw-r--r--    1 root     root          2548 Aug 21  2012 java.html
     6 -rw-r--r--    1 root     root          6361 Aug 21  2012 java_control.html
     0 -rw-r--r--    1 root     root           302 Aug 21  2012 java_simple.html
     5 -rw-r--r--    1 root     root          5429 Aug 21  2012 javascript.html
     6 -rw-r--r--    1 root     root          6270 Aug 21  2012 javascript_motiondetection.html
     2 -rw-r--r--    1 root     root          1620 Aug 21  2012 javascript_simple.html
    70 -rw-r--r--    1 root     root         72174 Aug 21  2012 jquery.js
     3 -rw-r--r--    1 root     root          2830 Aug 21  2012 jquery.rotate.js
     4 -rw-r--r--    1 root     root          3987 Aug 21  2012 jquery.ui.core.min.js
    21 -rw-r--r--    1 root     root         21090 Aug 21  2012 jquery.ui.custom.css
    11 -rw-r--r--    1 root     root         11435 Aug 21  2012 jquery.ui.tabs.min.js
     3 -rw-r--r--    1 root     root          2989 Aug 21  2012 jquery.ui.widget.min.js
     3 -rw-r--r--    1 root     root          2962 Aug 21  2012 rotateicons.png
     0 -rw-r--r--    1 root     root            35 Aug 21  2012 sidebarbg.gif
     1 -rw-r--r--    1 root     root          1041 Aug 21  2012 spinbtn_updn.gif
     2 -rw-r--r--    1 root     root          1773 Aug 21  2012 static.html
     0 -rw-r--r--    1 root     root           329 Aug 21  2012 static_simple.html
     3 -rw-r--r--    1 root     root          3053 Aug 21  2012 stream.html
     0 -rw-r--r--    1 root     root           166 Aug 21  2012 stream_simple.html
     5 -rw-r--r--    1 root     root          5157 Aug 21  2012 style.css
     3 -rw-r--r--    1 root     root          2619 Aug 21  2012 videolan.html

— значит jQuery уже есть — тем лучше 🙂

# cat /www/webcam/jquery.js | head
/*!
 * jQuery JavaScript Library v1.4.2
 * http://jquery.com/
 *
 * Copyright 2010, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/

пример CGI-скрипта на bash

# cat /www/cgi-bin/uptime
#!/bin/sh
echo "Content-type: text/html"
echo ""
echo "<html><header></header><body>"
echo "<h1>Uptime information</h1>"
echo "Your embedded device has been running for:<pre><font color=Blue>"
echo `uptime`
echo "</font></pre>"
echo "</body></html>"

скрипт mylua.cgi:

#!/bin/sh
echo "Content-type: text/html"
echo ""
echo "<html><header></header><body><pre>"
echo `env`
echo `/root/lua -v`
echo $QUERY_STRING
echo $SCRIPT_DATA
echo "</pre></body></html>"

ответ:

<html><header></header><body><pre>
CONTENT_TYPE=application/x-www-form-urlencoded GATEWAY_INTERFACE=CGI/1.1 REMOTE_HOST=192.168.217.15 HTTP_AUTHORIZATION=Basic cm9vdDox REMOTE_USER=root REMOTE_ADDR=192.168.217.15 QUERY_STRING= HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 DOCUMENT_ROOT=/www REMOTE_PORT=1388 HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 CONTENT_LENGTH=233 SCRIPT_FILENAME=/www/cgi-bin/mylua.cgi HTTP_HOST=192.168.217.1 REQUEST_URI=/cgi-bin/mylua.cgi SERVER_SOFTWARE=uHTTPd HTTP_CONNECTION=keep-alive PATH=/sbin:/usr/sbin:/bin:/usr/bin HTTP_ACCEPT_LANGUAGE=ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3 HTTP_REFERER=http://192.168.217.1/mylua.html SERVER_PROTOCOL=HTTP/1.1 HTTP_ACCEPT_ENCODING=gzip, deflate REDIRECT_STATUS=200 REQUEST_METHOD=POST SERVER_ADDR=192.168.217.1 PWD=/www SERVER_PORT=80 SCRIPT_NAME=/cgi-bin/mylua.cgi SERVER_NAME=192.168.217.1
Lua 5.2.1 Copyright (C) 1994-2012 Lua.org, PUC-Rio


</pre></body></html>

используем силу гугл и поищем про написание cgi на bash

нашёлся кусок кода для считывания данных POST и их декодирования:

if [ "$REQUEST_METHOD" = "POST" ]; then
read POST_STRING

  while true; do
    HEX="$(echo "$POST_STRING" | sed 's/^.*[^%]%\([0-9a-fA-F][0-9a-fA-F]\).*/\1/')"
    if [ "$HEX" = "$POST_STRING" ]; then
      break;
    fi
    REP=$(echo -e \\x$HEX)
    # to avoid mishandling of %25 (== '%') replace all occurences of the
    # percent sign itself with a double percent sign (kind of escaping)
    [ "$REP" = "%" ] && REP="%%"

    POST_STRING="$(echo "$POST_STRING" | sed 's/^\(.*[^%]\)%\([0-9a-fA-F][0-9a-fA-F]\)/\1'$REP'/')"
  done

  # replace all escaped percent signs with a single percent sign
  POST_STRING=$(echo $POST_STRING | sed 's/%%/%/g')

  # replace all ampersands with spaces for easier handling later
  POST_STRING=$(echo $POST_STRING | sed 's/&/ /g')

  do_stuff
fi

реализуем CGI для обработки и запуска Lua-скриптов.

запрос:

var='hello world!';
print(var);
a='123';
print(a);
b=tonumber(a);
print(b);
c=234;
d=b+c;
print(d);

print("start lua...");

require('mytest');
res = mytest.add1(12);
print(res);
print("end lua...");

тестовый CGI — mylua.cgi

#!/bin/sh
echo "Content-type: text/html"
echo ""
echo "<html><header></header><body><pre>"
#echo `env`
#echo `/root/lua -v`
#echo $QUERY_STRING
#echo $SCRIPT_DATA

if [ "$REQUEST_METHOD" = "POST" ]; then
read POST_STRING

  echo $POST_STRING
  echo "==="
  POST_STRING=$(echo $POST_STRING | sed 's/+/ /g')

  while true; do
    HEX="$(echo "$POST_STRING" | sed 's/^.*[^%]%\([0-9a-fA-F][0-9a-fA-F]\).*/\1/')"
    if [ "$HEX" = "$POST_STRING" ]; then
      break;
    fi
    REP=$(echo -e \\x$HEX)
    # to avoid mishandling of %25 (== '%') replace all occurences of the
    # percent sign itself with a double percent sign (kind of escaping)
    [ "$REP" = "%" ] && REP="%%"

    POST_STRING="$(echo "$POST_STRING" | sed 's/^\(.*[^%]\)%\([0-9a-fA-F][0-9a-fA-F]\)/\1'$REP'/')"
  done
  
  echo $POST_STRING
  echo "==="

  # replace all escaped percent signs with a single percent sign
  POST_STRING=$(echo $POST_STRING | sed 's/%%/%/g')

  # replace all ampersands with spaces for easier handling later
  POST_STRING=$(echo $POST_STRING | sed 's/&/ /g')
  
  POST_STRING=$(echo $POST_STRING | sed 's/SCRIPT_DATA=//g')
  echo $POST_STRING
  echo "==== RESULT ===="
  
  echo $POST_STRING > /tmp/tmpscript.lua
  export PATH="$/root:$PATH"
  cd /root
  echo `/root/lua /tmp/tmpscript.lua`
fi

echo "</pre></body></html>" 

результат:

<html><header></header><body><pre>
SCRIPT_DATA=var%3D'hello+world!'%3B%0Aprint(var)%3B%0Aa%3D'123'%3B%0Aprint(a)%3B%0Ab%3Dtonumber(a)%3B%0Aprint(b)%3B%0Ac%3D234%3B%0Ad%3Db%2Bc%3B%0Aprint(d)%3B%0A%0Aprint(%22start+lua...%22)%3B%0A%0Arequire('mytest')%3B%0Ares+%3D+mytest.add1(12)%3B%0Aprint(res)%3B%0Aprint(%22end+lua...%22)%3B%0A
===
SCRIPT_DATA=var='hello world!';print(var);a='123';print(a);b=tonumber(a);print(b);c=234;d=b+c;print(d);print("start lua...");require('mytest');res = mytest.add1(12);print(res);print("end lua...");
===
var='hello world!';print(var);a='123';print(a);b=tonumber(a);print(b);c=234;d=b+c;print(d);print("start lua...");require('mytest');res = mytest.add1(12);print(res);print("end lua...");
==== RESULT ====
hello world! 123 123 357 start lua... [i] test_add1(12.00) 13 end lua...
</pre></body></html>

Что-то переносы строки никак не хотят работать 🙁

добавим форму для загрузки файла:

<hr/>
<form action="/cgi-bin/myluafile.cgi" method=POST enctype="multipart/form-data">
	<label style="font-size:14pt;">Select file with Lua script: </label>
      <input type="file" name="luafile" />
      <input type="submit" value="Send file!" />
</form>

заливаем файлы
scp myluafile.cgi [email protected]:/www/cgi-bin/
scp mylua.html [email protected]:/www/

скрипт myluafile.cgi

#!/bin/sh
echo "Content-type: text/html"
echo ""
echo "<html><header></header><body><pre>"
killall lua
echo `env`

echo $QUERY_STRING
echo "========"

read Beg
echo $Beg
read ContentDisposition
echo $ContentDisposition
read ContentType
echo $ContentType

echo "" > /tmp/tmpscript.lua

while read STR ; do 
	echo $STR
	echo $STR >> /tmp/tmpscript.lua
done

if [ "$REQUEST_METHOD" = "POST" ]; then
	echo "========"
	export PATH="$/root:$PATH"
	cd /root
	echo `/root/lua /tmp/tmpscript.lua`
fi

echo "</pre></body></html>"

веб-страничка mylua.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>OR-WIFI-ROBOT: Lua script</title>
	<script src="./webcam/jquery.js"></script>
    <script type="text/javascript">
		function sendScript(){
			//alert("setSettings");
			var scr_data = $("#luascriptData").val();
		//	if( console && console.log ) {
		//		console.log("sendScript");
		//		console.log(scr_data);
		//	}
			$("#luascriptData").css("background-color", "yellow");
			$("#scriptResult").val("");
			$.ajax({
				type: "POST",
				url: "/cgi-bin/mylua.cgi",
				dataType: "html",
				data: {SCRIPT_DATA : scr_data},
				success: function ( data ) {
					$("#luascriptData").css("background-color", "white");
			//		if( console && console.log ) {
			//			console.log(data);
			//		}
					//alert(data);
					$("#scriptResult").val(data);
				}
			});
		}
    </script>
</head>
<body>
<table>
    <tr>
        <td>
            <label style="font-size:14pt;">Lua script:</label>
            <textarea id="luascriptData" name="SCRIPT_DATA" rows="20" cols="80">
var='hello world!';
print(var);
a='123';
print(a);
b=tonumber(a);
print(b);
c=234;
d=b+c;
print(d);
</textarea>
        </td>
		<td>
			<label style="font-size:14pt;">Result:</label>
			<textarea id="scriptResult" rows="20" cols="80" style="" >
			</textarea>
		</td>
    </tr>
	<tr>
		<td><input type="submit" value="Send" onclick="sendScript(); return false;" /></td>
		<td></td>
	</tr>
</table>
<hr/>
<form action="/cgi-bin/myluafile.cgi" method=POST enctype="multipart/form-data">
	<label style="font-size:14pt;">Select file with Lua script: </label>
      <input type="file" name="luafile" />
      <input type="submit" value="Send file!" />
</form>
<hr/>
<a href="index.html">home</a>
<a href="admin/index.html">administration</a>
<a href="https://robocraft.ru">RoboCraft</a>
</body>
</html>

— в ней же виден javascript-код для jQuery, реализующий ajax-запрос к нашему CGI-скрипту /cgi-bin/mylua.cgi

ответ скрипта на загрузку файла blink.lua (414 байт):

CONTENT_TYPE=multipart/form-data; boundary=---------------------------4827543632391 GATEWAY_INTERFACE=CGI/1.1 REMOTE_HOST=192.168.217.15 HTTP_AUTHORIZATION=Basic cm9vdDox REMOTE_USER=root REMOTE_ADDR=192.168.217.15 QUERY_STRING= HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 DOCUMENT_ROOT=/www REMOTE_PORT=2592 HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 CONTENT_LENGTH=618 SCRIPT_FILENAME=/www/cgi-bin/myluafile.cgi HTTP_HOST=192.168.217.1 REQUEST_URI=/cgi-bin/myluafile.cgi SERVER_SOFTWARE=uHTTPd HTTP_CONNECTION=keep-alive PATH=/sbin:/usr/sbin:/bin:/usr/bin HTTP_ACCEPT_LANGUAGE=ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3 HTTP_REFERER=http://192.168.217.1/mylua.html SERVER_PROTOCOL=HTTP/1.1 HTTP_ACCEPT_ENCODING=gzip, deflate REDIRECT_STATUS=200 REQUEST_METHOD=POST SERVER_ADDR=192.168.217.1 PWD=/www SERVER_PORT=80 SCRIPT_NAME=/cgi-bin/myluafile.cgi SERVER_NAME=192.168.217.1

========
-----------------------------4827543632391
Content-Disposition: form-data; name="luafile"; filename="blink.lua"
Content-Type: application/octet-stream

--[[ blink ]]--
led=io.open("/sys/devices/platform/leds-gpio/leds/tp-link:green:3g/brightness", "w"); 
if led==nil then 
print("Error open file!"); 
os.exit(-1); 
end 
val = 0; 
t0 = os.time(); 
t1 = 0; 
while 1 do 
t1 = os.time(); 
led:seek(beg, 0); 
if t1 > t0 then 
t0 = t1; 
print(val); 
led:write(val); 
if val == 0 then 
val = 1; 
else 
val = 0; 
end 
end 
end

-----------------------------4827543632391--
========

блинк пошёл :))
разумеется, нужно делать проверки, правильно считывать и отбрасывать последнюю строчку, но последняя строчка всё равно будет принята за комментарий 😉

Файлы:
mylua.cgi
myluafile.cgi
mylua.html

Ссылки
http://jquery.com

По теме
Использование Lua в робототехнике
Исследование Wi-Fi-роутера TP-LINK TL-MR3020
Кросс-компиляция Lua для TP-LINK TL-MR3020
Lua — модуль для работы с последовательным портом


Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна конкурс манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение