Project Gemini

投機的仕様

v0.16.1, 2022/01/30

これは、Project Geminiの実際的な仕様のラフなスケッチだが、徐々にそうではなくなりつつあるものである。 まだ確定してはいないが、この仕様に対するさらなる変更は、比較的小さなものになると思われる。 この疑似仕様に合わせてコードを書いたとしても、おそらく翌週の大規模な変更によって全く機能しなくなる、ということはないと断言できるが、それでもプロトコルの進行中の開発に目を向けて、必要に応じて変更することが望ましい。

これは、人々がたくさんの古いphlog(訳注: Solderpunk氏のGopherブログのこと)の投稿を読んだり、メモを取ったりすることなく、私(訳注: Solderpunk氏)が考えていることを素早く知ることができるようにするために提供されているものである。

本ドキュメントに関するフィードバックは大歓迎である。是非 solderpunk@posteo.net までメールされたし。

本書で使用されている規約

本文書におけるキーワード「MUST」「MUST NOT」「REQUIRED」「SHALL」「SHALL NOT」「SHOULD」「SHOULD NOT」「RECOMMENDED」「MAY」「OPTIONAL」は、BCP14の記載に従って解釈されるものとする。

1 概要

Geminiは、リクエストとレスポンスのトランザクションを特徴とするクライアントサーバプロトコルで、大まかにはgopherやHTTPに類するものである。 接続は1つのトランザクションの終了時に閉じられ、再利用はできない。 GeminiがTCP/IPで提供される場合、サーバはポート番号 1965 (ジェミニ計画における初の有人ミッション・ジェミニ3号は1965年3月に飛行した)をリッスンする必要がある。 これは非特権ポート(unprivileged port)なので、例えばサーバがGoで書かれていて、従来の方法で権限を削除できない場合でも、「nobody」ユーザとしてサーバを非常に容易く実行可能である。

1.1 Geminiトランザクション

Geminiのトランザクションは1種類で、おおよそgopherリクエストやHTTPのGETリクエストに相当するものである。 トランザクションは次のように行われる。

(訳注: C=クライアント、S=サーバ)

C: コネクションを開く

S: 接続を受け入れる

C/S: TLSハンドシェイクを完了する(4章参照)

C: サーバ証明書を検証する(4.2 参照)

C: リクエスト(CRLFで終端する1行)を送信する(2章参照)

S: レスポンスヘッダ(CRLFで終わる1行)を送信するが、成功しない場合は接続を閉じる(3.1 と 3.2 参照)

S: レスポンスボディ(テキストまたはバイナリデータ)を送信する(3.3 参照)

S: 接続を閉じる (TLS の close_notify メッセージを含む。4章参照)

C: レスポンスを処理する (3.4 参照)

クライアントは、サーバが接続を閉じてからレスポンスの処理を開始することを待つ義務を負わない、ということに注意すること。 これは、典型的な条件下では接続を閉じる責任はサーバにあり、レスポンスボディの完了後直ちに接続を閉じるべきであることを強調するために、単純化/明確化の意味で記載されるものである。

1.2 Gemini URIスキーム

Geminiを介してホストされるリソースは、「gemini」スキームを持つURIを使用して識別される。 このスキームは、RFC3986で定義された一般的URI構文(訳注: generic URI syntax、以下「一般的構文」)と構文的に互換性を持つが、一般的構文のすべての要素をサポートしているわけではない。 特に、 authority 要素は許可されており必須であるが、その userinfo 副要素は許可されていない(NOT)。 host 副要素は必須である。 port 副要素は任意であり、デフォルト値は 1965 である。 path 、 query 、fragment 要素は使用可能で、一般的な構文で定義されている以上の特別な意味を持たない。 空のパスは、「/」のみで構成されるパスと同意である。 パス中のスペースは、 + ではなく %20 としてエンコードされるべきである。

クライアントは、リクエストを送る前に(RFC3986のセクション6.2.3に従って) URIを正規化するべき(SHOULD)であり(セクション2参照)、また、サーバはリクエストを処理する前に受け取ったURIを正規化するべきである(SHOULD)。

2 Geminiリクエスト

Geminiリクエストとは、以下の構造を持つCRLF終端の1行のことである。

<URL><CR><LF>

<URL> はUTF-8で符号化された絶対URLで、スキームを含み、最大長は1024バイトである。 リクエストは U+FEFF バイトオーダーマークで始まってはならない(MUST NOT)。

