httpd

長年無料でお世話になってる長屋が、来年の3月いっぱいを持って閉鎖されるそうだ。

Yahoo!ジオシティーズ サービス終了のお知らせ

こんな案内が、家主さんから配られた。

老体の身でホームレスになるのは辛いな。移転先の候補として無料のものもあった。けど、暫く住んだ後で、ずっと居るなら管理費ぐらいは払ってよねと脅迫する所もあるかな。

そんな不愉快な思いをするぐらいなら、最初から有料(老人)ホームにでも入居した方がいいか。老後(今でも十分老後だろうに)は、北海道の石狩あたりが良いかも知れないな。

案内によると、 ジオユーザー優待のキャンペーンをやってる所がほとんどだった。何万人のユーザーがいるか知らないけど、それが流浪の民になる訳 だから、みんな手ぐすね引いてまってるんだな。 温泉街やらキャバレーの客引きと一緒。甘い言葉にだまされちゃいけませんぞ。

ポッキリ3000円で飲み放題とか言われて入ったら、オードブルがめちゃくちゃ高かったとか、おねーちゃんがおねだりする分は、別会計とか、よくある話ですから。

そんなこんなで、自前で家を建てたら、どうなるか調べてみる。なに、現役だった頃は、自分で家を建てる事を普通にやってましたからね。

何処かのデストリみたいに、建売じゃなくて、本当に間取りから設計してました。最近は、golangだとかPythonの簡易移動式の家も幅を利かせているみたい。

たまには、原点に返ってみるかな。

CERN式の住居

世界で初めての住居(跡)だそうですから、遺跡って分類? それとも観光業界の依頼で、 世界のお墨付き認定機関、世界遺産なんとか団体の手によって、文化遺産に認定されてる? この団体は(も)もっともらしい事を言ってるけど、利権が生まれて、濡れ手に粟。

そう言えば、某タイヤ屋が、勝手によその国の料理屋にランクを付けて、大儲けしてるな。 それに乗せられて、有難がってる連中も大勢いるけど。

http://info.cern.ch - home of the first website

CERN httpd

ソースを取ってきて、CentOSでコンパイル出来るか試してみた。

[sakae@cent cern]$ make
./BUILD
________________________________________________________________
WWW build for machine type:                             linux
make[1]: ディレクトリ `/tmp/cern/All/Implementation' に入ります

------ Building W3C Reference Library ------

Object files of libwww will go to directory Library/linux
        - already exists

make[2]: ディレクトリ `/tmp/cern/Library/linux' に入ります
echo Include files generated from hypertext.
Include files generated from hypertext.
cc -c -o ../../Library/linux/HTFTP.o -g -Wall -DPOSIXWAIT  -I../../Library/Implementation/  ../../Library/Implementation/HTFTP.c
../../Library/Implementation/HTFTP.c: 関数 ‘HTStrpTime’ 内:
../../Library/Implementation/HTFTP.c:438:5: 警告: 関数 ‘time’ の暗黙的な宣言です [-Wimplicit-function-declaration]
     time_t curtime = time(NULL);
     :
../../Library/Implementation/HTFTP.c:444:14: エラー: 不完全型のポインタへの間接参照
     time_info->tm_isdst = -1;         /* Disable summer time */
     :
make[2]: *** [../../Library/linux/HTFTP.o] エラー 1
make[2]: ディレクトリ `/tmp/cern/Library/linux' から出ます
make[1]: *** [../../Library/linux/libwww.a] エラー 2
make[1]: ディレクトリ `/tmp/cern/All/Implementation' から出ます

WWW build for  linux  done. status =  2
make: *** [all] エラー 2

見事にエラーですな。ちょっとエラー潰しに、ヘッダーファイルとかを追加してみたけど、さっぱり収束する気配無し。実行するのは、残念ながら諦めよう(根気が続かん)。その代わり、ちょっとソースを眺めておく。

