AWK HTTPサーバ
AWK Users JPの中で紹介されている簡易HTTPサーバをベースに少しだけ機能追加してみた。例では固定の文字列しか扱っていなかったので最低限リクエストしたパスに従いそのファイルを表示できるようにした。
ソースコード – httpd.awk
http://github.com/yokawasa/any/tree/master/awk_httpd/
http://github.com/yokawasa/any/blob/master/awk_httpd/httpd.awk
BEGIN {
port = "8080";
docroot = "./";
http_service = "/inet/tcp/" port "/0/0";
RS = ORS = "\r\n";
for (;;) {
if ((http_service |& getline reqline) > 0) {
request_handler(http_service, reqline, docroot);
}
close(http_service);
}
}
function request_handler(http_service,reqline, docroot) {
# parse request line
if ( split(reqline, t, " ") !=3 ) {
show_error(http_service, 400, "Bad Request");
return 1;
}
req_method = t[1];
req_uri = (index(t[2], "/")==1) ? substr(t[2],2) : t[2];
if (req_method != "GET" ) {
show_error(http_service, 405, "Method Not Allowed");
return 1;
}
# set path and query string
path = docroot req_uri;
n = split(path,tt,"?");
if (n >=2 ) {
path = tt[1];
ENVIRON["QUERY_STRING"] = tt[2];
}
# path should end with "/" if it's directory.
if(dir_exists(path)) {
if (substr(path,length(path)) != "/") {
path = path "/";
}
# set default file
path = path "index.html";
}
# check if file exists
if (!file_exists(path)) {
show_error(http_service, 404, "Not Found");
return 1;
}
show_page(http_service, path);
return 0;
}
function file_exists(path) {
cmd ="if [ -f " path " ]; then echo OK; fi";
exist = 0;
if ( (cmd |getline res) > 0) {
gsub("\n","", res);
if (res == "OK") {
exist = 1;
}
}
close(cmd);
return exist;
}
function dir_exists(path) {
cmd ="if [ -d " path " ]; then echo OK; fi";
exist = 0;
if ( (cmd |getline res) > 0) {
gsub("\n","", res);
if (res == "OK") {
exist = 1;
}
}
close(cmd);
return exist;
}
function file_read(file) {
buf = "";
while (getline < file > 0) {
buf = buf $0;
}
close(file);
return buf;
}
function find_mime_type(path) {
mime_type = "application/ocet-stream"; # default mime type
n = split(path, t, "/");
if (n >=2 ) {
filename = t[n];
m = split(filename, tt, ".");
if (m >=2 ) {
ext = tolower(tt[m]);
if (ext == "html" || ext == "htm") {
mime_type = "text/html";
}else if (ext == "css" ) {
mime_type = "text/css";
}else if (ext == "txt" || ext == "text" ) {
mime_type = "text/plain";
}
}
}
return mime_type;
}
function show_page( http_service,path) {
outbuf = file_read(path);
mime_type = find_mime_type(path);
content_len = length(buf);
print_output(http_service,200,"OK",outbuf,mime_type,content_len);
}
function show_error( http_service, errcode, reason) {
outbuf = "<h1>" reason "</h1>";
mime_type = "text/html";
content_len = length(buf);
print_output(http_service,errcode,reason,outbuf,mime_type,content_len);
}
function print_output( http_service,code,reason,outbuf,mime_type,content_len) {
print "HTTP/1.x " code " " reason |& http_service;
print "Content-type: " mime_type |& http_service;
print "Content-Length: " content_len |& http_service;
print "" |& http_service;
print outbuf |& http_service;
}
このプログラムの肝はgawkネットワーク接続用ファイル表記/inet/~でTCP/IPネットワーク接続の利用を宣言しhttp_service変数に格納、 ‘|&’ オペレータでINPUTとOUTPUTの2方向のネットワーク接続パイプを作成し、 ネットワーク接続パイプラインからのINPUT内容は” http_service |& getline’ で受けとり、 OUTPUT内容は ‘ print “書き込む内容” |& http_service’ で書き込む。 これに尽きる。
- ネットワーク通信用ファイル表記について – Using gawk for Network Programming
- 他プロセスとの2方向(IN、OUT)通信について – Two-Way Communications with Another Process
あと、残念なことにAWKはバイナリーデータが扱えない。よってHTTPサーバとしては致命的ではあるが画像やその他メディアファイルの表示をすることができない。 このHTTPサーバでは .htm、.html、.css、.txtファイルに対してはそれぞれMIMEタイプを’text/html’、’text/css’、’text/plain’としているがそれ以外のファイルタイプに対しては一律’application/ocet-stream’としている。
サーバ起動、サンプルページの表示
git clone でソースコードを取得する。リポジトリanyのサブディレクトリ any/awk_httpdが今回のサンプルにあたる。そして取得したhttpd.awkをgawkのファイル指定で実行する。gawkのパスが/usr/bin/gawkな場合は直接 ./httpd.awkで実行すればよい。 httpd.awkはデフォルトでポートが8080、ドキュメントルートが”./”となっている。ちなみに同一ディレクトリにポートとドキュメントルートのオプション指定ができるhttpd.igawkを用意している。 これを使用するには実行環境にigawkシェルスクリプトがインストールされている必要がある。
Initialized empty Git repository in /home/m/dev/github/t/any/.git/
remote: Counting objects: 45, done.
remote: Compressing objects: 100% (44/44), done.
remote: Total 45 (delta 11), reused 0 (delta 0)
Receiving objects: 100% (45/45), 13.99 KiB, done.
Resolving deltas: 100% (11/11), done
$ cd any/awk_httpd
$ ls -1
httpd.awk
httpd.igawk
pages
$ gawk -f ./httpd.awk
ページ表示テスト用にany/awk_httpd/pages下にhtml、cssファイルを用意してあるのでこれらを/home/awk_httpd/pages配下に配置して実際にブラウザでindex.htmlを表示させてみる。成功すると以下のようなページが表示される。
おわり。
Related posts:
Posted in: Programming / プログラミング
1 Comment
Comments RSS
TrackBack Identifier URI
Leave a comment







