[インデックス 14439] ファイルの概要
このコミットは、Go言語の net/http/cgi
パッケージ内のテストデータである test.cgi
ファイルに対する変更です。具体的には、Windows環境におけるPerl CGIスクリプトのテストの堅牢性を向上させることを目的としています。特に、cmd.exe
の特定のパスへの依存を排除し、Windowsパスの正規化をより適切に行うための修正が含まれています。
コミット
commit e070aeae779b641a5180c1807de19bfc9e5864c2
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Mon Nov 19 10:40:13 2012 -0800
net/http/cgi: more windows perl test work
Don't rely on finding cmd.exe in a particular spot.
Fixes #4401
R=golang-dev, krautz
CC=golang-dev
https://golang.org/cl/6842066
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e070aeae779b641a5180c1807de19bfc9e5864c2
元コミット内容
このコミットは、net/http/cgi
パッケージのテストスクリプト test.cgi
において、Windows環境でのPerlの動作に関する問題を修正するものです。以前のバージョンでは、現在の作業ディレクトリ(CWD)を取得するために cmd.exe
を呼び出すという、特定のパスに依存した回避策が用いられていました。このコミットは、その cmd.exe
への依存を取り除き、Windowsパスの正規化をPerlスクリプト内で直接行う新しい関数を導入することで、テストの信頼性を高めています。
変更の背景
Go言語の net/http/cgi
パッケージは、CGI(Common Gateway Interface)プロトコルを介して外部プログラムを実行し、その出力をHTTPレスポンスとして提供するための機能を提供します。このパッケージのテストには、Perlで書かれたCGIスクリプト test.cgi
が使用されています。
Windows環境では、Perlの getcwd()
関数が返すパスの形式が、Goの期待する形式と異なる場合や、msys
(Minimal SYStem) のような環境ではUnix形式のパス(例: /c/go/src/...
)を返すことがありました。このため、以前の test.cgi
では、Windows上で現在の作業ディレクトリを取得する際に、環境変数 COMSPEC
または固定パス c:\\windows\\system32\\cmd.exe
を使用して cmd.exe
を呼び出し、その cd
コマンドの出力からCWDを取得するという、やや複雑で環境に依存するロジックが組み込まれていました。
この cmd.exe
への依存は、cmd.exe
が特定の場所に存在しない場合や、異なるバージョンのWindowsでパスが変更された場合にテストが失敗する可能性がありました。また、msys
環境でのパスの不整合も問題となっていました。
このコミットは、これらの問題を解決し、Windows環境でのCGIテストの堅牢性と移植性を向上させることを目的としています。具体的には、GoのIssue #4401で報告された問題に対応しています。
前提知識の解説
- CGI (Common Gateway Interface): Webサーバーが外部プログラム(CGIスクリプト)と連携するための標準的なインターフェースです。WebサーバーはHTTPリクエストの情報をCGIスクリプトに渡し、スクリプトは処理結果を標準出力に書き出し、WebサーバーがそれをHTTPレスポンスとしてクライアントに返します。
- Perl: スクリプト言語の一つで、特にCGIスクリプトの記述によく用いられます。
test.cgi
はPerlで書かれています。 net/http/cgi
パッケージ (Go言語): Go言語の標準ライブラリの一部で、CGIプロトコルを実装し、GoアプリケーションからCGIスクリプトを実行したり、Goアプリケーション自体をCGIとして動作させたりするための機能を提供します。- Windowsのパス形式: Windowsでは、パスは通常、ドライブレター(例:
C:
)から始まり、ディレクトリの区切り文字としてバックスラッシュ(\
)を使用します(例:C:\Users\User\Documents
)。 - Unix/Linuxのパス形式: Unix系OSでは、パスはルートディレクトリ(
/
)から始まり、ディレクトリの区切り文字としてスラッシュ(/
)を使用します(例:/home/user/documents
)。 - MSYS/Cygwin: Windows上でUnix/Linuxのような環境を提供するツールです。これらの環境では、WindowsのパスがUnix形式(例:
C:\foo\bar
が/c/foo/bar
)に変換されることがあります。 getcwd()
(Perl): Perlの組み込み関数で、現在の作業ディレクトリのパスを返します。Windows環境では、この関数の挙動が環境によって異なることが問題の原因となっていました。cmd.exe
: Windowsのコマンドプロンプトの実行ファイルです。cd
コマンドは現在の作業ディレクトリを表示するために使用されます。$^O
(Perl): Perlの特殊変数で、現在のオペレーティングシステムの名前を格納しています。WindowsではMSWin32
やmsys
などの値を取ります。
技術的詳細
このコミットの主要な技術的変更点は、Windows環境におけるパスの正規化ロジックを test.cgi
スクリプト内に直接組み込んだことです。
-
on_windows
サブルーチンの導入:- このサブルーチンは、現在の実行環境がWindowsであるかどうかを判定します。Perlの特殊変数
$^O
の値が'MSWin32'
または'msys'
であるかをチェックします。これにより、Windows固有の処理を条件付きで実行できるようになります。
- このサブルーチンは、現在の実行環境がWindowsであるかどうかを判定します。Perlの特殊変数
-
normalize_windows_path
サブルーチンの導入:- このサブルーチンは、様々な形式のWindowsパスをGoが期待する標準的なWindowsパス形式に正規化します。
- ドライブレターの正規化:
^[a-z]:
のような小文字のドライブレターを大文字に変換します(例:c:/foo
をC:/foo
に)。 - MSYS/Cygwin形式パスの変換:
/c/foo/bar
のようなUnix形式のパスで、先頭が/ドライブレター/
となっているものを、C:\foo\bar
のようなWindows形式に変換します。これは正規表現s!^/([a-zA-Z])/!!
と置換uc($1) . ":\\\\$dir"
を用いて行われます。 - スラッシュからバックスラッシュへの変換: すべてのスラッシュ(
/
)をバックスラッシュ(\
)に変換します。これはWindowsのパス区切り文字に合わせるためです。 - この関数により、
getcwd()
が返すパスがどのような形式であっても、Goのテストが期待する一貫したWindowsパス形式に変換されるようになります。
-
cmd.exe
呼び出しロジックの削除とnormalize_windows_path
の適用:- 以前の
cmd.exe
を呼び出してCWDを取得する複雑なロジックが削除されました。 - 代わりに、Perlの標準関数
getcwd()
で取得したパスを、新しく導入されたnormalize_windows_path
サブルーチンで正規化するようになりました。これにより、外部コマンドへの依存が解消され、コードが簡潔かつ堅牢になりました。
- 以前の
-
テストケースの追加:
Tests
パッケージ内にtest_normalize_windows_paths
というテストサブルーチンが追加されました。- このテストは、
normalize_windows_path
が正しく機能するかどうかを検証するためのものです。様々な入力パス(例:C:\\foo\\bar
,C:/foo/bar
,c:/foo/bar
,/c/foo/bar
)に対して、期待される正規化された出力(C:\\foo\\bar
)が得られるかをチェックします。 - このテストは
on_windows()
が真の場合、つまりWindows環境でのみ実行されます。これにより、Windows固有のパス正規化ロジックが正しく動作することが保証されます。
これらの変更により、test.cgi
はWindows環境におけるパスの差異をより適切に扱い、cmd.exe
の存在やパスに依存することなく、安定して動作するようになりました。
コアとなるコードの変更箇所
変更は 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,6 +10,23 @@ 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;
@@ -41,29 +58,18 @@ if ($params->{"bigresponse"}) {
print "test=Hello CGI\n";
foreach my $k (sort keys %$params) {
- print "param-$k=$params->{$k}\n";
+ print "param-$k=$params->{$k}\n";
}
foreach my $k (sort keys %ENV) {
- my $clean_env = $ENV{$k};
- $clean_env =~ s/[\n\r]//g;
- print "env-$k=$clean_env\n";
+ my $clean_env = $ENV{$k};
+ $clean_env =~ s/[\n\r]//g;
+ print "env-$k=$clean_env\n";
}
-# NOTE: don't call getcwd() for windows.
-# msys return /c/go/src/... not C:\go\...
-my $dir;
-if ($^O eq 'MSWin32' || $^O eq 'msys') {
- my $cmd = $ENV{'COMSPEC'} || 'c:\\windows\\system32\\cmd.exe';
- $cmd =~ s!\\!/!g;
- $dir = `$cmd /c cd`;
- chomp $dir;
-} else {
- $dir = getcwd();
-}
+my $dir = normalize_windows_path(getcwd());
print "cwd=$dir\n";
-\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
# some distros now bundle perl-base and perl-modules separately...)
@@ -96,3 +102,24 @@ sub _urldecode {
$v =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
return $v;
}\n+\n+package Tests;\n+\n+sub test_normalize_windows_paths {\n+ my @tests = (\n+ {in => "C:\\\\foo\\\\bar", want => "C:\\\\foo\\\\bar"},\n+ {in => "C:/foo/bar", want => "C:\\\\foo\\\\bar"},\n+ {in => "c:/foo/bar", want => "C:\\\\foo\\\\bar"},\n+ {in => "/c/foo/bar", want => "C:\\\\foo\\\\bar"},\n+ );\n+ foreach my $tt (@tests) {\n+ my $got = ::normalize_windows_path($tt->{in});\n+ unless ($got eq $tt->{want}) {\n+ die "For path $tt->{in}, normalize = $got; want $tt->{want}\\n";\n+ }\n+ }\n+}\n+\n+BEGIN {\n+ test_normalize_windows_paths() if ::on_windows();\n+}\n```
## コアとなるコードの解説
* **`sub on_windows`**:
```perl
sub on_windows {
return $^O eq 'MSWin32' || $^O eq 'msys';
}
```
この関数は、Perlの組み込み変数 `$^O` をチェックして、現在のOSがWindows(`MSWin32`)またはMSYS環境(`msys`)であるかを判定します。これにより、Windows固有のパス処理を条件付きで適用できます。
* **`sub normalize_windows_path`**:
```perl
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;
}
```
この関数がパス正規化の核心です。
1. `return $dir unless on_windows();`: Windows環境でない場合は、パスをそのまま返します。
2. `$dir =~ s!^[a-z]:!uc($&)!e;`: パスの先頭が小文字のドライブレター(例: `c:`)で始まる場合、それを大文字に変換します(例: `C:`)。`$&` はマッチした文字列全体を指します。
3. `if ($dir =~ s!^/([a-zA-Z])/!!) { $dir = uc($1) . ":\\\\$dir"; }`: パスが `/c/foo` のようなMSYS/Cygwin形式の場合、これを `C:\foo` のようなWindows形式に変換します。`$1` は正規表現の最初のキャプチャグループ(ここではドライブレター)を指します。
4. `$dir =~ s!/!\\\\!g;`: すべてのスラッシュ(`/`)をバックスラッシュ(`\`)に変換します。`\\\\` はPerlの文字列リテラルでバックスラッシュをエスケープしたものです。
* **CWD取得ロジックの変更**:
```perl
-my $dir;
-if ($^O eq 'MSWin32' || $^O eq 'msys') {
- my $cmd = $ENV{'COMSPEC'} || 'c:\\windows\\system32\\cmd.exe';
- $cmd =~ s!\\!/!g;
- $dir = `$cmd /c cd`;
- chomp $dir;
-} else {
- $dir = getcwd();
-}
+my $dir = normalize_windows_path(getcwd());
```
以前の `cmd.exe` を呼び出す複雑なロジックが削除され、`getcwd()` で取得したパスを `normalize_windows_path` で処理する簡潔な形に変更されました。
* **テストケース `test_normalize_windows_paths`**:
```perl
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();
}
```
このテストは、`normalize_windows_path` 関数が様々な入力に対して正しくパスを正規化するかを検証します。`BEGIN` ブロック内で `on_windows()` が真の場合にのみ実行されるため、Windows環境でのみテストが実行されます。
## 関連リンク
* Go Issue #4401: [https://github.com/golang/go/issues/4401](https://github.com/golang/go/issues/4401)
* Go CL 6842066: [https://golang.org/cl/6842066](https://golang.org/cl/6842066)
## 参考にした情報源リンク
* Perl `$^O` 変数に関するドキュメント: [https://perldoc.perl.org/perlvar#%24%5EO](https://perldoc.perl.org/perlvar#%24%5EO)
* Perl `getcwd()` 関数に関するドキュメント: [https://perldoc.perl.org/Cwd#getcwd](https://perldoc.perl.org/Cwd#getcwd)
* CGI (Common Gateway Interface) の概要: [https://ja.wikipedia.org/wiki/Common_Gateway_Interface](https://ja.wikipedia.org/wiki/Common_Gateway_Interface)
* Windowsのパス形式に関する情報 (Microsoft Docsなど)
* MSYS/Cygwinのパス変換に関する情報