** Authors
**      TBL     Tim Berners-lee <timbl@info.cern.ch>
**      DD      Denis DeLaRoca 310 825-4580 <CSP1DWD@mvs.oac.ucla.edu>
**      LM      Lou Montulli <montulli@ukanaix.cc.ukans.edu>
**      FM      Foteos Macrides <macrides@sci.wfeb.edu>
**      HF      Henrik Frystyk <frystyk@dxcern.cern.ch>
**      AL      Ari Luotonen <luotonen@www.cern.ch>
**
** History:
**       2 May 91       Written TBL, as a part of the WorldWideWeb project.
**      15 Jan 92       Bug fix: close() was used for NETCLOSE for control soc
**      10 Feb 92       Retry if cached connection times out or breaks
**       8 Dec 92       Bug fix 921208 TBL after DD
 :

生みの親のTBLさんの名前が出てますなあ。TBLさんが独自開発したと思っていたけど、いろんな人が関わっているんか。メアドを見ると、CERNの研究所だけじゃなくて、大学関係者もいるな。

[sakae@cent cern]$ ls All/
Implementation/   freebsd/     netbsd/    pyramid/  sun4-sol2/  vax_ultrix/
Makefile.include  hp300/       news/      sco/      ultrix/
aix/              i86pc-sol2/  next/      sgi/      unisys/
apollo_m68k/      isc3.0/      next-386/  snake/    unix/
apple/            linux/       next-fat/  sun3/     uts2/
dell/             ncr/         osf1/      sun4/     uts4/

色々なマシンで動くように、みんな頑張っていた訳ね。この頃は、GNUのconfigureなんて言う、便利な道具は普及してなかったんだな。

遺跡は復元出来なかったと、研究報告には書いておこう。

apache式住居

CERN式はヨーロッパ発。対抗意識むき出しの米国も国産化に乗り出した。 確かNCSA HTTPdとか言ったな。これと対になるブラウザーが、モザイクって名前だった。 データを受け取って画像をきちんと表示するまで時間がかかる。そこで、最初はモザイクを かけて、ユーザーの期待感を高めておこう。その間に、画像をきちんと整えればいい。

んな事で、日本のむふふなビデオなんかで採用されてた、モザイクってのをブラウザーの 名前にした。いいネーミングセンスしてるね。米国じゃ、無修正当たり前だから、モザイク なんて無いのよ。で、名前と手法を輸入したんだね。

で、サーバーの話に戻るけど、 設計が悪いんだか、立て付けが悪いんだか、しょっちゅう雨漏りとか害虫の侵入に悩まされていた。

その度に、つぎはぎのpatchが出されるんだけど、余りの多さに住人は嫌気が差した。 んで、一部の有志が、パッチをまとめたジャンボパッチ(世間一般風に言うと、大規模改修)の提供を始めた。

そんな訳で、そのパッチに名前が付けられた。many patch じゃないんだよ。a patch だよとな。(沢山じゃなくて、一つだけって事)それが一つの単語として、apatchとなったのさ。

今でも、老舗として連綿とリリースが続いているけど、古いやつも手に入るかなあ?

apache source

昔の記憶では、1.3.36ぐらいを良く使っていたと思うので、現代に蘇るか試してみる。 さすがに、この頃になると、configureも普及してるんで、ルンルンかと思ったら、

