mini_httpdを利用する

PaPeRo iでは設定画面用にmini_httpdというwebサーバーが使われています。
これをシステム用とは別にもう一つ起動して利用する方法を紹介します。

デモの内容

mini_httpdはGET,HEAD,POSTメソッド、また、CGIに対応しているそうです。
そこで今回は例として、/bin/shでCGIを作り、別途用意したシェルから呼べるPaPeRo iに喋らせるコマンドと組み合わせて、ブラウザで入力した言葉を喋らせることができる様にしてみたいと思います。
動作させるためにはPaPeRo i本体へのPythonのインストールは不要ですが、弊社WebSocket通信アドオンシナリオが動作している必要があります。

mini_httpdの起動

システム用のmini_httpdの起動スクリプトは/etc/init.d/S81mini_httpd、設定ファイルは/etc/mini_httpd.conf、データディレクトリ=ブラウザからルートに見えるディレクトリが/tmp/usr/local/wwwとなっています。
アプリ用にはこれらを修正して使うことになります。

(1) 起動スクリプト
何でも良いのですが、今回の起動スクリプトはシステム用のS81mini_httpdを修正してS981mini_httpd_speechとします。
/Extension/script/に置けば電源ONで自動で起動しますが、コマンドシェルから実行する分には置く場所はどこでも構いません。
システム用のS81mini_httpdで

mini_httpd_pid=/var/run/mini_httpd.pid
mini_httpd_conf=/etc/mini_httpd.conf
mini_httpd_content_dir=/tmp/usr/local/www

となっていたpid保存ファイル指定などの部分は重複してはまずいのでS981mini_httpd_speechでは

mini_httpd_pid=/var/run/mini_httpd_speech.pid
mini_httpd_conf=/etc/mini_httpd_speech.conf
mini_httpd_content_dir=/tmp/usr/local/www_speech

とします。また、データディレクトリや/etcはRAMディスクで保存されないので、
/Extension/local/demo/cgi_speech以下に必要な全ファイルを置き、
起動スクリプトS981mini_httpd_speechでコピーすることにします。

SRCROOT=/Extension/local/demo/cgi_speech
cp -fa $SRCROOT/${mini_httpd_conf##*/} $mini_httpd_conf
cp -fa $SRCROOT/${mini_httpd_content_dir##*/} $mini_httpd_content_dir

さらに、システムではベーシック認証のため.htpasswdと.htserviceを作成していますが、
今回はベーシック認証なしにするためその部分を削除しています。
起動スクリプトS981mini_httpd_speechの全体は以下の様になります。

#!/bin/sh
SRCROOT=/Extension/local/demo/cgi_speech

mini_httpd_prog=/usr/sbin/mini_httpd
mini_httpd_pid=/var/run/mini_httpd_speech.pid
mini_httpd_conf=/etc/mini_httpd_speech.conf
mini_httpd_content_dir=/tmp/usr/local/www_speech

start() {
    cp -fa $SRCROOT/${mini_httpd_conf##*/} $mini_httpd_conf
    cp -fa $SRCROOT/${mini_httpd_content_dir##*/} $mini_httpd_content_dir
    if [ ! -f $mini_httpd_conf ] ; then
        echo "configure file do not exist!"
        exit 1
    fi

    cd $mini_httpd_content_dir &&
    $mini_httpd_prog -i $mini_httpd_pid -C $mini_httpd_conf
}

stop() {
    kill `cat $mini_httpd_pid`
    rm -f $mini_httpd_conf
    rm -rf $mini_httpd_content_dir
}

restart() {
    stop
    start
}

case "$1" in
start)
    start
    ;;
stop)
    stop
    ;;
restart)
    restart
    ;;
*)
    echo "usage: $0 { start | stop | restart }" >&2
    exit 1
    ;;
esac

exit 0

(2) 設定ファイル
設定ファイルは/Extension/local/demo/cgi_speech/mini_httpd_speech.confに置き、起動スクリプトで/etc/mini_httpd_speech.confにコピーしています。
これはシステム用の設定ファイル/etc/mini_httpd.confからベーシック認証を外し、データディレクトリ、pidファイル名、ポート番号を変更する修正を行っています。
ポート番号は8863としています。設定ファイルmini_httpd_speech.confの全体は以下の通りです。

# mini_httpd configure file

#basic_realm=NEC(admin)
cgipat=**.cgi|**.sh
user=root
#user=nobody
#chroot=/tmp/usr/local/www
#dir=/tmp/usr/local/www
data_dir=/tmp/usr/local/www_speech

