戻る

プロジェクトGemini 観念的な仕様

2022年1月30日、v0.16.1

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

 これは、人々がたくさんの古いphlogの投稿を読んだり、メモを取ったりすることなく、私が考えていることを素早く知ることができるようにするために提供されているものです。

 この文書のどの部分に対するフィードバックも大歓迎です。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をリッスンすべきである(最初の有人Geminiミッション、Gemini 3は1965年3月に飛行した)。これは非特権ポートなので、例えばサーバーがGoで書かれていて伝統的な方法で特権を落とせない場合でも、「nobody」ユーザーとしてサーバーで実行することが非常に簡単である。

1.1 Geminiトランザクション

 Geminiトランザクションには1種類あり、おおよそgopherリクエストまたはHTTPの「GET」リクエストに相当する。トランザクションは以下のように行われる。

C: 接続を開く

S: 接続を受け入れる

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

C: サーバ証明書の検証(4.2参照)

C: リクエスト(<CR><LF>で終端する1行)を送信する(2参照)

S: レスポンスヘッダ(<CR><LF>で終わる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構文と構文的に互換性があるが、汎用構文のすべてのコンポーネントをサポートしているわけではない。特に、authorityコンポーネントは許可され、必須であるが、そのuserinfoサブコンポーネントは許可されていない(NOT)。hostサブコンポーネントは必須である。port サブコンポーネントはオプションであり、デフォルト値は 1965 である。path、query、fragmentコンポーネントは使用可能で、一般的な構文で定義されている以上の特別な意味を持たない。空のパスは、"/"のみで構成されるパスと同じである。パスの中のスペースは,+ではなく%20として符号化されるべきである。

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

2 Geminiリクエスト

 Geminiリクエストは、以下の構造を持つ<CR><LF>で終端された1行である。

「URL」<CR><LF>

 「URL」はUTF-8でエンコードされた絶対URLで、スキームを含み、最大長は1024バイトである。リクエストはU+FEFFバイトオーダーマークで始めてはならない[MUST NOT]。
 パスやセレクタの代わりに絶対 URL を送ることは、実質的に HTTP の「Host」ヘッダを組み込むことと同じである。これは、同じIPアドレス上で複数のGeminiドメインを仮想的にホストすることを許可する。また、サーバーをプロキシとして動作させることも可能である。リクエストに「gemini」以外のスキームを含めることで、サーバーをプロトコル変換ゲートウェイとして動作させ、例えば、Gemini上でGopherリソースを取得することができる。プロキシは任意であり、大多数のサーバーは、それ自身のドメインのリソースに対するリクエストにのみ応答することが期待される。

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

3 Geminiレスポンス

 Geminiレスポンスは,<CR><LF>で終端する一つのヘッダー行からなり,オプションでその後にレスポンス本体が続く。

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」コード範囲に属さない場合、サーバーはヘッダーを送信した後に接続を閉じなければならず (MUST)、レスポンスボディを送信してはならない (MUST NOT)。

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

3.2 ステータスコード

 Geminiは2桁の数値ステータスコードを使用する。関連するステータスコードは、同じ最初の桁を共有する。重要なのは、Geminiステータスコードの最初の桁は、HTTPのように「クライアントエラー」や「サーバーエラー」のような曖昧なカテゴリにコードをグループ化しないことである。その代わり、1桁目だけでクライアントが応答をどのように処理すべきかを判断するのに十分な情報を提供する。そのため、1桁目だけを見るシンプルかつ完全なクライアントを書くことができる。2桁目は、より細かい情報を提供する。これは、サーバーのログを明確に記録したり、より快適な対話型クライアントを書いたり、より合理的なユーザーインターフェースを提供したり、コンテンツアグリゲーターやサーチエンジンクローラーなど、より堅牢で知的な自動化クライアントを書いたりするためである。

 レスポンスコードの最初の桁は、レスポンスを6つのカテゴリのうちの1つに明確に分類し、<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を「そのまま」使用しなければならない(as is)。リダイレクトは一時的なものとみなされるべきである。すなわち、クライアントは元のアドレスでリソースのリクエストを続け、ブックマークの自動更新のような便利なアクションを実行すべきではない。レスポンス本体はない。

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>のコンテンツ(and/or特定の6xコード)は、証明書の要件または証明書が拒否された理由に関する追加情報を提供するかもしれない。

3.2.7 注意事項

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

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

 Geminiステータスコードシステムは、2桁目を処理することで発生する負荷(およびそれに伴う複雑さの増加)が、サーバーとクライアントの両側で完全に「オプトイン」されるように、慎重に設計されている。

3.3 レスポンス本体

 レスポンス本体は単なる生のコンテンツであり、テキストまたはバイナリで、Gopherと同じである。圧縮、チャンキング、その他のコンテンツや転送のエンコーディングはサポートされていない。サーバーは最後のバイトの後で接続を閉じ、Gopherの「単独のdot」のような「応答の終了」シグナルはない。

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

 インターネットメディアタイプは、正規の形式で登録されている。Geminiを介して転送されるコンテンツは、次の段落で定義される「テキスト」タイプを除いて、転送前に適切な標準形式で表現されなければならない(MUST)。

 標準形式の場合、「text」タイプのメディアサブタイプは、テキストの改行として<CR><LF>を使用する。Geminiはこの要件を緩和し、応答ボディ全体に対して一貫して行われる場合、改行を表す<LF>のみでテキストメディアを転送することを許可する。<CR>のみで改行することは許可されない。Geminiクライアントは、<CR><LF>と素の<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は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以下を使用するサーバーへの接続を拒否してもよい(MAY)。

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は、クライアントがクライアント証明書によるリクエストを繰り返すことを、サーバーが帯域内で要求する機能を含む。これは、非常に柔軟で安全性が高く、また非常にシンプルなクライアントIDの概念であり、いくつかのアプリケーションを備えている。

 オンデマンドで生成され、使用後すぐに削除される短命のクライアント証明書は、アプリケーションのサーバーサイドの状態を維持するための「セッション識別子」として使用することがてきる。この役割において、クライアント証明書はHTTPクッキーの代わりとして機能するが、クッキーとは異なり、クライアントによって自発的に生成され、クライアントが証明書とそのマッチングキーを削除すると、サーバーは同じ値を後で「復活」させることができない(いわゆる「スーパークッキー」とは異なる)。
 長寿命のクライアント証明書は、総当たり攻撃される可能性のあるパスワードを必要とせず、マルチユーザーアプリケーションにユーザーを確実に識別することがてきる。証明書のハッシュをユーザ ID にマッピングするデータベーステーブルが盗まれたとしても、証明書用のレインボーテーブルは実現不可能であるため、セキュリティリスクにはならない。
 自己ホスト型のシングルユーザーアプリケーションは、OpenSSH でおなじみの方法で簡単かつ確実にセキュリティを確保てきる。ユーザーは自己署名証明書を生成し、そのハッシュを、SSH の .authorized_keys ファイルに類似した、サーバー側の許可証明書リストに追加する)。
 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のプレーンテキストよりも豊富なタイポグラフィの可能性を許容するが、解析は非常に簡単なままである。このフォーマットは行指向であり、各行を独立して処理することにより、一回の文書処理で満足のいくレンダリングを行うことがてきる。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つ以上の言語タグのカンマ区切りリストである。たとえば

