この記事はkdnaktの1人 Advent Calendar 2020の10日目の記事です。
2020年は会社でKotlin dojoを主催して週1回30分Kotlinと戯れていました。12月はその集大成ということで、Kotlin/NativeでHTTPサーバーを作ってみたいと思います。どこまでできるか、お楽しみ……。
[RFC7230]
これまで、Kotlin/Nativeでリクエストを受け取ってそのまま返すだけのエコーサーバーを実装し、テストを書くための準備をしました。
HTTPリクエストをKotlinのオブジェクトにパースするには、どのようなテストを書けばよいのか理解するために、RFC7230を確認します。
HTTPでやりとりされるメッセージの基本的な形式は次のようになっています(Section 3. Message Format)。HTTP-message
はHTTPリクエストまたはHTTPレスポンスのいずれかを表します。
HTTP-message = start-line *( header-field CRLF ) CRLF [ message-body ]
start-line
で始まり、CRLF
(改行コード)で区切られたヘッダーが0個以上続いて、CRLF
だけの空行があり、メッセージボディへと続く構成になっています。
start-line
は、HTTPリクエストの場合にはrequest-line
、HTTPレスポンスの場合にはstatus-line
とそれぞれ異なります。
[HTTPリクエストのrequest-line]
request-line
は次の形式で表現されます。SP
はシングルスペース(single space)を表しています。
request-line = method SP request-target SP HTTP-version CRLF
最初は、シンプルなGETリクエストを受け取る場合を考えていきます。
▼method
method
はHTTPメソッドを表し、RFC7231のSection 4で定義されたHTTPメソッドは以下の8つです。
- GET
- HEAD
- POST
- PUT
- DELETE
- CONNECT
- OPTIONS
- TRACE
▼request-target
request-target
は取得対象のリソースを表し、以下の形式で表現されます。
request-target = origin-form / absolute-form / authority-form / asterisk-form
authority-form
はCONNECTリクエストで、asterisk-form
はOPTIONSリクエストでのみ利用されるので、今回はいったん無視して進みます。
absolut-form
も、プロキシサーバーへのリクエストを行う場合に利用されるので、当分は利用しません。
GETリクエストを構成するorigin-form
は、以下の形式で表現されます。
origin-form = absolute-path [ "?" query ]
absolute-path
は空文字にはならず、少なくとも/
を含みます。
query
はRFC3986で詳細が定義されていますが、ここではいったん雑に?name1=value1&name2=value2
のようにnameとvalueのペアと理解しておきます。
▼HTTP-Version
HTTP-Versionはとりあえず固定でHTTP/1.1としておきます。それ以前のバージョンに対応する予定はありませんし、HTTP/2に対応するのは当分先になりそうだからです。
これで少なくともstart-line
をパースすることはできそうです。
残るHTTPヘッダー部分は、field-name ":" OWS field-value OWS
という形式で定義されています。OWS
は半角スペースまたはタブ文字を任意の数含みます(ゼロ個の場合もあります)。
[まとめ]
- HTTPリクエストの仕様をRFC7230に沿って簡単に確認した
- 1行目は
method
+request-target
+HTTP-version
- 2行目以降空行までリクエストヘッダが
field-name
+:
+field-value
形式で任意の行数続く
明日以降はここで確認した仕様に従ってHTTPリクエストをパースするテスト、実装を進めていきます。