パスやセレクタだけでなく、絶対URLを送信することは、実質的にHTTPの「Host」ヘッダを構築することと同じである。 これは、同じIPアドレス上で複数のGeminiドメインを仮想的にホストすることを許可するものである。 また、サーバをプロキシとして動作させることも可能である。 リクエストに「gemini」以外のスキームを含めることで、例えばGemini上でGopherリソースを取得するためなどに、サーバをプロトコル変換ゲートウェイとして動作させることを許可できる。 プロキシは任意であり、大多数のサーバは自分自身の単一あるいは複数のドメインのリソースに対するリクエストにのみレスポンスすることが期待される。

クライアントはリクエストの中で最初に現れる <CR><LF> の後に何も送ってはならず、サーバは最初に現れる <CR><LF> の後に送られたものを無視しなければならない(MUST NOT)。

3 Geminiレスポンス

Geminiレスポンスは、CRLFで終端する1つのヘッダ行と、オプションでそれに続くレスポンスボディから構成される。

3.1 レスポンスヘッダ

Geminiレスポンスヘッダとは以下のようなものである。

<STATUS><SPACE><META><CR><LF>

<STATUS> は2桁の数字のステータスコードで、後述の 3.2 および 付録1 に記載されているとおりのものである。

<SPACE> はスペース1文字、すなわちバイト 0x20 である。

<META> はUTF-8で符号化された最大長 1024 バイトの文字列で、その意味は <STATUS> に依存する。

レスポンスヘッダ全体とその部分文字列としての <META> の両方が、 U+FEFF バイトオーダーマークで始まってはならない(MUST NOT)。

<STATUS> が「SUCCESS」のコード範囲(訳注: 3.2.2 参照)に属さない場合、サーバはヘッダを送信した後に接続を閉じなければならず (MUST)、レスポンスボディを送信してはならない(MUST NOT)。

サーバが2桁でない <STATUS> や 1024 バイトを超える <META> を送信した場合、クライアントは接続を閉じてレスポンスヘッダを無視し、ユーザにエラーを通知すべきである(SHOULD)。

3.2 スターテスコード

Geminiは、2桁の数字によるステータスコードを使用する。 関連するステータスコードは、同じ1桁目を共有する。 ここで重要なのは、Geminiステータスコードの1桁目が、HTTPのように「クライアントエラー」や「サーバエラー」のような曖昧なカテゴリにコードをグループ化しないということである。 その代わり、1桁目だけでクライアントがレスポンスをどのように処理すべきかを判断するのに十分な情報を提供する。 なので、1桁目のみを参照する、シンプルで完全なクライアントを書くことが可能である。 2桁目はより細かい情報を提供するものであり、サーバのログを明確にしたり、より快適な対話型クライアントを書いたり、コンテンツアグリゲータや検索エンジンのクローラなど、より堅牢で知的な自動化クライアントを書いたりすることを可能とする。

レスポンスコードの1桁目は、レスポンスが6つのカテゴリのいずれかに属することを意味しており、 <META> 行のセマンティクスを定義するものである。

3.2.1 1x (INPUT)

1 で始まるステータスコードは INPUT ステータスコードで、意味は以下のとおりである。

リクエストされたリソースは一行のテキストによるユーザ入力を受け付ける。 <META> 行はユーザに表示されるべきプロンプトである。 同じリソースを再度リクエストし、ユーザの入力をクエリコンポーネントとして含める必要がある。 クエリはRFC3986の通常の一般的なURLの定義に従ってリクエストに含まれる。つまり、パスと?で区切られるものである。 ユーザの入力に使用される予約文字は、RFC3986に従って「パーセントエンコード」されなければならず、スペース文字もパーセントエンコードされなければならない。

3.2.2 2x (SUCCESS)

2で始まるステータスコードは SUCCESS ステータスコードで、意味は以下のとおりである。

リクエストは正常に処理され、レスポンスボディがレスポンスヘッダの後に続く。 <META> 行は、レスポンスボディに適用されるMIMEメディアタイプである。

3.2.3 3x (REDIRECT)

3 で始まるステータスコードは、REDIRECT ステータスコードで、意味は以下のとおりである。

サーバは、クライアントをリクエストされたリソースの新しい場所へとリダイレクトしている。 レスポンスボディは存在しない。 <META>はリクエストされたリソースへの新しいURLである。 URLは絶対か相対のどちらかである。 相対URLの場合には、元のリクエストで使用されたURLに対して解決される必要がある。 元のリクエストで使用されたURLがクエリ文字列を含んでいた場合、クライアントはこの文字列をリダイレクトURLに適用してはならず(MUST NOT)、 代わりにリダイレクトURLを「そのまま」使用する。 リダイレクトは一時的なものとみなされるべきである。すなわち、ク ライアントは元のアドレスでリソースのリクエストを続けるべきであり、ブックマークの自動更新のような便利なアクションは実行すべきでない。