「text/gemini; lang=ja」英語で書かれたtext/geminiドキュメントを表す。
「text/gemini; lang=fr」フランス語で書かれたtext/geminiドキュメントを表す。
「text/gemini; lang=en,fr」英語とフランス語の混在で書かれたtext/geminiドキュメントを表す。
「text/gemini; lang=de-CH」スイスのドイツ語で書かれたtext/gemini ドキュメントを表す。
「text/gemini; lang=sr-Cyrl」セルビア語のキリル文字で書かれたtext/geminiドキュメントを表す。
「text/gemini; lang=zh-Hans-CN」中国本土で使用されている簡体字を使用した中国語で書かれたtext/geminiドキュメントを表す。

5.3 行指向

 前述のように、text/gemini形式は行指向である。text/gemini文書の各行は1つの「行の種類」を持っている。行のタイプは、最初の3文字を調べるだけで明確に決定することがてきる。行のタイプは、それがどのようにユーザーに表示されるべきかを決定する。ある行の種類に関連する表示やレンダリングの詳細は、厳密にその行に限定される。

 行の種類は全部で7種類ある。しかし、完全に機能し、仕様に準拠したGeminiクライアントは、それらのうちの4つだけを認識し、処理すればよい……これらは「中核的な行」である(5.4参照)。、高機能なクライアントは、さらに「高度な行」(5.5を参照)を扱うことがてきる。単純なクライアントは、すべての高度な行を中核的な行の1つと同等に扱うことができ、なおかつ適切なユーザー体験を提供することがてきる。

5.4 中核的な行

 4つの中核的な行は次のとおりである。

5.4.1 テキスト行

 テキスト行は最も基本的な行である。以下に定義する他の行の定義と一致しない線は、デフォルトでテキスト行になる。一般的なtext/gemini文書では、ほとんどの行がテキスト行になる。

 テキスト行は、クライアントのビューポートに適した幅に折り返された後、ユーザーに提示されるべきである(下記参照)。テキスト行は、一般的な読み物として視覚的に楽しい方法でユーザーに表示することができるが、その正確な意味はクライアントの判断に委ねられる。例えば、可変幅のフォントを使用したり、スペーシングを正規化し、文の間のスペースを単語の間のスペースより広くしたり、その他のタイポグラフィ上の巧妙さを適用することができる。クライアントは、フォント、フォントサイズ、テキストと背景色などを変更することによって、ユーザーがテキスト行の外観をカスタマイズすることを許可するかもしれない。著者は、テキスト行の正確なレンダリングを制御することは期待できないが、実際のテキストコンテンツについては制御てきる。
 アスキーアート、コンピューターのソースコードなど、正しく表示されない可能性のある行は、あらかじめ整形した上で、トグル行としなければならない。(5.4.3)  空白行もテキスト行であってそれ以上の特別の意味を持たない。空白行については、1行ごとに改行として表示されなければならない。これはHTMLにおける
