ドキュメント
プロジェクト

Caddyfileのサポート

Caddyモジュールは、登録されると、名前空間によってネイティブJSON設定に自動的に追加され、使用可能かつドキュメント化されます。 これにより、Caddyfileのサポートは完全にオプションとなりますが、Caddyfileを好むユーザーからよく要求されます。

Unmarshaler

モジュールにCaddyfileのサポートを追加するには、caddyfile.Unmarshalerインターフェースを実装するだけです。 トークンの解析方法によって、モジュールのCaddyfile構文を選択できます。

アンマーシャラーの仕事は、渡されたcaddyfile.Dispenserを使用して、モジュールの型のフィールドを設定するなど、モジュールの型を設定することです。 たとえば、Gizmoという名前のモジュール型には、次のメソッドがあります。

// UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax:
//
//     gizmo <name> [<option>]
//
func (g *Gizmo) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
	d.Next() // consume directive name

	if !d.Args(&g.Name) {
		// not enough args
		return d.ArgErr()
	}
	if d.NextArg() {
		// optional arg
		g.Option = d.Val()
	}
	if d.NextArg() {
		// too many args
		return d.ArgErr()
	}

	return nil
}

godocコメントに構文を記述することをお勧めします。 Caddyfileの解析の詳細については、caddyfileパッケージのgodocを参照してください。

ディレクティブ名トークンは、単純なd.Next()呼び出しで消費/スキップできます。

d.NextArg()またはd.RemainingArgs()を使用して、欠落または過剰な引数がないか確認してください。 単純な「無効なケース」メッセージにはd.ArgErr()を使用し、問題の説明(および理想的には、推奨される解決策)を含む有用なエラーメッセージを作成するには、d.Errf("some message")を使用します。

また、インターフェースが正しく満たされていることを確認するために、インターフェースガードを追加する必要があります

var _ caddyfile.Unmarshaler = (*Gizmo)(nil)

ブロック

1行に収まらない設定を受け入れるには、サブディレクティブを持つブロックを許可することをお勧めします。 これは、d.NextBlock()を使用して、元のネストレベルに戻るまで反復処理することで実行できます。

for nesting := d.Nesting(); d.NextBlock(nesting); {
	switch d.Val() {
		case "sub_directive_1":
			// ...
		case "sub_directive_2":
			// ...
	}
}

ループの各反復がセグメント全体(行またはブロック)を消費する限り、これはブロックを処理する洗練された方法です。

HTTPディレクティブ

HTTP Caddyfileは、CaddyのデフォルトのCaddyfileアダプター構文(または「サーバタイプ」)です。 拡張可能であるため、モジュール用に独自の「トップレベル」ディレクティブを登録できます。

func init() {
	httpcaddyfile.RegisterDirective("gizmo", parseCaddyfile)
}

ディレクティブが単一のHTTPハンドラーのみを返す場合(よくあることですが)、RegisterHandlerDirectiveの方が簡単です。

func init() {
	httpcaddyfile.RegisterHandlerDirective("gizmo", parseCaddyfileHandler)
}

基本的な考え方は、ディレクティブに関連付ける解析関数が、1つ以上のConfigValue値を返すということです。 (または、RegisterHandlerDirectiveを使用する場合は、設定されたcaddyhttp.MiddlewareHandler値を直接返します。) 各設定値は「クラス」に関連付けられており、HTTP Caddyfileアダプターが最終的なJSON設定のどの部分で使用できるかを知るのに役立ちます。 すべての設定値は、アダプターが最終的なJSON設定を構築するときにそこから引き出す山にダンプされます。

この設計により、ディレクティブは認識されているクラスの任意の設定値を返すことができます。つまり、HTTP Caddyfileアダプターが指定されたクラスを持つ設定の任意の部分に影響を与えることができます。

UnmarshalCaddyfile()メソッドをすでに実装している場合、解析関数は次のように簡単です。

// parseCaddyfileHandler unmarshals tokens from h into a new middleware handler value.
func parseCaddyfileHandler(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
	var g Gizmo
	err := g.UnmarshalCaddyfile(h.Dispenser)
	return g, err
}

httpcaddyfile.Helperタイプの使用方法の詳細については、httpcaddyfileパッケージのgodocを参照してください。

ハンドラーの順序

HTTPミドルウェア/ハンドラー値を返すすべてのディレクティブは、正しい順序で評価する必要があります。 たとえば、サイトのルートディレクトリを設定するハンドラーは、ルートディレクトリにアクセスするハンドラーの前に来る必要があります。そうすれば、ディレクトリパスがわかります。

HTTP Caddyfileには、標準ディレクティブのハードコードされた順序があります。 これにより、ユーザーはWebサーバーの最も一般的な機能の実装の詳細を知る必要がなくなり、正しい構成を簡単に記述できるようになります。 単一のハードコードされたリストは、Caddyfileの拡張可能な性質を考慮しても、非決定性を防ぎます。

新しいハンドラーディレクティブを登録する場合、(routeブロックの外側で)使用するには、そのリストに追加する必要があります。 これは、次の2つの方法のいずれかを使用して設定で行われます。

  • orderグローバルオプションは、その設定の標準順序のみを変更します。 たとえば、order mydir before respondは、新しいディレクティブmydirを挿入して、respondハンドラーの前に評価します。 その後、ディレクティブは通常どおり使用できます。
  • または、routeブロックでディレクティブを使用します。 ルートブロック内のディレクティブは並べ替えられないため、ルートブロックで使用されるディレクティブはリストに表示される必要はありません。

ユーザーがディレクティブを正しく使用できるように、リストのどこにディレクティブを配置するのが適切かをユーザーに説明してください.

クラス

この表は、HTTP Caddyfileアダプターによって認識される、エクスポートされた型を持つ各クラスについて説明しています。

クラス名 予想される型 説明
bind []string サーバーリスナーのバインドアドレス
route caddyhttp.Route HTTPハンドラールート
error_route *caddyhttp.Subroute HTTPエラー処理ルート
tls.connection_policy *caddytls.ConnectionPolicy TLS接続ポリシー
tls.cert_issuer certmagic.Issuer TLS証明書発行者
tls.cert_loader caddytls.CertificateLoader TLS証明書ローダー

サーバータイプ

構造的には、Caddyfileは単純な形式であるため、ニーズに合わせてさまざまなタイプのCaddyfile形式(「サーバタイプ」と呼ばれることもあります)を使用できます。

デフォルトのCaddyfile形式はHTTP Caddyfileであり、おそらくおなじみでしょう。 この形式は、主にhttpアプリを設定しますが、Caddy設定構造の他の部分(たとえば、証明書を読み込んで自動化するtlsアプリ)に設定を散在させる可能性があります。

HTTP以外のアプリを設定するには、独自のサーバタイプを使用する独自の設定アダプターを実装することをお勧めします。 Caddyfileアダプターは実際に入力を解析して、サーバーブロックとオプションのリストを提供します。その構造を理解してJSON設定に変換するのはアダプター次第です。