<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Yoichi Kawasaki&#039;s Web &#187; net</title>
	<atom:link href="http://yk55.com/blog/tags/net/feed/" rel="self" type="application/rss+xml" />
	<link>http://yk55.com/blog</link>
	<description>my publicly accessible private memorandums</description>
	<lastBuildDate>Mon, 14 May 2012 01:31:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
	<!-- google_ad_section_end --><!-- google_ad_section_start(weight=ignore) -->	<item>
		<title>AWK HTTPサーバ</title>
		<link>http://yk55.com/blog/2010/06/29/awk_http/</link>
		<comments>http://yk55.com/blog/2010/06/29/awk_http/#comments</comments>
		<pubDate>Mon, 28 Jun 2010 23:04:02 +0000</pubDate>
		<dc:creator>yoichi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[awk]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[igawk]]></category>
		<category><![CDATA[net]]></category>
		<category><![CDATA[network]]></category>

		<guid isPermaLink="false">http://yk55.com/blog/?p=383</guid>
		<description><![CDATA[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 #! /usr/bin/gawk -f BEGIN { &#160; &#160; port = &#34;8080&#34;; &#160; &#160; docroot = &#34;./&#34;; &#160; &#160; http_service = &#34;/inet/tcp/&#34; port &#34;/0/0&#34;; &#160; &#160; RS = ORS = &#34;\r\n&#34;; &#160; &#160; for (;;) { &#160; &#160; &#160; &#160;if ((http_service &#124;&#38; getline reqline) &#62; 0) { &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>AWK Users JPの中で紹介されている<a href="http://gauc.no-ip.org/awk-users-jp/blis.cgi/DoukakuAWK_065">簡易HTTPサーバ</a>をベースに少しだけ機能追加してみた。例では固定の文字列しか扱っていなかったので最低限リクエストしたパスに従いそのファイルを表示できるようにした。</p>
<p><h2><strong>ソースコード – httpd.awk</strong></h2>
<p><a href="http://github.com/yokawasa/any/tree/master/awk_httpd/">http://github.com/yokawasa/any/tree/master/awk_httpd/</a><br />
<a href="http://github.com/yokawasa/any/blob/master/awk_httpd/httpd.awk">http://github.com/yokawasa/any/blob/master/awk_httpd/httpd.awk</a></p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#! /usr/bin/gawk -f<br />
<br />
BEGIN {<br />
&nbsp; &nbsp; port = &quot;8080&quot;;<br />
&nbsp; &nbsp; docroot = &quot;./&quot;;<br />
&nbsp; &nbsp; http_service = &quot;/inet/tcp/&quot; port &quot;/0/0&quot;;<br />
&nbsp; &nbsp; RS = ORS = &quot;\r\n&quot;;<br />
&nbsp; &nbsp; for (;;) {<br />
&nbsp; &nbsp; &nbsp; &nbsp;if ((http_service |&amp; getline reqline) &gt; 0) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; request_handler(http_service, reqline, docroot);<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp;close(http_service);<br />
&nbsp; &nbsp; }<br />
}<br />
<br />
function request_handler(http_service,reqline, docroot) {<br />
&nbsp; &nbsp; # parse request line<br />
&nbsp; &nbsp; if ( split(reqline, t, &quot; &quot;) !=3 ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; show_error(http_service, 400, &quot;Bad Request&quot;);<br />
&nbsp; &nbsp; &nbsp; &nbsp; return 1;<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; req_method = t[1];<br />
&nbsp; &nbsp; req_uri = (index(t[2], &quot;/&quot;)==1) ? substr(t[2],2) : t[2];<br />
&nbsp; &nbsp; if (req_method != &quot;GET&quot; ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; show_error(http_service, 405, &quot;Method Not Allowed&quot;);<br />
&nbsp; &nbsp; &nbsp; &nbsp;return 1;<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; # set path and query string<br />
&nbsp; &nbsp; path = docroot req_uri;<br />
&nbsp; &nbsp; n = split(path,tt,&quot;?&quot;);<br />
&nbsp; &nbsp; if (n &gt;=2 ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; path = tt[1];<br />
&nbsp; &nbsp; &nbsp; &nbsp; ENVIRON[&quot;QUERY_STRING&quot;] = tt[2];<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; # path should end with &quot;/&quot; if it's directory.<br />
&nbsp; &nbsp; if(dir_exists(path)) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; if (substr(path,length(path)) != &quot;/&quot;) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; path = path &quot;/&quot;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; # set default file<br />
&nbsp; &nbsp; &nbsp; &nbsp; path = path &quot;index.html&quot;;<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; # check if file exists<br />
&nbsp; &nbsp; if (!file_exists(path)) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; show_error(http_service, 404, &quot;Not Found&quot;);<br />
&nbsp; &nbsp; &nbsp; &nbsp;return 1;<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; show_page(http_service, path);<br />
&nbsp; &nbsp; return 0;<br />
}<br />
<br />
function file_exists(path) {<br />
&nbsp; &nbsp; cmd =&quot;if [ -f &quot; path &quot; ]; then echo OK; fi&quot;;<br />
&nbsp; &nbsp; exist = 0;<br />
&nbsp; &nbsp; if ( (cmd |getline res) &gt; 0) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; gsub(&quot;\n&quot;,&quot;&quot;, res);<br />
&nbsp; &nbsp; &nbsp; &nbsp; if (res == &quot;OK&quot;) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exist = 1;<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; close(cmd);<br />
&nbsp; &nbsp; return exist;<br />
}<br />
<br />
function dir_exists(path) {<br />
&nbsp; &nbsp; cmd =&quot;if [ -d &quot; path &quot; ]; then echo OK; fi&quot;;<br />
&nbsp; &nbsp; exist = 0;<br />
&nbsp; &nbsp; if ( (cmd |getline res) &gt; 0) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; gsub(&quot;\n&quot;,&quot;&quot;, res);<br />
&nbsp; &nbsp; &nbsp; &nbsp; if (res == &quot;OK&quot;) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exist = 1;<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; close(cmd);<br />
&nbsp; &nbsp; return exist;<br />
}<br />
<br />
function file_read(file) {<br />
&nbsp; &nbsp; buf = &quot;&quot;;<br />
&nbsp; &nbsp; while (getline &lt; file &gt; 0) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;buf = buf $0;<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; close(file);<br />
&nbsp; &nbsp; return buf;<br />
}<br />
<br />
function find_mime_type(path) {<br />
&nbsp; &nbsp; mime_type = &quot;application/ocet-stream&quot;; # default mime type<br />
&nbsp; &nbsp; n = split(path, t, &quot;/&quot;);<br />
&nbsp; &nbsp; if (n &gt;=2 ) { &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; filename = t[n];<br />
&nbsp; &nbsp; &nbsp; &nbsp; m = split(filename, tt, &quot;.&quot;);<br />
&nbsp; &nbsp; &nbsp; &nbsp; if (m &gt;=2 ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ext = tolower(tt[m]);<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (ext == &quot;html&quot; || ext == &quot;htm&quot;) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mime_type = &quot;text/html&quot;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }else if (ext == &quot;css&quot; ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mime_type = &quot;text/css&quot;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }else if (ext == &quot;txt&quot; || ext == &quot;text&quot; ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mime_type = &quot;text/plain&quot;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; return mime_type;<br />
}<br />
<br />
function show_page( http_service,path) {<br />
&nbsp; &nbsp; outbuf = file_read(path);<br />
&nbsp; &nbsp; mime_type = find_mime_type(path);<br />
&nbsp; &nbsp; content_len = length(buf);<br />
&nbsp; &nbsp; print_output(http_service,200,&quot;OK&quot;,outbuf,mime_type,content_len);<br />
}<br />
<br />
function show_error( http_service, errcode, reason) {<br />
&nbsp; &nbsp; outbuf = &quot;&lt;h1&gt;&quot; reason &quot;&lt;/h1&gt;&quot;;<br />
&nbsp; &nbsp; mime_type = &quot;text/html&quot;;<br />
&nbsp; &nbsp; content_len = length(buf);<br />
&nbsp; &nbsp; print_output(http_service,errcode,reason,outbuf,mime_type,content_len);<br />
}<br />
<br />
function print_output( http_service,code,reason,outbuf,mime_type,content_len) {<br />
&nbsp; &nbsp; print &quot;HTTP/1.x &quot; code &quot; &quot; reason |&amp; http_service;<br />
&nbsp; &nbsp; print &quot;Content-type: &quot; mime_type |&amp; http_service;<br />
&nbsp; &nbsp; print &quot;Content-Length: &quot; content_len |&amp; http_service;<br />
&nbsp; &nbsp; print &quot;&quot; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&amp; http_service;<br />
&nbsp; &nbsp; print outbuf |&amp; http_service;<br />
}</div></div>
<p>このプログラムの肝はgawkネットワーク接続用ファイル表記/inet/～でTCP/IPネットワーク接続の利用を宣言しhttp_service変数に格納、 &#8216;|&#038;&#8217; オペレータでINPUTとOUTPUTの2方向のネットワーク接続パイプを作成し、 ネットワーク接続パイプラインからのINPUT内容は&#8221; http_service |&#038; getline&#8217; で受けとり、 OUTPUT内容は &#8216; print &#8220;書き込む内容&#8221; |&#038; http_service&#8217;  で書き込む。 これに尽きる。</p>
<ul>
<li><a href="http://www.gnu.org/manual/gawk/html_node/TCP_002fIP-Networking.html#TCP_002fIP-Networking">ネットワーク通信用ファイル表記について &#8211; Using gawk  for Network Programming</a></li>
<li><a href="http://www.gnu.org/manual/gawk/html_node/Two_002dway-I_002fO.html#Two_002dway-I_002fO">他プロセスとの2方向(IN、OUT)通信について &#8211; Two-Way Communications with Another Process</a></li>
</ul>
<p><p>
あと、残念なことにAWKはバイナリーデータが扱えない。よってHTTPサーバとしては致命的ではあるが画像やその他メディアファイルの表示をすることができない。 このHTTPサーバでは .htm、.html、.css、.txtファイルに対してはそれぞれMIMEタイプを&#8217;text/html&#8217;、&#8217;text/css&#8217;、&#8217;text/plain&#8217;としているがそれ以外のファイルタイプに対しては一律&#8217;application/ocet-stream&#8217;としている。</p>
<p><h2><strong>サーバ起動、サンプルページの表示</strong></h2>
<p>git clone でソースコードを取得する。リポジトリanyのサブディレクトリ any/awk_httpdが今回のサンプルにあたる。そして取得したhttpd.awkをgawkのファイル指定で実行する。gawkのパスが/usr/bin/gawkな場合は直接 ./httpd.awkで実行すればよい。 httpd.awkはデフォルトでポートが8080、ドキュメントルートが&#8221;./&#8221;となっている。ちなみに同一ディレクトリにポートとドキュメントルートのオプション指定ができる<a href="http://github.com/yokawasa/any/blob/master/awk_httpd/httpd.igawk">httpd.igawk</a>を用意している。 これを使用するには実行環境にigawkシェルスクリプトがインストールされている必要がある。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git clone git@github.com:yokawasa/any.git &nbsp;<br />
Initialized empty Git repository in /home/m/dev/github/t/any/.git/<br />
remote: Counting objects: 45, done.<br />
remote: Compressing objects: 100% (44/44), done.<br />
remote: Total 45 (delta 11), reused 0 (delta 0)<br />
Receiving objects: 100% (45/45), 13.99 KiB, done.<br />
Resolving deltas: 100% (11/11), done<br />
<br />
$ cd any/awk_httpd<br />
<br />
$ ls -1 <br />
httpd.awk<br />
httpd.igawk<br />
pages<br />
<br />
$ gawk -f ./httpd.awk</div></div>
<p>ページ表示テスト用にany/awk_httpd/pages下にhtml、cssファイルを用意してあるのでこれらを/home/awk_httpd/pages配下に配置して実際にブラウザでindex.htmlを表示させてみる。成功すると以下のようなページが表示される。</p>
<p><a href="http://www.flickr.com/photos/yk55/4743945384/" title="AWK HTTP Server Page by yoichi*, on Flickr"><img src="http://farm5.static.flickr.com/4115/4743945384_2fa7426d09_z.jpg" width="640" height="315" alt="AWK HTTP Server Page"></a></p>
<p>おわり。</p>
<iframe src="http://www.facebook.com/plugins/like.php?href=http://yk55.com/blog/2010/06/29/awk_http/&amp;layout=button_count&amp;show_faces=1&amp;width=450&amp;action=like&amp;colorscheme=light&amp;font=arial" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:25px"></iframe>]]></content:encoded>
			<wfw:commentRss>http://yk55.com/blog/2010/06/29/awk_http/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	<!-- google_ad_section_end --></channel>
</rss>