タグと同じではあるが、連続した空白行をより少ない空白行に折りたたむころはできない。
 また、空白でない連続したテキスト行は、「段落」のような首尾一貫した単位やブロックを形成しないことに注意してされたい。

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

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

 ハードラップにこだわる場合は、ハードラップされた長さと同じかそれ以上の幅のディスプレイを持つクライアントにはコンテンツがきれいに表示されるが、幅の狭いクライアントでは不規則な行幅で表示されることに注意しなければならない。

5.4.2 リンク行

 2つの文字「=>」で始まる行はリンク行で,次のような構文になる。

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

ここで

<whitespace>は、0でない連続したスペースまたはタブの数である。
角括弧は、囲まれた内容がオプションであることを示す。
「URL」は,絶対URLまたは相対URLのいずれでもよい。

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

=> gemini://example.org/(ジェミニ://example.jp)。
=> gemini://example.org/リンク例
=> gemini://example.org/foo 同じホストでの別のリンク例
=> foo/bar/baz.txt 相対リンク
=> gopher://example.org:70/1 gopherリンク
 リンク行のURLは,RFC3986に従って予約文字と空白をパーセントエンコードされたい。

 リンクURLはgemini以外のスキームを持つことができることに注意されたい。これは、gophermapsが「h」アイテムタイプの非標準的な適応によってのみ非gopherコンテンツにリンクできるのとは異なり、geminiドキュメントが他のプロトコルによってホストされるドキュメントにシンプルかつエレガントにリンクできることを意味する。

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

5.4.3 トグル行のプリフォーマット化

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

 プリフォーマットされたトグル行は,HTMLの
及び
タグに類似していると考えることができる。

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

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

5.4.4 プリフォーマットされたテキスト行

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

5.5 高度な行の種類

 高度な行は、高機能なクライアントで認識してもかまわない。単純なクライアントは、本質的な機能を損なうことなく、これらすべてを5.4.1によるテキスト行として扱うことができる。

5.5.1 見出し行

 「#」で始まる行は見出し行である。見出し行は1つ、2つ、または3つの連続した "#"文字から成り、その後に任意の空白文字が続き、さらに見出しテキストが続く。文字の数は見出しの「レベル」を示す。#、#、##はHTMLの<h1>、<h2>、<h3>に類似していると考えることができる。

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

5.5.2 順不同のリスト項目

 「*」で始まる行は、順不同のリスト項目である。この行のタイプは、純粋にスタイル上の理由から存在する。先進的なクライアントでは、「*」を箇条書きの記号に置き換えることがてきる。「*」の後のテキストは、ビューポートに合わせて折り返され、「きれいに」フォーマットされる。高機能なクライアントでは、長いリスト項目を折り返すときに、箇条書きの記号のスペースを考慮して、その項目に対応するすべてのテキスト行が画面の左から等しい距離だけオフセットされるようにすることがてきる。

5.5.3 引用符で囲む行

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

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

10 入力

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

11 センシティブ入力

 ステータスコード10と同様であるが、パスワードのような機密性の高い入力に使用するためのものである。クライアントはステータスコード10と同様にプロンプトを表示するが、ユーザーの入力は他人にのぞき見されるのを防ぐために画面にエコーされるべきではない。

20 サクセス

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

30 リダイレクト……一時的

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

31 リダイレクト……永続的

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

40 一時的な故障

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

41 サーバ使用不可

 サーバーが過負荷やメンテナンスのために利用できない状態である。(HTTP 503を参照)

42 CGI エラー

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

43 プロキシエラー

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

44 スローダウン

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

50 永続的な障害

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

51 NOT FOUND

 要求されたリソースは見つかりませんでしたが、将来は利用できるかもしれない。(HTTP 404参照) (この重要なステータスコードを覚えるのに苦労していますか?覚え方は簡単です:エリア51に隠されたものを見つけることはできません!)

52 GONE

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

53 プロキシリクエスト拒否

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

59 BAD REQUEST (不正なリクエスト)

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

60 要クライアント証明書

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

61 証明書が認証されていない

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

62 証明書が有効でない

 提供されたクライアント証明書は、有効でないため受け入れられなかった。これは、要求された特定のリソースを考慮せず、証明書自体に問題があることを示している。最も考えられる原因は、証明書の有効開始日が未来であるか、有効期限が過ぎていることであるが、このコードは無効な署名、またはX509規格の要件違反を示すこともある。<META>には、正確なエラーに関する詳細な情報が記載されているはずである。
(原典)gemini://gemini.circumlunar.space/docs/specification.gmi

(2022年12月13日 初版)

戻る