pidfile=/var/run/mini_httpd_speech.pid
charset=euc-jp
#charset=shift_jis
#charset=iso-2022-jp
nosingle_session
### HTTPS/SSL
#nossl
#ssl
#certfile=/tmp/mini_httpd.pem

port_default1=8863:IPv4
port_default2=8863IPv6

permit_dir=css|img
permit_root_file=index.cgi

#auth_mac_port=8863

# HTTP server configure file path
#config_file_append=/etc/mini_httpd/mini_httpd_append.conf
#config_file_dirpasswd
#config_file_diralias
#config_file_run_auth_ext=/etc/mini_httpd/auth_ext.conf
#config_file_run_auththrough=/etc/mini_httpd/auththrough.conf
#config_file_run_cgipattern=/etc/mini_httpd/cgipattern.conf
#config_file_run_mimetype=/etc/mini_httpd/mimetypes.conf
config_file_run_mimetype=/etc/mimetypes.conf
config_file_run_revproxypattern=/etc/revproxypattern.conf
config_file_run_add_headers=/etc/add_headers.conf

default_file=index.html|index.htm|index.cgi

(3) データディレクトリ
CGI本体、CGIで喋らせるために使用するコマンドなどのファイルは/Extension/local/demo/cgi_speech/www_speechに置き、起動スクリプトで/tmp/usr/local/www_speechにコピーしています。

パペロに喋らせるCGI

今回の設定で起動したmini_httpdにより、/tmp/usr/local/www_speech直下に置いたファイル、例えばtest.htmlという名前で置いたとすると、これはブラウザからhttp://192.168.1.1:8863/test.htmlで表示できる様になります。
これはmini_httpdがtest.htmlの中身をそのままブラウザに渡すという動作をすると言うことです。
CGIの場合、例えば今回index.cgiという名前にしましたが、mini_httpdはindex.cgiの中身をブラウザに渡すのではなく、index.cgiを実行し、その標準出力をブラウザに渡すという動作をします。
従ってCGIは実行さえできれば言語などを問わず、htmlファイルを出力できれば良いことになります。今回はシェルスクリプトで実現しています。
なおPOSTの場合、テキストボックスなどで入力されたデータは、標準入力としてCGIに渡されますが、POSTされたデータはURLエンコードされているのでデコードする必要があります。
これには@richmikan@github様のURLエンコード・デコードするに掲載されていたスクリプトをそのまま使わせて頂きました(index.cgiから./urldecode.shとして呼び出し)。
ライセンスは「必要な方はコピペして使うといい。」とあり、ラフですのでもし製品に使用する場合にはご注意下さい。

喋らせるコマンドはpaperospeechです。これは弊社WebSocket通信アドオンシナリオを前提としたgo言語で作成した喋らせるだけのコマンドです。これについては近々詳しくご紹介させて頂く予定です。→golangでPaPeRo iのアプリをつくる(※2017/12/28追記)
なおエラー処理などは入っておりません。喋らせるCGI(index.cgi)の全体は以下の通りです。

#!/bin/sh

echo "Status: 200"
echo "Content-Type: text/html; charset=UTF-8"
echo ""
echo "<!DOCTYPE html>"
echo "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"ja,zh\" xml:lang=\"ja,zh\">"
echo "<head>"
echo "</head>"
if [ ! -z $CONTENT_LENGTH ] && [ $CONTENT_LENGTH -gt 0 ]; then
  str="`cat`"
  str=${str#txt=}
  str=`echo $str | ./urldecode.sh`
fi
echo "<body>"
echo "<form action=\"./index.cgi\" method=\"post\">"
echo "<input name="txt" type=\"text\" value=\"$str\" style=\"width: 560px; height: 24px\"><br>"
echo "<input type=\"submit\" value=\"発話\">"
echo "</form>"
if [ ! -z $CONTENT_LENGTH ] && [ $CONTENT_LENGTH -gt 0 ]; then
  ./paperospeech -speech "$str" > /dev/null 2>&1
fi
echo "</body>"
echo "</html>"

実行方法

こちらからcgi_speech.tar.gzをダウンロードして下さい。
PaPeRo iの/tmpに転送して以下のコマンドで展開して下さい。

# mkdir -p /Extension/local/demo
# cd /Extension/local/demo
# tar xvzf /tmp/cgi_speech.tar.gz

単に実行するためには以下の様にして下さい。

# /Extension/local/demo/cgi_speech/S981mini_httpd_speech start

index.cgiをブラウザで開き、文字を入力して発話ボタンを押すと、パペロがしゃべります。