[インデックス 14445] ファイルの概要
このコミットは、Go言語の標準ライブラリnet/http/cgi
パッケージにおけるWindows環境でのテストの安定性向上を目的としています。具体的には、Windows上でのCGIスクリプトの実行に関するパスの正規化と、テストのスキップ条件の調整が行われています。
コミット
commit 54b9c2015194b68135098c4eae564a122a4bccf6
Author: Alex Brainman <alex.brainman@gmail.com>
Date: Tue Nov 20 16:24:12 2012 +1100
net/http/cgi: another attempt to fix windows tests
Also enables TestDirWindows test on windows.
Fixes #4401.
R=golang-dev, bradfitz
CC=golang-dev, krautz
https://golang.org/cl/6847072
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/54b9c2015194b68135098c4eae564a122a4bccf6
元コミット内容
net/http/cgi: another attempt to fix windows tests
Also enables TestDirWindows test on windows.
Fixes #4401.
変更の背景
このコミットは、Go言語のnet/http/cgi
パッケージにおけるWindows環境でのテストの不安定性を解決するために行われました。特に、Issue #4401で報告されていた問題に対処しています。Windows環境では、ファイルパスの表現や改行コードの扱いがUnix系システムと異なるため、CGIスクリプトが期待通りに動作しない、あるいはテストが失敗するといった問題が発生しがちです。このコミットは、これらのWindows特有の問題を吸収し、テストの信頼性を向上させることを目的としています。また、これまでWindows環境でスキップされていたTestDirWindows
テストを有効にすることで、Windows環境でのCGI機能の動作保証を強化しています。
前提知識の解説
CGI (Common Gateway Interface)
CGIは、Webサーバーが外部プログラム(CGIスクリプト)を実行し、その出力をWebブラウザに返すための標準的なインターフェースです。Webサーバーは、HTTPリクエストの情報を環境変数としてCGIスクリプトに渡し、スクリプトは標準出力にHTTPヘッダとコンテンツを出力します。これにより、動的なWebページを生成したり、データベースと連携したりすることが可能になります。
net/http/cgi
パッケージ
Go言語のnet/http/cgi
パッケージは、GoプログラムをCGIスクリプトとして実行するための機能を提供します。これにより、既存のWebサーバー(Apache, Nginxなど)のCGI機能を利用してGoアプリケーションをデプロイすることができます。このパッケージは、CGI環境変数の処理、標準入力/出力のハンドリング、およびCGIスクリプトの実行を抽象化します。
Windowsにおけるパスと改行コード
WindowsとUnix系OSでは、ファイルパスの区切り文字と改行コードが異なります。
- パス区切り文字:
- Windows:
\
(バックスラッシュ) - Unix系:
/
(スラッシュ)
- Windows:
- 改行コード:
- Windows: CRLF (
\r\n
) - Unix系: LF (
\n
)
- Windows: CRLF (
これらの違いは、特にCGIスクリプトがファイルパスを扱ったり、HTTPヘッダやコンテンツを出力したりする際に問題を引き起こす可能性があります。PerlスクリプトのようなCGIスクリプトがWindows上で実行される場合、パスの正規化や改行コードの適切な処理が重要になります。
Perlの$^O
変数とgetcwd()
関数
$^O
: Perlの特殊変数で、現在のオペレーティングシステムを示す文字列を格納します。例えば、WindowsではMSWin32
やmsys
といった値を取ります。getcwd()
: 現在の作業ディレクトリのパスを返します。Windows環境では、Perlのバージョンや実行環境(例: msys)によって、返されるパスの形式が異なる場合があります(例:C:\path\to\dir
、/c/path/to/dir
)。
技術的詳細
このコミットは、主に以下の2つのファイルに変更を加えています。
src/pkg/net/http/cgi/host_test.go
: テストのスキップ条件を変更し、Windows環境でのTestDirWindows
テストを有効化しています。また、Perlが見つからない場合にテストをスキップするログを追加しています。src/pkg/net/http/cgi/testdata/test.cgi
: CGIテスト用のPerlスクリプトです。Windows環境でのパスの正規化ロジックと、改行コードの扱いが変更されています。
host_test.go
の変更点
TestDirWindows
テストのスキップ条件から|| runtime.GOOS != "windows"
が削除されました。これにより、このテストはWindows環境で常に実行されるようになります。- Perlが見つからない場合にテストをスキップする際に、より詳細なログメッセージ(
Skipping test: perl not found.
)が出力されるようになりました。これはデバッグの際に役立ちます。
test.cgi
の変更点
このPerlスクリプトの変更はより重要で、Windows環境でのCGIの動作に関する根本的な問題を解決しようとしています。
- パス正規化ロジックの削除と再構築:
- 以前は
on_windows
とnormalize_windows_path
というサブルーチンが存在し、WindowsパスをGoの形式に正規化しようとしていました。しかし、このロジックは削除されました。 - 新しいロジックでは、
getcwd()
で取得したパスがWindows形式(C:\...
)でない場合(例: msys環境で/c/...
のような形式で返される場合)、cmd.exe
を使用して現在のディレクトリを正確に取得する試みが行われています。これは、Perlのgetcwd()
が返すパスが環境によって一貫しない問題に対処するためです。
- 以前は
- 改行コードの統一:
- 以前は
$NL
変数を使って改行コードを動的に設定していましたが、この変数は削除され、すべてのprint
文で明示的にWindowsの改行コードである\r\n
を使用するように変更されました。これにより、HTTPヘッダやコンテンツの出力がWindows環境で正しく解釈されるようになります。
- 以前は
- 不要なテストコードの削除:
Tests::test_normalize_windows_paths
という内部テストコードが削除されました。これは、新しいパス正規化アプローチにより不要になったためです。
これらの変更により、Windows環境におけるCGIスクリプトの実行がより堅牢になり、特にパスの解釈と改行コードの扱いの不一致によるテストの失敗が減少することが期待されます。
コアとなるコードの変更箇所
src/pkg/net/http/cgi/host_test.go
--- a/src/pkg/net/http/cgi/host_test.go
+++ b/src/pkg/net/http/cgi/host_test.go
@@ -404,7 +404,8 @@ func TestDirUnix(t *testing.T) {
}
func TestDirWindows(t *testing.T) {
- if skipTest(t) || runtime.GOOS != "windows" {
+ if runtime.GOOS != "windows" {
+ t.Logf("Skipping windows specific test.")
return
}
@@ -414,6 +415,7 @@ func TestDirWindows(t *testing.T) {
var err error
perl, err = exec.LookPath("perl")
if err != nil {
+ t.Logf("Skipping test: perl not found.")
return
}
perl, _ = filepath.Abs(perl)
@@ -456,6 +458,7 @@ func TestEnvOverride(t *testing.T) {
var err error
perl, err = exec.LookPath("perl")
if err != nil {
+ t.Logf("Skipping test: perl not found.")
return
}
perl, _ = filepath.Abs(perl)
src/pkg/net/http/cgi/testdata/test.cgi
--- a/src/pkg/net/http/cgi/testdata/test.cgi
+++ b/src/pkg/net/http/cgi/testdata/test.cgi
@@ -10,23 +10,6 @@ use Cwd;
binmode STDOUT;
-sub on_windows {
- return $^O eq 'MSWin32' || $^O eq 'msys';
-}
-
-# normalize_windows_path normalizes the various Windows Perl path
-# formats into Go's format.
-sub normalize_windows_path {
- my $dir = shift;
- return $dir unless on_windows();
- $dir =~ s!^[a-z]:!uc($&)!e;
- if ($dir =~ s!^/([a-zA-Z])/!!) {
- $dir = uc($1) . ":\\$dir";
- }
- $dir =~ s!/!\\!g;
- return $dir;
-}
-
my $q = MiniCGI->new;
my $params = $q->Vars;
@@ -35,40 +18,43 @@ if ($params->{"loc"}) {
exit(0);
}
-my $NL = "\r\n";
-$NL = "\n" if $params->{mode} eq "NL";
-
-my $p = sub {
- print "$_[0]$NL";
-};
-
-# With carriage returns
-$p->("Content-Type: text/html");
-$p->("X-CGI-Pid: $$");
-$p->("X-Test-Header: X-Test-Value");
-$p->("");
+print "Content-Type: text/html\r\n";
+print "X-CGI-Pid: $$\r\n";
+print "X-Test-Header: X-Test-Value\r\n";
+print "\r\n";
if ($params->{"bigresponse"}) {
for (1..1024) {
- print "A" x 1024, "\n";
+ print "A" x 1024, "\r\n";
}\
exit 0;\
}\
-print "test=Hello CGI\n";
+print "test=Hello CGI\r\n";
foreach my $k (sort keys %$params) {
- print "param-$k=$params->{$k}\n";
+ print "param-$k=$params->{$k}\r\n";
}\
foreach my $k (sort keys %ENV) {
my $clean_env = $ENV{$k};\
$clean_env =~ s/[\n\r]//g;\
- print "env-$k=$clean_env\n";
+ print "env-$k=$clean_env\r\n";
}\
-my $dir = normalize_windows_path(getcwd());
-print "cwd=$dir\n";
+# NOTE: msys perl returns /c/go/src/... not C:\go\....
+my $dir = getcwd();
+if ($^O eq 'MSWin32' || $^O eq 'msys') {
+ if ($dir =~ /^.:/) {
+ $dir =~ s!/!\\!g;
+ } else {
+ my $cmd = $ENV{'COMSPEC'} || 'c:\\windows\\system32\\cmd.exe';
+ $cmd =~ s!\\!/!g;
+ $dir = `$cmd /c cd`;
+ chomp $dir;
+ }
+}
+print "cwd=$dir\r\n";
# A minimal version of CGI.pm, for people without the perl-modules
# package installed. (CGI.pm used to be part of the Perl core, but
@@ -102,24 +88,3 @@ sub _urldecode {
$v =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
return $v;
}
-\
-package Tests;\
-\
-sub test_normalize_windows_paths {\
- my @tests = (\
- {in => "C:\\foo\\bar", want => "C:\\foo\\bar"},\
- {in => "C:/foo/bar", want => "C:\\foo\\bar"},\
- {in => "c:/foo/bar", want => "C:\\foo\\bar"},\
- {in => "/c/foo/bar", want => "C:\\foo\\bar"},\
- );\
- foreach my $tt (@tests) {\
- my $got = ::normalize_windows_path($tt->{in});\
- unless ($got eq $tt->{want}) {\
- die "For path $tt->{in}, normalize = $got; want $tt->{want}\\n";
- }\
- }\
-}\
-\
-BEGIN {\
- test_normalize_windows_paths() if ::on_windows();\
-}\
コアとなるコードの解説
host_test.go
TestDirWindows
関数内のif runtime.GOOS != "windows"
の条件からskipTest(t) ||
が削除されました。これは、このテストがWindows環境でのみ実行されるべきであり、他のプラットフォームではスキップされるべきであることを明確にしています。また、Windows環境以外でスキップされる場合にt.Logf("Skipping windows specific test.")
というログが出力されるようになりました。exec.LookPath("perl")
でPerlが見つからなかった場合、t.Logf("Skipping test: perl not found.")
というログが出力されるようになりました。これにより、テストがスキップされた理由が明確になり、デバッグが容易になります。
test.cgi
- パス正規化ロジックの変更:
- 以前の
on_windows
およびnormalize_windows_path
サブルーチンは削除されました。これらのサブルーチンは、Windowsパスの様々な形式をGoが期待する形式に変換しようとしていましたが、そのロジックが複雑で、すべてのケースをカバーできていなかった可能性があります。 - 新しいロジックでは、
getcwd()
で取得したパスがWindowsのドライブレター形式(例:C:
)で始まらない場合(これはmsys環境などで/c/go/src/...
のような形式でパスが返される場合に発生します)、cmd.exe
を呼び出して現在のディレクトリを正確に取得するようになりました。my $cmd = $ENV{'COMSPEC'} || 'c:\\windows\\system32\\cmd.exe';
:COMSPEC
環境変数(通常はcmd.exe
のパス)を取得し、なければデフォルトのパスを使用します。$cmd =~ s!\\!/!g;
:コマンドパスのバックスラッシュをスラッシュに変換します。これは、Perlがシェルコマンドを実行する際にスラッシュパスを好むためです。$dir =
$cmd /c cd;
:cmd.exe /c cd
を実行して、現在のディレクトリを正確に取得します。/c
オプションは、コマンドを実行した後にcmd.exe
を終了させます。chomp $dir;
:取得したディレクトリパスの末尾の改行文字を削除します。
- この変更により、Perlの
getcwd()
が返すパスの形式に依存せず、Windows環境で常に正しい現在の作業ディレクトリを取得できるようになります。
- 以前の
- 改行コードの統一:
- 以前は
$NL
変数を使って改行コードを動的に設定していましたが、この変数は削除されました。 - すべての
print
文で、明示的にWindowsの改行コードである\r\n
が使用されるようになりました。これにより、CGIスクリプトが出力するHTTPヘッダやコンテンツが、Windows環境で正しく解釈され、表示されることが保証されます。特に、HTTPヘッダはCRLFで区切られることがRFCで定められているため、この変更は重要です。
- 以前は
- テストコードの削除:
Tests::test_normalize_windows_paths
という内部テストコードが削除されました。これは、新しいパス正規化アプローチにより、以前の正規化ロジックが不要になったためです。
これらの変更は、Windows環境におけるCGIスクリプトの実行の堅牢性を高め、特にパスの解釈と改行コードの扱いの不一致によるテストの失敗を減少させることを目的としています。
関連リンク
- Go Issue #4401: https://github.com/golang/go/issues/4401
- Go CL 6847072: https://golang.org/cl/6847072
参考にした情報源リンク
- Common Gateway Interface (CGI): https://ja.wikipedia.org/wiki/Common_Gateway_Interface
- Perlの特殊変数
$^O
: https://perldoc.perl.org/perlvar#%24%5EO - Perlの
Cwd
モジュール: https://perldoc.perl.org/Cwd - RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1 (Section 2.2 Basic Rules): https://www.rfc-editor.org/rfc/rfc2616#section-2.2 (HTTPヘッダの改行コードに関する情報)
- Windowsのパスと改行コードに関する一般的な情報源 (例: Microsoft Learn, Stack Overflowなど)