無精で短気で傲慢なプログラマ

UNIX や web やプログラムの技術的なことを中心に。

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

PageTop

やねうらおさんから http クライアントサンプルコードへのツッコミ

mixi にてやねうらおさんから http://x68000.q-e-d.net/~68user/net/c-http-1.html のコードについてご指摘を受けたので、ここで書いても伝わるかどうかわかりませんが、一応回答と言い訳を。

> connectに失敗したときにソケットがcloseされない。

うーん。懐かしの malloc/free 論争を思い出してしまいました。その考えを否定はしませんが、わたしはここでは close しません。サンプルコードの可読性を損なうから。実務であっても、即終了するなら close しないと思う。理由は「OS にまかせて実害がないから」。常駐モノならするけど。

> そのreadってhttpで送られてきたデータを受け取っているのでないの?
> データ自体はRFCで規定されている長さまでなら送られてくると思うのだけど。

わたしの知る限りでは、RFC2616 においては HTTP のレスポンスメッセージの最大長は規定されていませんので、理論的には ssize_t の範囲のデータが返ってくると思います (実際は mbuf がもたなくてブロックしてしまうでしょうが)。

ついでに恥をさらしておくと、あのソースは他にもいろいろまずいところがあって、サンプルコードであるという前提であったとしても、以下の問題点があります。参考になれば>葵さん

◎直すべきもの
 ・write(2) のエラーチェックが漏れている。
 ・read(2) のエラーチェックが漏れている。
 ・close(2) のエラーチェックが漏れている。
 ・おっしゃるとおり、int は ssize_t に直すべき。
  ところで負け惜しみのようでかっこ悪いですが、「ssize_t は unsigned」というのは
  誤りだと思います (signed じゃないと read(2) が -1 を返せない)。ちなみに FreeBSD
  では int でした。

◎直した方がいいなぁと思うもの
 ・socket(2)・connect(2) などのエラーチェックで、errno を表示した方が親切。
 ・gethostbyname(3) のエラーチェックは herror(3) あたりを使った方が親切。
 ・read(s, buf, BUF_LEN) は read(s, buf, sizeof(buf)) に変えたいなぁ。
 ・strcmp(argv[1], "http://" ) は strcmp(argv[1], "http://" ) != 0 としたい。
 ・socket(AF_INET, ...) は socket(PF_INET, ...) が正しい (プロトコルファミリの指定なので)
 ・write(2) で全データを送りきったかどうかのチェックが漏れている。
  (ただし、送りきれない場合があるよってのはページをわけて説明したい)
 ・BUF_LEN は定数の種類を増やすとわかりにくくなると思っていたのですが、
  今考えると分けておいた方がいいような気がしてきました。

◎直すべきかどうか、いまだにわからないもの
 ・printf(3) のエラーチェック
  … みんな仕事の場合、printf(3)/sprintf(3)/fprintf(3) の戻り値をチェックしてるの?
    stdout or stderr への出力であっても?
PageTop

英単語トリビアと look コマンド

話のネタになるかもしれないトリビア50個
> * "Almost"は、全ての文字がアルファベット順になっている単語の中で最も長い単語。
>  A→l→m→o→s→t。他にどんな単語があるのでしょうか。
>
> * "Rhythm"は、母音の無い最も長い単語。
>  これも他の単語が気になります。

英単語トリビアが気になったので調べてみる。

UNIX には look というコマンドがある (1979年リリースの V7 から存在する)。引数で与えた文字列から始まる英単語を表示するだけのものだ。
% look fuga
fugacious
fugaciously
fugaciousness
fugacity
fugal
fugally

テキストファイル (FreeBSD だと /usr/share/dict/words) に英単語が羅列してあって、そこから grep しているようなものである。テキストファイルは最初からソートしてあり、二分探索で探しているので grep よりは速い。でもいまどきのマシンにおいては、ほとんど誤差程度の違いしかない。

> * "Rhythm"は、母音の無い最も長い単語。

まずこれ。若干の敗北感を感じつつも awk を使う。
% grep -iv '[aeiou]' /usr/share/dict/words | awk '{print length($1),$1}' | sort -nr | head -15
8 symphysy
7 nymphly
7 gypsyry
7 gypsyfy
6 tyddyn
6 thymyl
6 syzygy
6 sylphy
6 styryl
6 strych
6 spryly
6 rhythm
6 pyrryl
6 phytyl
6 myrrhy

「Rhythm」より長い英単語はあるし、「Rhythm」と同じ長さの英単語も結構あるので「最も長い」はちょっと言いすぎのようだ。

look で最長であった「symphysy」でググった結果、ほんとの母音なしの最長英単語は「TWYNDYLLYNG」のようだ。15世紀ごろの英古語で意味は「twin」だとか。ここまでくると、どの範囲を英単語と認めるかという話になりそうだ。

 - A Collection of Word Oddities and Trivia, Page 6
 - Longest word without vowels

> * "Almost"は、全ての文字がアルファベット順になっている単語の中で最も長い単語。

今度は perl を使う。コマンドラインでこんなことができるんですよ! ということを書きたかったはずなのに。堕落だ。
#!/usr/local/bin/perl
open(IN, '/usr/share/dict/words') || die "$!";
wordloop:
while (<IN>){
  chomp;
  my @chars = unpack('C*', lc($_));
  $max = 0;
  foreach my $c (@chars){
    if ( $max < $c ){
      $max = $c;
    } else {
      next wordloop;
    }
  }
  printf("%d %s\n", length($_), $_);
}
実行結果:
% perl hoge.pl | sort -rn | head -15
7 egilops
7 Adelops
6 ghosty
6 dimpsy
6 deinos
6 dehort
6 dehors
6 chintz
6 biopsy
6 bijoux
6 beknow
6 behint
6 befist
6 almost
6 agnosy