3.2.4 4x (TEMPORARY FAILURE)

4 で始まるステータスコードは、TEMPORARY FAILURE ステータスコードで、意味は以下のとおりである。

リクエストに失敗した。 レスポンスボディは存在しない。 失敗の性質は一時的なものである。すなわち、同一のリクエストが将来成功してもよい(MAY)。 <META> のコンテンツは、失敗に関する追加情報を提供するかもしれず、人間の利用者に表示されるべきものである。

3.2.5 5x (PERMANENT FAILURE)

5 で始まるステータスコードは、PERMANENT FAILURE ステータスコードで、意味は以下のとおりである。

リクエストに失敗した。 レスポンスボディは存在しない。 失敗の性質は永久的なものである。すなわち、将来の同一のリクエストは確実に同じ理由で失敗する。 <META> のコンテンツは失敗に関する追加情報を提供するかもしれず、人間の利用者に表示されるべきものである。 アグリゲータやインデキシングクローラのような自動クライアントは、このリクエストを繰り返すべきでない。

3.2.6 6x (CLIENT CERTIFICATE REQUIRED)

6 で始まるステータスコードは、CLIENT CERTIFICATE REQUIRED ステータスコードで、意味は以下のとおりである。

リクエストされたリソースにアクセスするには、クライアント証明書が必要である。 リクエストが証明書なしで行われた場合は、証明書を添付して再送信する必要がある。 リクエストが証明書付きで行われた場合、サーバーはそれを受け入れなかったということであり、別の証明書でリクエストを繰り返す必要がある。 <META> の内容(および/または特定の6xコード)は、証明書の要件または証明書が拒否された理由についての追加情報を提供するかもしれない。

3.2.7 注記

人間が使う基本的な対話型クライアントでは、エラー 4 と 5 は、 <META> の内容を「ERROR」の見出しで表示するだけで、効果的に同じように扱えることに注意すること。 一時的/永続的エラーの区別は、主に行儀のよい自動化されたクライアントに関連するものである。 基本的なクライアントはクライアント証明書による認証をサポートしないこともでき、その場合、(1、2、3、または4と5の組み合わせで始まるステータスに対して)4つの異なるステータス処理ルーチンだけが必要とされる。

完全な2桁の体系については 付録1 にて詳述されている。 有効な6つの第1桁のそれぞれについて、第2桁が0のコードは、特別な意味合いを持たないその種の一般的なステータスであることに注意すること。 つまり、高度な機能を持たない基本的なサーバーは、10、20、30、40、50のコードを返すことができればよいということである。

Geminiのステータスコードシステムは、2桁目の数字の増加(およびそれに伴う複雑化)が、サーバーとクライアントの両側で完全に「オプトイン」(訳注: Opt-in、ここでは「事前に了解されている」)されるように、慎重に設計されている。

3.3 レスポンスボディ

Gopherのように、レスポンスボディは、テキストまたはバイナリの、素のコンテンツに過ぎない。 圧縮、チャンキング、その他のコンテンツや転送のエンコーディングはサポートされていない。 サーバは最終バイトの後に接続を閉じるが、Gopherの lonely dot のような「レスポンス終了」シグナルは存在しない。

レスポンスボディは、ヘッダーがSUCCESSステータス(すなわち、最初の桁が 2 であるステータスコード)を示すレスポンスにのみ付随する。 そのようなレスポンスでは、 <META> はRFC2046で定義されるMIMEメディアタイプとなる。

インターネットメディアタイプ(訳注: RFCによってはMIME typesとも)は、標準的な形式で登録されている。 Geminiを介して転送されるコンテンツは、次の段落で定義される 「text」タイプを除いて、転送前に適切な標準形式で表現されなければならない(MUST)。

正規形の場合、「text」タイプのメディアサブタイプは、テキストの改行としてCRLFを使用する。 Geminiはこの要件を緩和し、レスポンスボディ全体に対して一貫して行われる場合、改行を表すプレーンLFのみ(プレーンCRのみは不可)でテキストメディアを転送することを許可する。 Geminiクライアントは、CRLFと素のLFを、Gemini経由で受信したテキストメディアにおける改行の代表として受け入れなければならない(MUST)。

