[インデックス 11995] ファイルの概要
このコミットは、Go言語の標準ライブラリにおける複数の重要な変更を統合したものです。主に、net/url
パッケージのAPI改善、cmd/fix
ツールの汎用化、およびos.Exec
からsyscall.Exec
への移行に関連する修正が含まれています。これらの変更は、Go 1のリリースに向けたAPIの安定化と改善の一環として行われました。
コミット
commit b27bd42a9a4bd3e358499f517e8102fa152dd2ba
Author: Russ Cox <rsc@golang.org>
Date: Thu Feb 16 23:46:28 2012 -0500
net/url: API
Convert cryptotype to general go1rename fix.
Add os.Exec -> syscall.Exec fix along with new
URL fixes.
Fixes #2946.
R=golang-dev, r, dsymonds
CC=golang-dev
https://golang.org/cl/5672072
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b27bd42a9a4bd3e358499f517e8102fa152dd2ba
元コミット内容
このコミットの元々の内容は、net/url
パッケージのAPI変更、cmd/fix
ツールのcryptotype
からgo1rename
への汎用化、そしてos.Exec
からsyscall.Exec
への修正をまとめたものです。特に、net/url
のParse
関数がURLフラグメント(#
以降の部分)を適切に処理するようになり、ParseRequest
がParseRequestURI
にリネームされ、ParseWithFragment
が削除されました。また、http
パッケージのクッキー関連のエラーメッセージのタイポも修正されています。
変更の背景
このコミットは、Go 1のリリースに向けたGo言語の標準ライブラリのAPI安定化と改善という大きな流れの中で行われました。
-
net/url
パッケージのAPI改善:- 従来の
url.Parse
はURLフラグメント(#
以降の部分)を無視していました。しかし、クライアントサイドのJavaScriptなどでフラグメントが重要な意味を持つ場合があり、これをGoのURLパーサーで適切に扱えるようにする必要がありました。 ParseRequest
とParseRequestURI
の区別は、HTTPリクエストのURIが常に絶対URIまたは絶対パスとして解釈されるべきであるというHTTPの仕様に合わせたものです。これにより、URLの解釈における曖昧さを排除し、より堅牢な処理を可能にしました。ParseWithFragment
の削除は、Parse
関数自体がフラグメントを処理するようになったため、冗長になったためです。APIをシンプルに保つための変更と言えます。
- 従来の
-
cmd/fix
ツールの汎用化:cmd/fix
は、Go言語のバージョンアップに伴うAPI変更や非互換性を自動的に修正するためのツールです。元々cryptotype
という特定の型のリネームに対応していましたが、Go 1のリリースでは他にも多くのAPI変更が予定されていたため、より汎用的なgo1rename
という名前に変更され、様々なリネームに対応できるように拡張されました。これにより、開発者がGo 1への移行をスムーズに行えるように支援する目的がありました。
-
os.Exec
からsyscall.Exec
への移行:os.Exec
は、Go 1のリリースに向けてsyscall.Exec
に統合されることになりました。これは、Goの標準ライブラリにおけるシステムコール関連の機能の整理と一貫性の向上を目的としています。syscall
パッケージは低レベルなシステムコールへのアクセスを提供し、os
パッケージはより高レベルなOS操作を提供するという役割分担が明確化されました。
-
Issue #2946の修正:
- このコミットは、GoのIssue #2946を修正しています。このIssueは、
net/url
パッケージのParse
関数がURLフラグメントを正しく扱わないという問題に関連していると考えられます。
- このコミットは、GoのIssue #2946を修正しています。このIssueは、
前提知識の解説
Go言語のcmd/fix
ツール
cmd/fix
は、Go言語のソースコードを自動的に修正し、新しいGoのバージョンで導入されたAPIの変更や非互換性に対応させるためのコマンドラインツールです。Go言語は後方互換性を重視していますが、メジャーバージョンアップ(Go 1など)では一部のAPIが変更されることがあります。cmd/fix
は、このような変更に対して、古いAPIの使用箇所を新しいAPIに自動的に書き換えることで、開発者の移行作業の負担を軽減します。
URLの構造とフラグメント
URL(Uniform Resource Locator)は、インターネット上のリソースの位置を示す識別子です。一般的なURLの構造は以下のようになります。
scheme://user:password@host:port/path?query#fragment
- scheme: プロトコル(例:
http
,https
,ftp
) - host: ホスト名またはIPアドレス
- port: ポート番号
- path: サーバー上のリソースのパス
- query: クエリ文字列(
?
以降のキーと値のペア) - fragment: フラグメント識別子(
#
以降の部分)。これは通常、Webブラウザがページ内の特定の位置(アンカー)にスクロールするために使用され、HTTPリクエストとしてサーバーに送信されることはありません。
HTTPリクエストにおけるURIの解釈
HTTP/1.1の仕様(RFC 2616)では、HTTPリクエストのURIは、絶対URI(例: http://example.com/path
)または絶対パス(例: /path?query
)のいずれかとして解釈されるべきであると定められています。Webブラウザは、ユーザーが入力したURLからフラグメント部分を削除してからHTTPリクエストを送信します。したがって、サーバーサイドでURLを解析する際には、フラグメントが存在しないことを前提とすることが一般的です。
Go言語のos
パッケージとsyscall
パッケージ
os
パッケージ: オペレーティングシステム(OS)の機能へのプラットフォームに依存しないインターフェースを提供します。ファイル操作、プロセス管理、環境変数へのアクセスなど、高レベルなOS操作を抽象化して提供します。syscall
パッケージ: 低レベルなシステムコールへの直接的なアクセスを提供します。OS固有のシステムコールをGoの関数としてラップしており、より詳細な制御が必要な場合や、特定のOS機能を利用する場合に使用されます。Go 1の設計では、os
パッケージがよりユーザーフレンドリーな高レベルAPIを提供し、syscall
パッケージが低レベルなプリミティブを提供するという役割分担が明確化されました。
技術的詳細
net/url
パッケージの変更
このコミットにおけるnet/url
パッケージの最も重要な変更点は、Parse
関数がURLフラグメントを処理するようになったことです。
-
Parse(rawurl string) (*URL, error)
:- 変更前はフラグメントを無視していました。
- 変更後は、
rawurl
から#
で区切られたフラグメント部分を抽出し、URL
構造体のFragment
フィールドに格納するようになりました。これにより、Parse
関数はURL全体をより忠実に表現できるようになりました。 - 内部的には、
split
関数を使用してフラグメントを切り離し、残りの部分を既存のparse
関数(内部関数)で解析し、その後フラグメントをunescape
してURL.Fragment
に設定しています。
-
ParseRequest(rawurl string) (*URL, error)
からParseRequestURI(rawurl string) (*URL, error)
へのリネーム:- 関数名が
ParseRequest
からParseRequestURI
に変更されました。これは、HTTPリクエストのURIが「URI」であり、「URL」ではないというHTTPの仕様に合わせた、より正確な命名です。 - この関数は、HTTPリクエストで受信したURIを解析することを目的としており、
rawurl
が絶対URIまたは絶対パスとして解釈されることを前提としています。Webブラウザはフラグメントをサーバーに送信しないため、この関数はフラグメントを処理しません。
- 関数名が
-
ParseWithFragment(rawurl string) (*URL, error)
の削除:Parse
関数自体がフラグメントを処理するようになったため、ParseWithFragment
関数は不要となり削除されました。これにより、APIの重複が解消され、シンプルになりました。
cmd/fix
ツールの変更
src/cmd/fix/cryptotype.go
からsrc/cmd/fix/go1rename.go
へのリネーム:- ファイル名が変更され、
cryptotypeFix
がgo1renameFix
に、cryptotypeReplace
がgo1renameReplace
にそれぞれリネームされました。 - これにより、特定の暗号型のリネームだけでなく、Go 1で導入された様々なパッケージレベルの名前変更に対応できる汎用的な修正ツールとしての役割が明確になりました。
go1renameReplace
には、net/url
パッケージのurl.ParseWithReference
からurl.Parse
への変更、url.ParseRequest
からurl.ParseRequestURI
への変更、そしてos.Exec
からsyscall.Exec
への変更が追加されました。これは、cmd/fix
がこれらのAPI変更を自動的に修正するためのルールを保持していることを意味します。
- ファイル名が変更され、
os.Exec
からsyscall.Exec
への移行
cmd/fix/go1rename.go
に、os.Exec
をsyscall.Exec
にリネームするルールが追加されました。これは、Go 1のAPI安定化の一環として、プロセス実行に関する低レベルな機能がsyscall
パッケージに集約されたためです。
net/http/request.go
の変更
var ErrNoCookie = errors.New("http: named cookied not present")
のタイポがhttp: named cookie not present
に修正されました。これは小さな修正ですが、エラーメッセージの正確性を向上させます。req.URL, err = url.ParseRequest(rawurl)
がreq.URL, err = url.ParseRequestURI(rawurl)
に変更されました。これは、net/url
パッケージの関数名変更に合わせた修正です。
コアとなるコードの変更箇所
src/cmd/fix/go1rename.go
(旧 cryptotype.go
)
--- a/src/cmd/fix/cryptotype.go
+++ b/src/cmd/fix/go1rename.go
@@ -4,17 +4,22 @@
package main
-var cryptotypeFix = fix{
- "cryptotype",
+func init() {
+ register(go1renameFix)
+}
+
+var go1renameFix = fix{
+ "go1rename",
"2012-02-12",
- renameFix(cryptotypeReplace),
- `Rewrite uses of concrete cipher types to refer to the generic cipher.Block.
+ renameFix(go1renameReplace),
+ `Rewrite package-level names that have been renamed in Go 1.
http://codereview.appspot.com/5625045/
+http://codereview.appspot.com/5672072/
`,
}
-var cryptotypeReplace = []rename{
+var go1renameReplace = []rename{
{
OldImport: "crypto/aes",
NewImport: "crypto/cipher",
@@ -33,4 +38,22 @@ var cryptotypeReplace = []rename{
Old: "*des.TripleDESCipher",
New: "cipher.Block",
},\
++ {
++ OldImport: "net/url",
++ NewImport: "",
++ Old: "url.ParseWithReference",
++ New: "url.Parse",
++ },\
++ {
++ OldImport: "net/url",
++ NewImport: "",
++ Old: "url.ParseRequest",
++ New: "url.ParseRequestURI",
++ },\
++ {
++ OldImport: "os",
++ NewImport: "syscall",
++ Old: "os.Exec",
++ New: "syscall.Exec",
++ },\
}
src/pkg/net/url/url.go
--- a/src/pkg/net/url/url.go
+++ b/src/pkg/net/url/url.go
@@ -321,19 +321,28 @@ func split(s string, c byte, cutc bool) (string, string) {
}
// Parse parses rawurl into a URL structure.
-// The string rawurl is assumed not to have a #fragment suffix.
-// (Web browsers strip #fragment before sending the URL to a web server.)
// The rawurl may be relative or absolute.
func Parse(rawurl string) (url *URL, err error) {
- return parse(rawurl, false)
+ // Cut off #frag
+ u, frag := split(rawurl, '#', true)
+ if url, err = parse(u, false); err != nil {
+ return nil, err
+ }
+ if frag == "" {
+ return url, nil
+ }
+ if url.Fragment, err = unescape(frag, encodeFragment); err != nil {
+ return nil, &Error{"parse", rawurl, err}
+ }
+ return url, nil
}
-// ParseRequest parses rawurl into a URL structure. It assumes that
-// rawurl was received from an HTTP request, so the rawurl is interpreted
+// ParseRequestURI parses rawurl into a URL structure. It assumes that
+// rawurl was received in an HTTP request, so the rawurl is interpreted
// only as an absolute URI or an absolute path.
// The string rawurl is assumed not to have a #fragment suffix.
// (Web browsers strip #fragment before sending the URL to a web server.)
-func ParseRequest(rawurl string) (url *URL, err error) {
+func ParseRequestURI(rawurl string) (url *URL, err error) {
return parse(rawurl, true)
}
@@ -415,22 +424,6 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
return
}
-// ParseWithFragment is like Parse but allows a trailing #fragment.
-func ParseWithFragment(rawurl string) (url *URL, err error) {
- // Cut off #frag
- u, frag := split(rawurl, '#', true)
- if url, err = Parse(u); err != nil {
- return nil, err
- }
- if frag == "" {
- return url, nil
- }
- if url.Fragment, err = unescape(frag, encodeFragment); err != nil {
- return nil, &Error{"parse", rawurl, err}
- }
- return url, nil
-}
-
// String reassembles the URL into a valid URL string.
func (u *URL) String() string {
// TODO: Rewrite to use bytes.Buffer
コアとなるコードの解説
src/cmd/fix/go1rename.go
このファイルは、Go 1への移行を支援するための自動修正ルールを定義しています。
go1renameFix
というfix
構造体が定義され、その中に修正の対象となる古いAPIと新しいAPIのマッピングがgo1renameReplace
としてリストされています。go1renameReplace
スライスには、以下の重要なリネームルールが追加されています。url.ParseWithReference
->url.Parse
:net/url
パッケージのParseWithReference
関数がParse
関数に統合されたことを示します。url.ParseRequest
->url.ParseRequestURI
:net/url
パッケージのParseRequest
関数がParseRequestURI
にリネームされたことを示します。os.Exec
->syscall.Exec
:os
パッケージのExec
関数がsyscall
パッケージのExec
関数に移行されたことを示します。
これらのルールにより、古いGoのコードベースでこれらのAPIが使用されている場合、go fix
コマンドを実行することで自動的に新しいAPIに書き換えられます。
src/pkg/net/url/url.go
このファイルは、URLの解析と操作を行うnet/url
パッケージの主要な実装です。
Parse
関数の変更:- 変更前は、
Parse
関数はURLフラグメント(#
以降の部分)を無視していました。 - 変更後、
Parse
関数はまずsplit
ヘルパー関数を使ってrawurl
からフラグメント部分(frag
)を切り離します。 - 残りのURL部分(
u
)を内部のparse
関数で解析し、URL
構造体を作成します。 - もしフラグメントが存在すれば、
unescape
関数を使ってフラグメントをデコードし、その結果をURL
構造体のFragment
フィールドに設定します。これにより、Parse
関数がURLの全要素を正確に解析できるようになりました。
- 変更前は、
ParseRequest
からParseRequestURI
へのリネーム:ParseRequest
関数がParseRequestURI
にリネームされました。この関数は、HTTPリクエストで受信したURIを解析するために使用され、フラグメントは含まれないことを前提としています。
ParseWithFragment
関数の削除:Parse
関数がフラグメントを処理するようになったため、ParseWithFragment
関数は冗長となり、コードベースから削除されました。これにより、APIの重複が解消され、パッケージの設計がよりクリーンになりました。
これらの変更により、net/url
パッケージはURLの解析においてより柔軟かつ正確になり、HTTPリリクエストのURIの解釈もより厳密になりました。
関連リンク
- Go Issue #2946: https://github.com/golang/go/issues/2946
- Go Code Review 5672072: https://golang.org/cl/5672072
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のソースコード
- Go言語のIssueトラッカー
- Go言語のコードレビューシステム
- RFC 2616 (HTTP/1.1)
- URLの構造に関する一般的な情報源 (例: Wikipedia)
- Go言語の
os
およびsyscall
パッケージに関するドキュメント