===> src/support
make[2]: ディレクトリ `/tmp/apache_1.3.36/src/support' に入ります
gcc -c  -I../os/unix -I../include   -DLINUX=22 -DHAVE_SET_DUMPABLE -DUSE_HSREGEX -DUSE_EXPAT -I../lib/expat-lite -DNO_DL_NEEDED `../apaci` htpasswd.c
htpasswd.c:100:12: エラー: ‘getline’ と型が競合しています
 static int getline(char *s, int n, FILE *f)
            ^
In file included from ../include/ap_config.h:1053:0,
                 from htpasswd.c:39:
/usr/include/stdio.h:678:20: 備考: 前の ‘getline’ の宣言はここです
 extern _IO_ssize_t getline (char **__restrict __lineptr,
                    ^
make[2]: *** [htpasswd.o] エラー 1
make[2]: ディレクトリ `/tmp/apache_1.3.36/src/support' から出ます
make[1]: *** [build-support] エラー 1
make[1]: ディレクトリ `/tmp/apache_1.3.36' から出ます
make: *** [build] エラー 2

Uum... patch Plan A. とか言いながら、自前のpatchを捻り出します。libcが供給するgetlineとapacheが独自に定義したgetlineで、型が一致してないと抜かすわけね。 こういう所だけ、Cフラフラ語として扱ってくれないものかしら。名前の衝突を自動回避する機能に期待してね。(そんな不純な動機を許してくれるやら?)

apache側のgetlineをgetlineAPに改名する姑息な方法にでる。getlineはあちこちで使われているので、事前に調べて名前を変えておく? いいえ、モグラたたきゲームの開幕です。

emacsからコンパイルしてエラーが発生した時、C-x ` で、エラーしたソースの所に飛んでいける。(正確には、日本語環境だとエラーしたファイル名は抽出してくれるけど、PATHは検出出来ない。そこで、ユーザーが、src/support/ とかと補う必要がある。emacsは英語環境で使うのが吉。)

数度、もぐらを叩いたら、I win.

+--------------------------------------------------------+
| You now have successfully built and installed the      |
| Apache 1.3 HTTP server. To verify that Apache actually |
| works correctly you now should first check the         |
| (initially created or preserved) configuration files   |
|                                                        |
|   /home/sakae/MINE/conf/httpd.conf
|                                                        |
| and then you should be able to immediately fire up     |
| Apache the first time by running:                      |
|                                                        |
|   /home/sakae/MINE/bin/apachectl start
|                                                        |
| Thanks for using Apache.       The Apache Group        |
|                                http://www.apache.org/  |
+--------------------------------------------------------+

優勝証明書と、内部構造説明書。これが有れば、後はご自由に。建てた所は自分の敷地だから、改造と言うか増築とか、取り壊しも自由気ままに出来るぞ。

[sakae@cent ~]$ tree -d MINE
MINE
├── bin
├── cgi-bin
├── conf
├── htdocs
│   └── manual
│       ├── howto
│       ├── images
│       ├── misc
│       ├── mod
│       ├── programs
│       └── vhosts
├── icons
│   └── small
├── include
│   └── xml
├── libexec
├── logs
├── man
│   ├── man1
│   └── man8
└── proxy

21 directories

懐かしいねぇ。cgi-bin。最近のhttpサーバーでは、ルーティングとか訳わからんフレーズが飛び交っているからな。ああいう言い方を始めたのは、ruby rails あたりから? オイラーは上手くレールに乗れなかったrails挫折組だから、これ以上言うまい。

早速入居だな。鍵のポートがどうなってるか確認。8080とか言う古い番号だった。せめて8086ぐらいにして欲しかったぞ。

w3m http://localhost:8080

If you can see this, it means that the installation of the Apache web server
software on this system was successful. You may now add content to this
directory and replace this page.

これを見ると、ほっとするんだよな。このページから説明書も参照出来るしね。

次はCGIか。cgi-binの中のテストスクリプトは、安全の為パーミションが落としてある。実行属性を付けてから

w3m http://localhost:8080/cgi-bin/test-cgi

CGI/1.0 test script report:

argc is 0. argv is .