MIMEタイプが 「text/」で始まり、charsetが明示的に与えられていない場合、charsetはUTF-8であると仮定されなければならない。 準拠したクライアントは、UTF-8でエンコードされた text/* レスポンスをサポートしなければならない(MUST)。 クライアントはオプションで他のエンコーディングもサポートしてもよい(MAY)。 デコードできない文字コードでレスポンスを受け取ったクライアントは、ゴミを表示する代わりに何が起こったかをユーザに潔く知らせるべきである (SHOULD)。

<META> が空文字列の場合、MIMEタイプのデフォルトは「text/gemini; charset=utf-8」でなければならない(MUST)。 text/gemini メディアタイプは 5章 で定義されている。

3.4 レスポンスボディの扱い

クライアントによるレスポンスのハンドリングは、提供されたMIMEタイプ情報によって通知されるべきである。 Geminiでは、それ自身の一つのMIMEタイプ(text/gemini)を定義している。そのハンドリングはセクション5で後述されている。 他のすべての場合において、クライアントはMIMEタイプに基づいて「何か賢明なこと」を行うべきである。 最小限のクライアントは、他のすべての text/* レスポンスをフォーマットせずに画面に表示し、すべての非テキストレスポンスをディスクに保存するという戦略を採用してもよい。 UNIXシステムのクライアントは、 /etc/mailcap を参照して、非テキストタイプを処理するためにインストールされたプログラムを見つけられるかもしれない。

4 TLS

Geminiのトランザクションには、TLSの使用が必須である。

名前ベースのバーチャルホストを容易にするために、TLSのServer Name Indication(SNI)拡張の使用も必須である。

RFC5246及び8446に従って、Geminiサーバは、完全なレスポンスを送信した後に接続を閉じる前にTLSの `close_notify` メッセージを送信しなければならない(MUST)。 これは、完了したレスポンスと、ネットワークエラーや攻撃によって早期に閉じられたレスポンスとを区別するために不可欠である。

4.1 バージョン要件

サーバはTLSバージョン1.2以上を使わなければならず(MUST)、TLSバージョン1.3以上を使うべきである(SHOULD)。 TLS 1.2は、利用可能な実装ライブラリの幅を極端に狭めることを避けるため、現時点では不本意ながら許可されている。 近い将来、TLS 1.3以上が仕様となることを期待する。 先手を打ちたいクライアントは、TLSバージョン1.2以下を使用するサーバへの接続を拒否してもよい。

4.2 サーバ証明書の検証

クライアントはTLS接続をどのようにでも(全く検証しないことも含めて)検証できるが、強く推奨されるアプローチは、自己署名証明書を第一級市民として扱う、軽量の「TOFU」証明書ピンニングシステムを実装することである。 これにより、ネットワーク上のTLSオーバーヘッドが大幅に削減され(チェーン全体ではなく、1つの証明書を送信する必要がある)、Geminiサイトのセットアップの障壁が低くなる(CAに支払う必要もLet's Encryptのcronジョブを設定する必要もなく、証明書を作成するだけで大丈夫)。

ここでいうTOFUとは、「Trust On First Use」(初回使用時に信頼する)の略で、OpenSSHで使われているような公開鍵セキュリティモデルである。 Geminiクライアントは、初めてサーバーに接続したとき、提示された証明書が何であっても受け入れる。 その証明書のフィンガープリントと有効期限は、サーバーのホスト名と関連付けられた永続的なデータベース (SSHの .known_hosts ファイルのようなもの) に保存される。 そのホスト名へのその後のすべての接続で、受信した証明書のフィンガープリントが計算され、データベース内のものと比較される。 その証明書が以前受け取ったものと異なっていて、かつ以前の証明書の有効期限が過ぎていない場合、ウェブブラウザのユーザが信頼できるCAにつながる署名チェーンがない証明書を受け取ったときに表示されるのと同様の警告が、ユーザに表示されるのである。

このモデルは決して完璧ではないが、悪いものではなく、自己署名証明書を無条件に受け入れるよりは、はるかにマシである。

4.3 クライアント証明書

ウェブ上で見かけるのは稀だが、TLSはクライアントに、証明書を使用してクライアント自身をサーバに識別することを許可する。これは伝統的にサーバが、サーバ自身をクライアントに識別するのとまったく同じ方法である。 Geminiには、クライアントが、クライアント証明書を用いて繰り返しリクエストを行うことを、サーバが帯域内でリクエストする機能がある。 これは、非常に柔軟で安全性が高いだけでなく、非常にシンプルな、いくつかのアプリケーションを持つクライアントアイデンティティ(Client identity)の概念である。

Geminiリクエストは通常、クライアント証明書なしで行われる。 リクエストされたリソースがクライアント証明書を必要としているのにリクエストに含まれていない場合には、サーバーはステータスコード 60 、 61 または 62 でレスポンスできる (クライアント証明書に関するすべてのステータスコードの記述については、 以下の 付録1 参照)。 このようなステータスコードにレスポンスして、生成またはロードされるクライアント証明書は、そのスコープがリクエストURLと同じホスト名と、リクエストURLのパス以下のすべてのパスに束縛される。 例: gemini://example.com/fooへのリクエストがステータス60を返し、ユーザーがこれにレスポンスして新しいクライアント証明書を生成することを選択した場合、ユーザーが証明書を削除するか一時的に無効にするかを決定するまで、gemini://example.com/foo、 gemini://example.com/foo/bar/ 、 gemini://example.com/foo/bar/baz などへの後続のリクエストに対してその同じ証明書を使用する必要がある。 このような操作を容易にし、一般にクライアント証明書の使用を完全に制御できるようにするため、人間ユーザー向けの対話型クライアントの使用が強く推奨される。

5 text/gemini のメディアタイプ

5.1 概要

HTMLがHTTPの「ネイティブ」レスポンスフォーマットであり、プレーンテキストがgopherのネイティブレスポンスフォーマットであるのと同じ意味で、Geminiはそれ自身のネイティブレスポンスフォーマットを定義している。もちろん、レスポンスヘッダーにMIMEタイプを含めるおかげで、Geminiはプレーンテキスト、リッチテキスト、HTML、マークダウン、LaTeXなどの提供に使うことが可能となるのだが。

「text/gemini」タイプのレスポンスボディは、gophermapsとMarkdownからインスピレーションを得た、軽量のハイパーテキストフォーマットの一種である。 このフォーマットはGopherのプレーンテキストよりも豊富なタイポグラフィの可能性を許容しているが、解析は非常に簡単である。 このフォーマットは行指向であり、各行を独立して処理することにより、文書を1回通過させるだけで十分なレンダリングが可能である。 Gopherと同様、リンクは1行に1つしか表示できないので、リストのようなすっきりとした構成が可能なのである。

2桁のGeminiステータスコードが、単純なクライアントが2桁目を無視して正しく機能するように設計されているのと同様に、text/gemini形式は、単純なクライアントがより高度な機能を無視しても、非常に使いやすい状態を維持できるように設計されている。

5.2 パラメータ

最上位のメディアタイプ「text」のサブタイプとして、「text/gemini」はRFC2046で定義されている「charset」パラメータを継承する。 しかし、 3.3 で述べたように、「text」コンテンツをGeminiで転送する場合、「charset」のデフォルト値は 「UTF-8」である。

「text/gemini」サブタイプに固有の追加パラメータとして、「lang」パラメータ が1つ定義されている。「lang」の値は、「text/gemini」ドキュメントのテキストコンテンツを記述している自然言語(複数可)を示す。 「lang」パラメータの存在は任意である。 「lang」パラメータが存在する場合、その解釈はクライアントによって完全に定義される。 例えば、Geminiコンテンツを視覚障害者が利用できるようにするために音声合成技術を使用するクライアントは、コンテンツの発音を改善するために「lang」の値を使用することができる。 テキストを画面に表示するクライアントは、テキストを左から右に表示すべきか、右から左に表示すべきかを決定するために、「lang」の値を使用することができる。 左から右に書かれた言語しか読まない利用者のための単純なクライアントは、単に「lang」の値を無視することができる。 「lang」パラメータが存在しない場合、デフォルト値は仮定されるべきではなく、コンテンツを処理するために何らかの言語の概念を必要とするクライアント(例えば、音声合成スクリーンリーダー)は、「lang」パラメータが存在しない場合にどのように処理するかを決めるために、ユーザ入力を信頼しなければならない。

「lang」パラメータの有効な値は、BCP47に定義されている1つ以上の言語タグのカンマ区切りリストである。 例えば、以下のようになる。

5.3 行指向

前述のように、text/gemini 形式は行指向である。 text/gemini ドキュメントの各行は1つの「行タイプ」を持っている。 行タイプは、最初の3文字を見れば一義的に判断することができる。 行のタイプは、それがどのようにユーザーに表示されるべきかを決定するものである。 ある行の種類に関連する表示やレンダリングの詳細は、厳密にその行に限定される。

行の種類は全部で7種類ある。 しかし、完全に機能し、仕様に準拠したGeminiクライアントは、それらのうちの4つだけを認識し、処理すればよい。これらは「コア行タイプ」です(5.4 参照)。 上級クライアントは、さらに「上級行タイプ」(5.5 参照)を扱うことができる。 シンプルなクライアントは、すべての高度な線種をコア線種の1つと同等に扱うことができ、なおかつ適切なユーザーエクスペリエンスを提供することができる。

5.4 コア行タイプ

コア行タイプは以下の4つである。

5.4.1 テキスト行

テキスト行は最も基本的な行タイプである。以下に定義する他の行タイプの定義と一致しない行については、デフォルトでテキスト行とする。 一般的な text/gemini ドキュメントでは、ほとんどの行がテキスト行となる。

テキスト行は、クライアントのビューポートに適した幅に折り返された後、ユーザーに表示されるべきである(下記参照)。 テキスト行は、「一般的な読み物として視覚的に良く見える方法で」ユーザーに提示するのがもっともらしいが、その正確な意味はクライアントの判断に委ねられる。 例えば、可変幅のフォントを使用したり、スペーシングを正規化し、文の間のスペースを単語の間のスペースより広くしたり、その他のタイポグラフィ上の巧妙さを適用することができるかもしれない。 またクライアントは、フォント、フォントサイズ、テキストと背景色などを変更することによって、ユーザーがテキスト行の外観をカスタマイズすることを許可するかもしれない。著者は、テキスト行の正確なレンダリングを制御することは期待できないだろうが、実際のテキスト内容については制御することができる。 ASCIIアートやコンピュータのソースコードなど、そのように扱われると正しく表示されない可能性のあるコンテンツは、予めフォーマットされたトグル行で囲む必要がある(5.4.3 参照)。

空白行はテキスト行のインスタンスであり、特別な意味はない。 空白行が発生するたびに、垂直方向の空白として個別にレンダリングされるべきである。このやり方はHTMLの <br/> タグと類似のものである。 また連続した空白行は、より少ない空白行に折りたたまれてはならない(NOT)。 また、空白でない連続したテキスト行は、「段落」のようなまとまった単位やブロックを形成しないことにも注意すること。

クライアントのディスプレイデバイスに収まらない長さのテキスト行は、収まるように「折り返す」べきである(SHOULD)。すなわち、長い行は(理想的には空白またはハイフンで)デバイスに適した幅の連続した複数行に分割されるべきである。 この折り返しは、テキストの各行に独立して適用される。 クライアントの表示デバイスより短い複数の連続した行を、より少ない長い行にまとめてはならない(MUST NOT)。

このテキストフォーマットの方法を最大限に活用するために、 text/gemini コンテンツの作成者は、特定の固定幅にハードラップすることを避けるべきで(SHOULD)、これは、テキストは通常80文字以下で折り返されるGopherspaceの慣習とは対照的である。 その代わり、連続したブロックとして表示されるべきテキストは、1つの長い行として記述されるべきである。 ほとんどのテキストエディタは、「ソフトラップ」、つまり、著者の表示装置に合わせて単語境界で折り返された長い行を表示しながらこの種のファイルを書くように設定することができる。

ハードラッピングにこだわる著者は、ディスプレイの幅がハードラッピングの長さと同じかそれ以上のクライアントではコンテンツがきれいに表示されるが、幅の狭いクライアントでは不規則な幅で表示されうる、ということを承知しておかなければならない(MUST)。

5.4.2 リンク行

2文字「=>」で始まる行はリンク行で、以下のような構文になる。

=>[<whitespace>]<URL>[<whitespace><USER-FRIENDLY LINK NAME>]

構文において、

以下の例は全て有効なリンク行である。

=> https://example.org/
=> https://example.org/ An example link
=> https://example.org/foo	Another example link at the same host
=> foo/bar/baz.txt	A relative link
=> 	gopher://example.org:70/1 A gopher link

リンク行のURLは、RFC3986に従って予約文字と空白をパーセントエンコードする必要がある。

リンクURLはgemini以外のスキームを持つことができることに注意すること。 これは、gophermapsが `h` item-type の非標準的な適応によってのみ非 gopher コンテンツにリンクできるのとは異なり、Gemini ドキュメントは他のプロトコルによってホストされるドキュメントに、簡潔かつ華麗にリンクできることを意味する。

クライアントは、クライアントの作者の好きな方法でユーザーにリンクを表示できる。しかしクライアントはまた、スキームがネットワークプロトコルに対応するリンク(例えば、gemini://、 gopher://、 https://、 ftp:// などで始まるリンク)を表示する一環として、自動的にネットワーク接続を行ってはならない(MUST NOT)。

5.4.3 トグル行をあらかじめフォーマットすること

最初の3文字が「```」(すなわち、先頭の空白文字がない、連続した3つのバックティック) である行は、あらかじめフォーマットされたトグル行である。 これらの行はユーザーに表示されるレンダリング出力に含まれるべきではない(NOT)。 代わりに、これらの行はパーサーのプリフォーマットモードの 「on」と 「off」を切り替える。 プリフォーマットモードは、文書の始めには「off」であるべきである。 プリフォーマットモードの現在の状態は、パーサーが維持することをリクエストされる唯一の内部状態である。 プリフォーマットモードが「on」のとき。行のタイプを識別するための通常の規則は停止され。すべての行はプリフォーマットされたテキスト行として識別されるべきである(5.4.4 参照)。

あらかじめフォーマットされたトグル行はHTMLの <pre> と </pre> タグに類似していると言える。

プリフォーマットモードをオンにするプリフォーマットトグル行の先頭の「```」に続くテキストは、トグル行に続くプリフォーマットテキスト行に関連する「altテキスト」としてクライアントによって解釈されてもかまいません(MAY)。 altテキストの使用はクライアントの判断に委ねられ、単純なクライアントはそれを無視してもよい。 Altテキストは、例えばスクリーンリーダーで表示したときに意味が理解できない、あるいは検索エンジンで有用にインデックスされない、ASCIIアートや同様の非テキストコンテンツに使用することをお勧めする。 Altテキストは、高度なクライアントがシンタックスハイライトに使用できるプログラミング言語を特定するために、コンピュータのソースコードに使用することも可能である。

プリフォーマットモードをオフにするプリフォーマットトグル行の先頭の「```」に続くテキストは、クライアントからは無視されなければならない(MUST)。

5.4.4 あらかじめフォーマットされたテキスト行

あらかじめフォーマットされた(Preformatted)テキスト行は、空白や文体を変更することなく、「ニュートラル」な単幅フォントでユーザに表示されるべきである。 グラフィカルなクライアントは、ビューポートより長い書式付きテキスト行を表示する場合、文を折り返すことに先んじて、スクロール機構を使用する必要がある。 特に、空白を多用する言語(Pythonなど)のソースコードは、クライアントからファイルにコピー・アンド・ペーストして、クライアントの表示方法に起因する問題なしに解釈・コンパイルできるようにするべきである。

5.5 高度な行タイプ

次の高度な行の種類は、高度なクライアントによって認識されてもよい。 単純なクライアントは、本質的な機能を損なうことなく、これらすべてを 5.4.1 に従ってテキスト行として扱ってもよい。

5.5.1 見出し行

「#」で始まる行は見出し行である。 見出し行は、1つ、2つ、または3つの連続した 「#」文字、任意の空白文字、見出しテキストから構成されている。 「#」の数は見出しの「レベル」を表し、 # 、 # 、 ## はHTMLの <h1> 、 <h2> 、 <h3> と同意とみなせる。

見出しテキストはユーザーに提示されるべきで、クライアントはそのステータスを示すためにより大きなフォントや太いフォントなどの特別な書式を使用してもかまわない(MAY)(単純なクライアントはその先頭の # を含む行を、全くスタイルを付けずに単純にプリントするかもしれません)。 しかし、見出し行の定義の主な動機は、スタイルではなく、ドキュメントの内部構造のマシンリーダブルな表現を提供することである。 高度なクライアントでは、この情報を利用して、例えば、長い文書の「目次」をサイドペインに自動生成して階層的に表示し、ユーザーが過度にスクロールすることなく特定のセクションに簡単にジャンプできるようにすることができる。 CMSスタイルのツールでは、テキスト/geminiファイルのディレクトリにメニューやAtom/RSSフィードを自動生成し、そのファイルの最初の見出しを人間に優しいタイトルとして使用できる。

5.5.2 順序なしリスト項目

「* 」で始まる行は、順序なしリストの項目である。 この行タイプは、純粋にスタイル上の理由から存在している。 高度なクライアントでは、「*」の代わりに箇条書きの記号(訳注: Markdown

での「+」「-」のこと)を使用することができる。 「*」の後のテキストは、ビューポートに合わせて折り返され、「きれいに」フォーマットされる。 上級クライアントでは、長いリスト項目を折り返すときにビュレット記号のスペースを考慮して、その項目に対応するすべてのテキスト行が画面の左から同じ距離だけオフセットされるようにすることができる。

5.5.3 引用行

「>」で始まる行は引用行である。 この行タイプは、高度なクライアントが、あるテキストが外部から引用されているという重要な意味情報を読者に伝える際に明確なスタイルを使用できるようにする目的で存在している。 例えば、長い行をビューポート内で折り返す場合、結果として得られる各行の先頭に「>」記号を置くことができる。

付録 1. 完全な2桁のステータスコード

10 INPUT

3.2 の1桁コード 1 の定義による。

11 SENSITIVE INPUT

ステータスコード 10 に準ずるが、パスワードのような機密性の高い入力に使用する。 クライアントはステータスコード10と同様にプロンプトを表示すべきだが、「ショルダーサーファー」(訳注: 画面やキーボードの窃視により情報を抜き取ること)に読まれないように、ユーザの入力は画面に出力(echo)されるべきではない。

20 SUCCESS

3.2 の1桁コード 2 の定義による。

30 REDIRECT - TEMPORARY

3.2 の1桁コード 3 の定義による。

31 REDIRECT - PERMANENT

リクエストされたリソースは、今後、提供される新しいURLから一貫してリクエストされるようにする必要がある。 検索エンジンのインデクサやコンテンツアグリゲータのようなツールは古いURLをリクエストしないように設定を更新すべきであるし、エンドユーザクライアントはブックマークなどを自動的に更新してもよいだろう。 ステータスコードの最初の桁にしか注意を払わないクライアントは、これを一時的なリダイレクトとして扱うことに注意すること。 彼らは正しい場所にたどり着くが、このリダイレクトが永久的であるという知識を利用することができないため、毎回リダイレクトをたどる必要があり、わずかなパフォーマンス上のペナルティを支払うことになる。

40 TEMPORARY FAILURE

3.2 の1桁コード 4 の定義による。

41 SERVER UNAVAILABLE

サーバは過負荷かメンテナンスのため利用不可である。(HTTP 503 参照)

42 CGI ERROR

CGIプロセス、または動的なコンテンツを生成する同様のシステムが、予期せず停止したか、タイムアウトした。

43 PROXY ERROR

サーバーがリモートホストとのトランザクションを正常に完了できなかったため、プロキシリクエストが失敗した。 (HTTP 502, 504 参照)

44 SLOW DOWN

レート制限が有効である。 <META> は、クライアントがこのサーバに次のリクエストを行うまでに待機しなければならない秒数の整数値である。 (HTTP 429 参照)

50 PERMANENT FAILURE

3.2 の1桁コード 5 の定義による。

51 NOT FOUND

リクエストされたリソースは見つからなかったが、将来的に利用可能になる可能性がある。 (HTTP 404 参照) (もし、この重要なステータスコードを覚えるのに苦労しているなら「エリア51に隠されたものを見つけることは不可能だ」と覚えると簡単だろう。)

52 GONE

リクエストされたリソースはもう利用できないし、二度と利用できない。 検索エンジンや類似のツールは、このリソースをインデックスから削除する必要がある。 コンテンツアグリゲーターはそのリソースのリクエストを停止し、購読しているリソースがなくなったことをその人間のユーザに伝えるべきである。 (HTTP 410 参照)

53 PROXY REQUEST REFUSED

サーバーが提供していないドメインのリソースへのリクエストであり、サーバーはプロキシリクエストを受け付けない。

59 BAD REQUEST

おそらく不正なリクエストのため、サーバーがクライアントのリクエストを解析できなかった。 (HTTP 400 参照)

60 CLIENT CERTIFICATE REQUIRED

3.2 の1桁コード 6 の定義による。

61 CERTIFICATE NOT AUTHORISED

提供されたクライアント証明書は、リクエストされた特定のリソースにアクセスすることが許可されていない。 この問題は証明書自体にあるのではなく、他のリソースに対して認証されている可能性がある。

62 CERTIFICATE NOT VALID

提供されたクライアント証明書は有効でないため、受け入れられなかった。 これは、リクエストされた特定のリソースを考慮せず、証明書自体に問題があることを示している。 最も考えられる原因は、証明書の有効開始日が未来であるか、有効期限が過ぎていることだが、このコードは無効な署名、またはX509標準の要件違反を示すこともある。 <META> には、正確なエラーの詳細が記述されているはずである。