kdnakt blog

hello there.

Kotlin/NativeでHTTPサーバーを作るアドベントカレンダー(14日目:モックレスポンスを返す)

この記事はkdnaktの1人 Advent Calendar 2020の14日目の記事です。

 

2020年は会社でKotlin dojoを主催して週1回30分Kotlinと戯れていました。12月はその集大成ということで、Kotlin/NativeでHTTPサーバーを作ってみたいと思います。どこまでできるか、お楽しみ……。

 

 

[モックレスポンスを返す]

リクエストとして送られてきた文字列をそのままレスポンスとして送り返すエコーサーバーをベースにHTTPサーバーを実装してきました。

最終的にはリクエストされたファイルを公開用ディレクトリから探してレスポンスを返す、という形を目指しますが、今回はソース上にハードコーディングしたHTMLをレスポンスとして返す機能を追加します。

 

▼send()関数を理解する

リクエストを受け取ってエコーレスポンスを返している部分は以下のようなコードになっています。recv()でリクエストを読み込み、send()でレスポンスを返しています。

while (true) {
    val length = recv(commFd, pinned.addressOf(0), buffer.size.convert(), 0).toInt()
        .ensureUnixCallResult("read") { it >= 0 }

    if (length == 0) {
        break
    }

    send(commFd, pinned.addressOf(0), length.convert(), 0)
        .ensureUnixCallResult("write") { it >= 0 }
}

 

send()関数の説明をIntelliJで確認すると、以下のような内容を確認できる。@CCallというアノテーションがついていることから、C言語send()を直接呼び出しているようです。

f:id:kidani_a:20201214231418p:plain

 

send()システムコールの説明を見ると引数が4つあり、順番にint型のファイルディスクリプター、void型ポインターのメッセージ、size_t型のメッセージの長さ、int型のフラグとなっており、IntelliJの説明と型が一致しています。

linuxjm.osdn.jp

 

エコーレスポンスではなく、ハードコーディングされたHTMLをレスポンスとして返すためには、send()関数の2番目と3番目の引数を修正すれば良さそうです。

 

文字列をC言語の世界に渡すときは、String.cstrという拡張プロパティを利用します。

Mapping Strings from C - Kotlin Programming Language

 

h1タグで囲まれたHello Worldという文字列だけのHTMLを返すレスポンスを返す場合、以下のような実装になります。IntelliJで表示したヘルプの結果から、size_t型はULong型を利用しています。

val contents = "HTTP/1.1 200 OK\r\nContent-Length: 33\r\n\r\n<html><h1>Hello World</h1></html>\r\n".cstr
send(commFd, contents, contents.size.toULong(), 0)
    .ensureUnixCallResult("write") { it >= 0}

 

curlで動作確認

ビルドして動作を確認します。

 

curlでアクセスすると、以下のように表示されます。

$ curl -i localhost:8080
HTTP/1.1 200 OK
Content-Length: 33

<html><h1>Hello World</h1></html>

 

▼ブラウザの開発者ツールで動作確認

次に、Chromeでアクセスしてみると、次のように表示されます。

f:id:kidani_a:20201214132011p:plain

 

開発者ツールでレスポンスを確認すると、レスポンスヘッダーが正しく解釈されています。

f:id:kidani_a:20201214132132p:plain

f:id:kidani_a:20201214132206p:plain

 

[まとめ]

  • C言語のsend()関数を利用してレスポンスを返している
  • Kotlinから文字列をC言語に渡す場合はString.cstr拡張プロパティを利用する
  • ハードコーディングしたモックレスポンスを返す実装を追加した
  • 実装中のコードは以下のリポジトリにまとめてある 

github.com