SERVER_SOFTWARE = Apache/1.3.36 (Unix)
SERVER_NAME = localhost.localdomain
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/1.0
SERVER_PORT = 8080
REQUEST_METHOD = GET
HTTP_ACCEPT = text/html, text/*;q=0.5, image/*
PATH_INFO =
PATH_TRANSLATED =
SCRIPT_NAME = /cgi-bin/test-cgi
QUERY_STRING =
REMOTE_HOST =
REMOTE_ADDR = 127.0.0.1
REMOTE_USER =
AUTH_TYPE =
CONTENT_TYPE =
CONTENT_LENGTH =

どうやら、無事に動いているみたい。昔の事だけど、よく覚えているものだな。

尚、同じ要領でウブとdebianを試してみたけど、configureの所で失敗。何でもechoコマンドのエスケープが上手くいかない。そこで、それをdisableにしたけど駄目だったって、泣き言を言ってた。それ以上追及する気も無いので、ほってある。

ああ、それからここで立ち上げたのは、いわゆる、httpね。httpsなんて言う面倒は嫌いだから。

httpsなんてのは、最近注目されてる、GAFAのGの陰謀だからね。Gは覇権を握っちゃったものだから、やりたい放題。httpsに有らずばWebサーバーと認めないって方向に誘導中。次なる手は、TCPIPを棄てて、インターネットを分裂させるんだとか。

Aは、日本が大市場。次々と新製品を出して、金を吸い上げていく。それに加担する情けない電話屋。

Fは、プライバシーを丸裸にする事に余念がない。誰と誰が繋がっているかとか、みんな喜んで提供してるものなあ。濡れ手に粟ですぜ。みんなお人好しなんだから。

そして最後のAは、大河の上流に巨大な物流倉庫を構える。そこではせっせとslave達が物品のピックアップ。そのうちにslaveも文句を言わないロボットに置き換えられるだろう。大河を行き交う船賃の値下げを強要。どんなに物量が有っても、船がなければ運送出来ませんぜ。やまと集団やら飛脚は徹底抗戦しろや。物を頼んで2時間以内に届けよなんて、いつの間に我慢を知らない大人になったんや。

これらGAFAはみんなどこの国かと考えてみよう。スレーブですよ、みなさん。

httpd with gdb

例のごとく、サーバーが動いている所を、gdbで追いかけてみたい。(昔は動かすのに精一杯で、そんな発想すら無かった)

ちょいとMakefileをいじって、gdbにかけられるようにする。Makefileは、src/に有るもの。いずれも、下記のように変更。

CFLAGS=-g -O0 $(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS)

make clean してから、make httpdし直せばよい。出来上がった巨大な(898K)httpdを手動で、binの下に移動しとく。

それから、初期のhttpd.confでは、子供のhttpdが多数生まれるので、下記のように最低限の状態で起動するように設定変更。

conf/httpd.conf

MinSpareServers 1
MaxSpareServers 1
StartServers 1

これで起動。どんな風に起動したか確認。親が居て子がその下に出来るって構図。最近の日本みたいに、少子高齢化な環境だな。

[sakae@cent MINE]$ ps -ejH
  PID  PGID   SID TTY          TIME CMD
   :
 4374  4374  4374 ?        00:00:00   httpd
 4375  4374  4374 ?        00:00:00     httpd

masterが4374でslaveと言うかapache用語で言うとworkerのIDが4375。httpd.confの設定によってworkerを増やす事が出来る。ワーカーが沢山いれば、ユーザーからの要求を一度に沢山処理出来るので性能があがる。

そんじゃ、待機してるサーバーにgdbでattachして、どのあたりで待ってるか確認。まずは親分の方。

(gdb) bt
#0  0x00d0f416 in __kernel_vsyscall ()
#1  0x002d4f4d in ___newselect_nocancel () from /lib/libc.so.6
#2  0x08070343 in wait_or_timeout (status=0xbf9ef1f8) at http_main.c:2967
#3  0x08072a65 in standalone_main (argc=1, argv=0xbf9ef354) at http_main.c:5367
#4  0x080731ed in main (argc=1, argv=0xbf9ef354) at http_main.c:5683

standalone_mainの中

        while (!restart_pending && !shutdown_pending) {
            int child_slot;
            ap_wait_t status;
=>          int pid = wait_or_timeout(&status);

今度は、ワーカー側

(gdb) bt
#0  0x00d0f416 in __kernel_vsyscall ()
#1  0x002ddc71 in accept () from /lib/libc.so.6
#2  0x08071b81 in child_main (child_num_arg=0) at http_main.c:4555
#3  0x08072181 in make_child (s=0x9f9805c, slot=0, now=1538806114) at http_main.c:4982
#4  0x0807220c in startup_children (number_to_start=1) at http_main.c:5009
#5  0x0807293e in standalone_main (argc=1, argv=0xbf9ef354) at http_main.c:5341
#6  0x080731ed in main (argc=1, argv=0xbf9ef354) at http_main.c:5683

child_main

            for (;;) {
                clen = sizeof(sa_client);
=>              csd = ap_accept(sd, &sa_client, &clen);
                if (csd >= 0 || errno != EINTR)
                    break;
                if (deferred_die) {
                    /* we didn't get a socket, and we were told to die */
                    clean_child_exit(0);
                }
            }