トップは 7文字の「egilops」と「Adelops」。almost は 6文字で、2番手グループ。上記の結果は同じ文字が連続している英単語は除外していたが、それも含むと以下のようになる。
% perl hoge.pl | sort -rn | head -10
7 egilops
7 billowy
7 begorry
7 beefily
7 alloquy
7 Adelops
6 knotty
6 knoppy
6 glossy
6 ghosty

A Collection of Word Oddities and Trivia, Page 1 によれば、全ての文字がアルファベット順になっている最長英単語は 8文字の「aegilops」。意味は look の最長である「egilops」と同じで、意味は an ulcer in a part of the eye (目の潰瘍?)。

とはいえ、
 * "TWYNDYLLYNG"は、母音の無い最も長い単語。
 * "aegilops"は、全ての文字がアルファベット順になっている単語の中で最も長い単語。
ではあんまり「へぇ」とは思わないので、まぁいいか。

look のデータは更新されてるのかな? と思って FreeBSD の cvsweb を見てみたら、ちまちまと手が入っているようだ。例えば Australia, Denmark, karaoke, karate などの英単語が追加されている。最新版 (2003年更新) は 235,882 単語が登録されており、4.4 BSD Lite 版 (1994年) と比べると 2632 単語 追加・修正・削除されていた。

ちなみに V7 版 は 24,001単語だった。
PageTop

HTTP host ヘッダの初実装は?

HTTP にて name based なバーチャルホストを実現するための Host ヘッダは RFC2068 (Hypertext Transfer Protocol - HTTP/1.1) にて定義されている。

RFC2068 は 1997/1 の発行であるが、web サーバ・ブラウザへの実装自体はもっと早い段階で行われている。

例えば、apache で Host ヘッダが利用可能になったのは apache-1.1 だが (New Features with Apache 1.1 を参照。正確には apache-1.1b1 か?)、apache-1.1 のリリース日は 1996/7/3 である。

で、わたしがずっと疑問に思っていたのは Host ヘッダは誰が提案し、誰が初めて実装したものかというもの。web サーバとブラウザが歩調を合わせないと意味がないため、NCSA httpd と NCSA Mosaic が初実装ではないかと想像していたのだが、どうやら NCSA httpd には IP アドレスベースなバーチャルホスト機能しか実装されていなかったようなので、違うらしい。

では、RFC を策定した IETF の、HTTP ワーキンググループにて提案され、HTTP/1.1 策定前に web サーバ・ブラウザ開発者が先取りして実装したのか?

というところで時間切れ。結局何もわからず。
PageTop

SSL/TLS 必須ページの .htaccess 設定

http://example.jp/ は http だが、http://example.jp/security/ は SSL/TLS 必須と
する場合の .htaccess 設定。

方法1. バーチャルホスト (VirtualHost ディレクティブ) を別に切る
 これが一番スマートかも。それができない場合は方法2 や方法3 で対応。

方法2. SSLRequireSSL を使う。
 .htaccess に
  SSLRequireSSL
 と書くだけで、そのディレクトリ以下は SSL 必須となる (SSL 以外のアクセスは deny する)。
 httpd.conf に記述するなら
  <Directory "/foo/bar">
   SSLRequireSSL
  </Directory>
 とする。
  マニュアル: http://httpd.apache.org/docs/2.0/ja/mod/mod_ssl.html#SSLRequireSSL

方法3. RewiteCond で判別し、http(80) の場合は他に飛ばす。
 RewriteEngine on
 RewriteCond %{SERVER_PORT} ^80$
 RewriteRule ([^/]*)$ http://%{HTTP_HOST}/$0
  マニュアル: http://httpd.apache.org/docs/2.0/ja/mod/mod_rewrite.html

ちなみに
 SetenvIf SERVER_PORT 80 NO_SSL=1
 Deny from env=NO_SSL
という判定方法は SetenvIf から SERVER_PORT を参照できないため無理っぽい。

さらに余談。Apache-SSL には SSLRequireSSL と逆の働きをする (SSL なら拒否)、
SSLDenySSL というディレクティブが存在する。しかし mod_ssl には SSLDenySSL は
存在しないし、mod_ssl を取り込んだ形の Apache2 にも存在しない (Apache-SSL と
mod_ssl は別物
)。
PageTop

SELECT 要素の value プロパティ

SELECT 要素の値を参照・代入する場合は
 参照: myform.myselect.options[myform.myselect.selectedIndex].value
 代入: myform.myselect.selectedIndex = "..";
とするしかないとずっと思っていたのだが、
 参照: myform.myselect.value
 代入: myform.myselect.value = '..';
と書けるということを先日知った。

例:





ソース:
  <select name="pref">
    <option value="0">選択してください</option>
    <option value="1">1:北海道</option>
    <option value="2">2:東京都</option>
    <option value="3">3:沖縄県</option>
  </select>
  <input type="button" value="SELECT要素の valueを表示"
          onClick="alert(this.form.pref.value)">
  <input type="button" value="東京都にセット"
          onClick="this.form.pref.value = 2">


DOM level-1 の 付録 E: ECMAスクリプト言語バインディング にも
HTMLSelectElement オブジェクトは以下のプロパティをもつ。
  value このプロパティは String 型である。
とあるので、多分問題なさそう。少なくとも IE6 と Firefox1.5.0.6 では動作した。


Javascript の初歩ですかそうですか。
PageTop
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。