Documentation
¶
Overview ¶
httputilパッケージは、net/httpパッケージにある一般的なものと補完するHTTPユーティリティ関数を提供します。
Index ¶
- Variables
- func DumpRequest(req *http.Request, body bool) ([]byte, error)
- func DumpRequestOut(req *http.Request, body bool) ([]byte, error)
- func DumpResponse(resp *http.Response, body bool) ([]byte, error)
- func NewChunkedReader(r io.Reader) io.Reader
- func NewChunkedWriter(w io.Writer) io.WriteCloser
- type BufferPool
- type ClientConndeprecated
- func (cc *ClientConn) Close() error
- func (cc *ClientConn) Do(req *http.Request) (*http.Response, error)
- func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader)
- func (cc *ClientConn) Pending() int
- func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error)
- func (cc *ClientConn) Write(req *http.Request) error
- type ProxyRequest
- type ReverseProxy
- type ServerConndeprecated
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // Deprecated: 使用されていません。 ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"} // Deprecated: 使用されていません。 ErrClosed = &http.ProtocolError{ErrorString: "connection closed by user"} // Deprecated: 使用されていません。 ErrPipeline = &http.ProtocolError{ErrorString: "pipeline error"} )
var ErrLineTooLong = internal.ErrLineTooLong
ErrLineTooLong は、行が長すぎる不正なチャンクデータを読み取ると返されます。
Functions ¶
func DumpRequest ¶
DumpRequestは与えられたリクエストをHTTP/1.xのワイヤープレゼンテーションで返します。 クライアントのリクエストをデバッグするために、サーバーが使用するべきです。 返されるプレゼンテーションは近似値です。初期リクエストの一部の詳細は、http.Request に解析される際に失われます。 特にヘッダーフィールド名の順序と大文字小文字の情報が失われます。複数の値を持つヘッダーの値の順序は保持されます。 HTTP/2のリクエストは、元のバイナリ表現ではなく、HTTP/1.xの形式でダンプされます。
bodyがtrueの場合、DumpRequestはbodyも返します。そのため、req.Bodyを消費し、同じバイトを返す新しい io.ReadCloser に置き換えます。 DumpRequestがエラーを返す場合、reqの状態は未定義です。
http.Request.Write のドキュメントには、ダンプに含まれるreqのフィールドの詳細が記載されています。
Example ¶
package main
import (
"github.com/shogo82148/std/fmt"
"github.com/shogo82148/std/io"
"github.com/shogo82148/std/log"
"github.com/shogo82148/std/net/http"
"github.com/shogo82148/std/net/http/httptest"
"github.com/shogo82148/std/net/http/httputil"
"github.com/shogo82148/std/strings"
)
func main() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
dump, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "%q", dump)
}))
defer ts.Close()
const body = "Go is a general-purpose language designed with systems programming in mind."
req, err := http.NewRequest("POST", ts.URL, strings.NewReader(body))
if err != nil {
log.Fatal(err)
}
req.Host = "www.example.org"
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", b)
}
Output: "POST / HTTP/1.1\r\nHost: www.example.org\r\nAccept-Encoding: gzip\r\nContent-Length: 75\r\nUser-Agent: Go-http-client/1.1\r\n\r\nGo is a general-purpose language designed with systems programming in mind."
func DumpRequestOut ¶
DumpRequestOutは、outgoingのクライアントリクエスト用の DumpRequest のようなものです。これには、標準の http.Transport が追加するUser-Agentなど、任意のヘッダーが含まれます。
Example ¶
package main
import (
"github.com/shogo82148/std/fmt"
"github.com/shogo82148/std/log"
"github.com/shogo82148/std/net/http"
"github.com/shogo82148/std/net/http/httputil"
"github.com/shogo82148/std/strings"
)
func main() {
const body = "Go is a general-purpose language designed with systems programming in mind."
req, err := http.NewRequest("PUT", "http://www.example.org", strings.NewReader(body))
if err != nil {
log.Fatal(err)
}
dump, err := httputil.DumpRequestOut(req, true)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%q", dump)
}
Output: "PUT / HTTP/1.1\r\nHost: www.example.org\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 75\r\nAccept-Encoding: gzip\r\n\r\nGo is a general-purpose language designed with systems programming in mind."
func DumpResponse ¶
DumpResponseはDumpRequestと同様ですが、レスポンスをダンプします。
Example ¶
package main
import (
"github.com/shogo82148/std/fmt"
"github.com/shogo82148/std/log"
"github.com/shogo82148/std/net/http"
"github.com/shogo82148/std/net/http/httptest"
"github.com/shogo82148/std/net/http/httputil"
)
func main() {
const body = "Go is a general-purpose language designed with systems programming in mind."
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Date", "Wed, 19 Jul 1972 19:00:00 GMT")
fmt.Fprintln(w, body)
}))
defer ts.Close()
resp, err := http.Get(ts.URL)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
dump, err := httputil.DumpResponse(resp, true)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%q", dump)
}
Output: "HTTP/1.1 200 OK\r\nContent-Length: 76\r\nContent-Type: text/plain; charset=utf-8\r\nDate: Wed, 19 Jul 1972 19:00:00 GMT\r\n\r\nGo is a general-purpose language designed with systems programming in mind.\n"
func NewChunkedReader ¶
NewChunkedReaderは、rから読み込まれたデータをHTTPの「チャンク」形式から変換して返す新しいchunkedReaderを返します。 chunkedReaderは、最後の長さ0のチャンクが読み込まれた時に io.EOF を返します。
NewChunkedReaderは通常のアプリケーションでは必要ありません。httpパッケージは、応答ボディを読み込む際に自動的にチャンクをデコードします。
func NewChunkedWriter ¶
func NewChunkedWriter(w io.Writer) io.WriteCloser
NewChunkedWriter は、w に書き込む前に書き込みを HTTP の "chunked" フォーマットに変換する新しい chunkedWriter を返します。返された chunkedWriter を閉じると、ストリームの終わりを示す最後の長さが 0 のチャンクが送信されますが、トレーラーの後に表示される最後の CRLF は送信されません。トレーラーと最後の CRLF は別個に書き込む必要があります。 NewChunkedWriter は通常のアプリケーションでは必要ありません。http パッケージは、ハンドラが Content-Length ヘッダーを設定しない場合、自動的にチャンキングを追加します。ハンドラ内で NewChunkedWriter を使用すると、二重チャンキングや Content-Length 長さでのチャンキングなど、間違った結果になります。
Types ¶
type BufferPool ¶ added in v1.6.0
BufferPoolは io.CopyBuffer で使用するための一時的なバイトスライスを取得および返却するためのインターフェースです。
type ClientConn
deprecated
type ClientConn struct {
// contains filtered or unexported fields
}
ClientConnはGoの初期のHTTP実装の遺物です。 低レベルで古く、現在のGoのHTTPスタックでは使用されていません。 Go 1の前に削除すべきでした。
Deprecated: 代わりにpackage net/http のClientまたはTransportを使用してください。
func NewClientConn
deprecated
func NewProxyClientConn
deprecated
func (*ClientConn) Close ¶
func (cc *ClientConn) Close() error
Closeは ClientConn.Hijack を呼び出し、その後下層の接続も閉じます。
func (*ClientConn) Hijack ¶
func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader)
Hijackは ClientConn を切り離し、基礎となる接続と読み込み側のbufioを返します。 また、左にデータが残っているかもしれない読み込み側のbufioも返します。 HijackはユーザーまたはReadがkeep-aliveロジックの終了をシグナルした前に呼び出すことができます。 ユーザーは、ClientConn.Read または ClientConn.Writeが進行中の間にHijackを呼び出さないでください。
func (*ClientConn) Read ¶
Readはワイヤから次のレスポンスを読み込みます。有効なレスポンスは ErrPersistEOF と一緒に返される場合があります。これはリモートがこれがサービスされる最後のリクエストであることを要求したことを意味します。Readは ClientConn.Write と同時に呼び出すことができますが、他のReadと同時には呼び出すことはできません。
func (*ClientConn) Write ¶
func (cc *ClientConn) Write(req *http.Request) error
Writeはリクエストを書き込みます。もしHTTP keep-aliveによって接続が閉じられた場合、ErrPersistEOF エラーが返されます。もしreq.Closeがtrueの場合、このリクエストの後にkeep-alive接続が論理的に閉じられ、対向サーバーに通知されます。ErrUnexpectedEOFは、リモートが基礎となるTCP接続を閉じたことを示しており、通常は正常な終了と見なされます。
type ProxyRequest ¶ added in v1.20.0
type ProxyRequest struct {
In *http.Request
// Outはプロキシに送信されるリクエストです。
// Rewrite関数はこのリクエストを変更または置換する場合があります。
// Rewriteが呼び出される前に、ホップバイホップのヘッダーはこのリクエストから削除されます。
Out *http.Request
}
ProxyRequestは、ReverseProxy によって書き換えられるリクエストを含んでいます。
func (*ProxyRequest) SetURL ¶ added in v1.20.0
func (r *ProxyRequest) SetURL(target *url.URL)
SetURLは、アウトバウンドリクエストをtargetで指定されたスキーム、ホスト、およびベースパスにルーティングします。 例えば、targetのパスが "/base" で、受信リクエストが "/dir" の場合、ターゲットリクエストは "/base/dir" になります。 受信パスを結合せずにリクエストをルーティングしたい場合は、r.Out.URL を直接設定してください。
SetURLは、アウトバウンドのHostヘッダをターゲットのホストに合わせて書き換えます。 インバウンドのリクエストのHostヘッダを保持するために(NewSingleHostReverseProxy のデフォルトの動作):
rewriteFunc := func(r *httputil.ProxyRequest) {
r.SetURL(url)
r.Out.Host = r.In.Host
}
func (*ProxyRequest) SetXForwarded ¶ added in v1.20.0
func (r *ProxyRequest) SetXForwarded()
SetXForwardedは、出力リクエストのX-Forwarded-For、X-Forwarded-Host、およびX-Forwarded-Protoヘッダーを設定します。
- X-Forwarded-Forヘッダーは、クライアントのIPアドレスに設定されます。 - X-Forwarded-Hostヘッダーは、クライアントが要求したホスト名に設定されます。 - X-Forwarded-Protoヘッダーは、入力リクエストがTLS対応の接続で行われたかどうかに応じて、「http」または「https」に設定されます。
出力リクエストに既存のX-Forwarded-Forヘッダーが含まれている場合、SetXForwardedはクライアントのIPアドレスを追加します。 SetXForwardedを呼び出す前に、入力リクエストのX-Forwarded-Forヘッダー(Director関数を使用して ReverseProxy を使用している場合のデフォルト動作)をコピーして、 入力リクエストのX-Forwarded-Forヘッダーに追加します:
rewriteFunc := func(r *httputil.ProxyRequest) {
r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
r.SetXForwarded()
}
type ReverseProxy ¶
type ReverseProxy struct {
// Rewriteは、リクエストを変更してTransportを使用して送信される新しいリクエストに変換する関数でなければなりません。
// そのレスポンスは、元のクライアントに変更せずにコピーされます。
// Rewriteは、戻る後に提供されたProxyRequestまたはその内容にアクセスしてはいけません。
//
// Forwarded、X-Forwarded、X-Forwarded-Host、およびX-Forwarded-Protoヘッダーは、
// Rewriteが呼び出される前に送信リクエストから削除されます。また、ProxyRequest.SetXForwardedメソッドも参照してください。
//
// 解析できないクエリパラメータは、Rewriteが呼び出される前に送信リクエストから削除されます。
// Rewrite関数は、インバウンドURLのRawQueryをアウトバウンドURLにコピーして、元のパラメータ文字列を保持することがあります。
// 注意:これは、プロキシのクエリパラメータの解釈がダウンストリームサーバーと一致しない場合にセキュリティの問題を引き起こす可能性があります。
//
// RewriteまたはDirectorのいずれか一つのみ設定できます。
Rewrite func(*ProxyRequest)
// Director(ディレクター)は、リクエストを変更して新しいリクエストをTransport(トランスポート)を使用して送信します。そのレスポンスは、元のクライアントに変更せずにコピーされます。Directorは、戻った後に提供されたリクエストにアクセスしてはいけません。
// デフォルトでは、X-Forwarded-ForヘッダーはクライアントのIPアドレスの値に設定されます。もし既にX-Forwarded-Forヘッダーが存在する場合、クライアントのIPは既存の値に追加されます。ただし、特殊なケースとして、リクエストのRequest.Headerマップにヘッダーが存在しているが、値がnilである場合(Director関数によって設定された場合など)、X-Forwarded-Forヘッダーは変更されません。
// IPスプーフィングを防ぐために、クライアントまたは信頼できないプロキシから送られてきたプリエクスティングのX-Forwarded-Forヘッダーを削除するようにしてください。
// ディレクターが戻った後にリクエストからホップバイホップヘッダーが削除されます。これにより、ディレクターが追加したヘッダーも削除される可能性があります。リクエストの変更を保持するためには、リライト関数を使用してください。
// ディレクターが戻った後、リクエストのRequest.Formが設定されている場合は、解析できないクエリパラメータが送信先のリクエストから削除されます。
// RewriteまたはDirectorのうち、最大1つが設定できます。
Director func(*http.Request)
// プロキシリクエストを実行するために使用されるトランスポートです。
// nil の場合、http.DefaultTransport が使用されます。
Transport http.RoundTripper
// FlushIntervalは、レスポンスボディをクライアントにコピーする際のフラッシュ間隔を指定します。
// ゼロの場合、定期的なフラッシュは行われません。
// 負の値は、クライアントへの各書き込みの直後にすぐにフラッシュすることを意味します。
// FlushIntervalは、ReverseProxyがストリーミングレスポンスとしてレスポンスを認識するか、またはContentLengthが-1の場合は無視されます。
// このようなレスポンスの場合、書き込みはすぐにクライアントにフラッシュされます。
FlushInterval time.Duration
// ErrorLogは、リクエストをプロキシする際に発生したエラーのオプションのロガーを指定します。
// nilの場合、ログはlogパッケージの標準ロガーを使用して行われます。
ErrorLog *log.Logger
// BufferPoolは、io.CopyBufferがHTTPのレスポンスボディをコピーする際に使用するバイトスライスを取得するためのオプションのバッファプールを指定します。
BufferPool BufferPool
// ModifyResponseはオプションの関数であり、バックエンドからのレスポンスを変更する役割を持ちます。
// この関数は、バックエンドからのレスポンスがある場合に呼び出されます(HTTPのステータスコードに関係なく)。
// バックエンドに到達できない場合は、オプションのErrorHandlerが呼び出され、ModifyResponseは呼び出されません。
//
// ホップバイホップヘッダーは、ModifyResponseを呼び出す前にレスポンスから削除されます。
// ModifyResponseは、Alt-Svcなど、運用モデルに合わせて追加のヘッダーを削除する必要がある場合があります。
//
// ModifyResponseがエラーを返した場合、ErrorHandlerがそのエラー値で呼び出されます。
// ErrorHandlerがnilの場合は、デフォルトの実装が使用されます。
ModifyResponse func(*http.Response) error
// ErrorHandlerは、バックエンドに到達したエラーやModifyResponseからのエラーを処理するオプションの関数です。
//
// nilの場合、デフォルトでは提供されたエラーをログに記録し、502 Status Bad Gatewayレスポンスを返します。
ErrorHandler func(http.ResponseWriter, *http.Request, error)
}
ReverseProxyは、受信したリクエストを別のサーバーに送信し、レスポンスをクライアントにプロキシするHTTPハンドラです。
1xxレスポンスは、基盤となるトランスポートがClientTrace.Got1xxResponseをサポートしている場合、クライアントに転送されます。
ホップバイホップヘッダー(RFC 9110のセクション7.6.1参照)、 Connection、Proxy-Connection、Keep-Alive、Proxy-Authenticate、 Proxy-Authorization、TE、Trailer、Transfer-Encoding、Upgradeなどは、 クライアントリクエストおよびバックエンドレスポンスから削除されます。 Rewrite関数を使用してリクエストにホップバイホップヘッダーを追加したり、 ModifyResponse関数を使用してレスポンスからそれらを削除することができます。
Example ¶
package main
import (
"github.com/shogo82148/std/fmt"
"github.com/shogo82148/std/io"
"github.com/shogo82148/std/log"
"github.com/shogo82148/std/net/http"
"github.com/shogo82148/std/net/http/httptest"
"github.com/shogo82148/std/net/http/httputil"
"github.com/shogo82148/std/net/url"
)
func main() {
backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "this call was relayed by the reverse proxy")
}))
defer backendServer.Close()
rpURL, err := url.Parse(backendServer.URL)
if err != nil {
log.Fatal(err)
}
frontendProxy := httptest.NewServer(&httputil.ReverseProxy{
Rewrite: func(r *httputil.ProxyRequest) {
r.SetXForwarded()
r.SetURL(rpURL)
},
})
defer frontendProxy.Close()
resp, err := http.Get(frontendProxy.URL)
if err != nil {
log.Fatal(err)
}
b, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", b)
}
Output: this call was relayed by the reverse proxy
func NewSingleHostReverseProxy ¶
func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy
NewSingleHostReverseProxyは、URLを指定されたスキーム、ホスト、およびベースパスにルーティングする新しい ReverseProxy を返します。ターゲットのパスが"/base"であり、受信したリクエストが"/dir"である場合、ターゲットのリクエストは/base/dirになります。 NewSingleHostReverseProxyは、Hostヘッダーを書き換えません。
NewSingleHostReverseProxyが提供する以上のカスタマイズをするには、Rewrite関数を使用して直接ReverseProxyを使用してください。ProxyRequest SetURLメソッドを使用してアウトバウンドリクエストをルーティングすることができます(ただし、SetURLはデフォルトでアウトバウンドリクエストのHostヘッダーを書き換えます)。
proxy := &ReverseProxy{
Rewrite: func(r *ProxyRequest) {
r.SetURL(target)
r.Out.Host = r.In.Host // 必要に応じて
},
}
func (*ReverseProxy) ServeHTTP ¶
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request)
type ServerConn
deprecated
type ServerConn struct {
// contains filtered or unexported fields
}
ServerConnはGoの初期のHTTP実装の遺物です。 それは低レベルで古く、Goの現在のHTTPスタックでは使用されていません。 Go 1よりも前に削除すべきでした。
Deprecated: 代わりに net/http パッケージのServerを使用してください。
func NewServerConn
deprecated
func (*ServerConn) Close ¶
func (sc *ServerConn) Close() error
Closeによって ServerConn.Hijack され、その後基礎となる接続も閉じます。
func (*ServerConn) Hijack ¶
func (sc *ServerConn) Hijack() (net.Conn, *bufio.Reader)
Hijackは ServerConn を切り離し、基礎となる接続と、残っているデータを持つ読み込み側のbufioを返します。 HijackはReadがkeep-aliveロジックの終了を示すまえに呼び出される可能性があります。ユーザーは ServerConn.Read や ServerConn.Write が進行中の間にHijackを呼び出すべきではありません。
func (*ServerConn) Read ¶
func (sc *ServerConn) Read() (*http.Request, error)
Readはワイヤ上の次のリクエストを返します。ErrPersistEOF は、優雅にもうリクエストがないことが確定した場合に返されます(例えば、HTTP/1.0接続の最初のリクエスト後、またはHTTP/1.1接続のConnection: close後など)。
func (*ServerConn) Write ¶
Writeはreqに応じたrespを書き込みます。接続を正常に終了させるためには、 Response.Closeフィールドをtrueに設定してください。Writeは、ServerConn.Read 側で返される すべてのエラーに関係なく、エラーが返されるまで操作可能であると見なされるべきです。