w3mでアクセスしていると、いつの間にかワーカーが2つになってた。

[sakae@cent ~]$ curl -sv http://localhost:8080/cgi-bin/test-cgi >/dev/null
* About to connect() to localhost port 8080 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /cgi-bin/test-cgi HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sun, 07 Oct 2018 21:50:45 GMT
< Server: Apache/1.3.36 (Unix)
< Transfer-Encoding: chunked
< Content-Type: text/plain
<
{ [data not shown]
* Connection #0 to host localhost left intact

こんな風にして、アクセスしてみると、ワーカーがラウンドロビン(交互)に使われている事が分かった。なお、curlでのヘッダー表示が不要なら、-vを外せばよい。-sは、どれだけDLしましたって案内の不表示を指定するオプションだ。

  =>          if (r->status == HTTP_OK)    ;; Line 4811
                  ap_process_request(r);

読み込んだデータrを見ると

  unparsed_uri = 0x8d9cce4 "/cgi-bin/test-cgi",
  uri = 0x8d9ccfc "/cgi-bin/test-cgi",
  filename = 0x0,

こんなのだったんで、これから処理に行くんだな。

cgi-binの実行を追いたい。src/mainの下をちら見して util_script.cの中に、cgiの起動ルーチンぽいのを発見。そして、どうもforkされるようなので、追跡してくれるように依頼。

(gdb) b ap_call_exec
(gdb) set follow-fork-mode child
(gdb) c
Continuing.
[New process 1673]
[Switching to process 1673]

Breakpoint 1, ap_call_exec (r=0x9137554, pinfo=0x0,
    argv0=0x9137f6d "test-cgi", env=0x91383ac, shellcmd=0) at util_script.c:690
690         int pid = 0;
(gdb) bt
#0  ap_call_exec (r=0x9137554, pinfo=0x0, argv0=0x9137f6d "test-cgi",
    env=0x91383ac, shellcmd=0) at util_script.c:690
#1  0x0805b0b2 in cgi_child ()
#2  0x08062971 in spawn_child_core (p=0x913752c, func=0x805b017 <cgi_child>,
    data=0xbfbb93a4, kill_how=kill_after_timeout, pipe_in=0xbfbb7364,
    pipe_out=0xbfbb7360, pipe_err=0xbfbb735c) at alloc.c:2430
#3  0x08062bc2 in ap_bspawn_child (p=0x913752c, func=0x805b017 <cgi_child>,
    data=0xbfbb93a4, kill_how=kill_after_timeout, pipe_in=0xbfbbb3bc,
    pipe_out=0xbfbbb3b8, pipe_err=0xbfbbb3b4) at alloc.c:2702
#4  0x0805b3af in cgi_handler ()
#5  0x08065204 in ap_invoke_handler (r=0x9137554) at http_config.c:475
#6  0x0807b604 in process_request_internal (r=0x9137554) at http_request.c:1298
#7  0x0807b661 in ap_process_request (r=0x9137554) at http_request.c:1314
#8  0x08071ecd in child_main (child_num_arg=0) at http_main.c:4812
#9  0x08072181 in make_child (s=0x911d05c, slot=0, now=1538888428)
    at http_main.c:4982
#10 0x0807220c in startup_children (number_to_start=1) at http_main.c:5009
#11 0x0807293e in standalone_main (argc=1, argv=0xbfbbb704) at http_main.c:5341
#12 0x080731ed in main (argc=1, argv=0xbfbbb704) at http_main.c:5683

こんなに深いとソースを見るだけじゃ絶対に到達出来ないな。gdbさんに感謝。そして、この呼び出しルートを辿って行ったら、

alloc.c/L2702

=>  pid = spawn_child_core(p, func, data, kill_how,
                           pipe_in ? &fd_in : NULL,
                           pipe_out ? &fd_out : NULL,
                           pipe_err ? &fd_err : NULL);

cgiスクリプトとの絆っぽい仕掛けを発見したよ。

httpd.confについて調べたのでまとめたよ

httpd in OpenBSD

親分のご厚意により、OpenBSDを導入するとwebサーバーが付属で付いてくる。喜びいさんで、

ob6$ doas httpd
doas (sakae@ob6.localdomain) password:
pushfile: /etc/httpd.conf: No such file or directory

起動するも、早速怒られた。そりゃそうだわな。どんな性格のWebサーバーにするかまでは、親分と言えどもわからないので、自前で用意しろとな。ええ、たたき台は、/etc/exampleにありましたから、これを叩けば良いのでしょう。

一から設定してる人がいたので、倣ってみる。

Setting Up OpenBSD's httpd Web Server

ob6$ cat /etc/httpd.conf
ext_ip = "127.0.0.1"

server "default" {
    listen on $ext_ip port 80
    root "/htdocs/my.domain"
}

types {
    include "/usr/share/misc/mime.types"
}
ob6# mkdir -p /var/www/htdocs/my.domain
ob6# echo "Hello, world. from OpenBSD httpd" > /var/www/htdocs/my.domain/index.html
ob6# rcctl -f start httpd
httpd(ok)

サーバーの雛形は、/var/wwwに用意されてるので、差分だけを登録。

19827 ??  Isp     0:00.02 /usr/sbin/httpd
78640 ??  Isp     0:00.01 httpd: server (httpd)
 5534 ??  Isp     0:00.01 httpd: logger (httpd)
95219 ??  Isp     0:00.01 httpd: server (httpd)
48166 ??  Isp     0:00.01 httpd: server (httpd)

起動したのでアクセスしてみる

ob6$ curl -sv http://localhost
* Rebuilt URL to: http://localhost/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.59.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Length: 33
< Content-Type: text/html
< Date: Mon, 08 Oct 2018 23:54:54 GMT
< Last-Modified: Mon, 08 Oct 2018 23:52:40 GMT
< Server: OpenBSD httpd
<
Hello, world. from OpenBSD httpd
* Connection #0 to host localhost left intact

参考

OpenBSDのサーバ httpd の設定

OpenBSD の chroot jail httpd で CGI を動かす(1)

OpenBSDのacme-clientでLet's Encryptの証明書を取得する

httpd in NetBSD

ふらふらとNetBSDのpkgsrcを見ていたら、w3c-httpdなんてのが置いてあった。 1000行を超すパッチによって、世界最古のhttpdが蘇るように手入れされてた。

さすが、コンピュータの博物館。古いものの収集に余念が無い。中の学芸員も、大した腕の持ち主なんでしょうな。

試しにコンパイルしたら、無事にhttpdが出来上がってた。インストールするには、一度梱包と言うかパッケージングする必要が有るんで、諦めた。その代わり、パッキングリストだけを眺めて、インストール出来た気分に浸っておく。

@comment $NetBSD: PLIST,v 1.3 2009/06/14 22:00:39 joerg Exp $
bin/htadm
sbin/cgiparse
sbin/cgiutils
sbin/htimage
sbin/w3c-httpd
share/examples/w3c-httpd/all.conf
share/examples/w3c-httpd/caching.conf
share/examples/w3c-httpd/httpd.conf
share/examples/w3c-httpd/prot.conf
share/examples/w3c-httpd/proxy.conf
share/w3c-httpd/icons/back.xbm
 :