CodeCraftersで「Build your own HTTP server」を（無料の範囲で）やってみよう

[CodeCrafters](https://codecrafters.io/)で「HTTPサーバー」を作ってみたくなったのでやっていきます。

---

### CodeCraftersの各webページ

CodeCraftersの主要ページは以下のような構成になっているようです。

- 製品紹介
    - https://codecrafters.io/
- サービス本体
    - https://app.codecrafters.io/catalog
- ドキュメント
    - https://docs.codecrafters.io/introduction
- サービス稼働状況
    - https://status.codecrafters.io/
- リポジトリ
    - https://github.com/codecrafters-io

---

### GitHubアカウントと連携

CodeCraftersを利用するにはGitHubアカウントでログインする必要があるので、その対応を行っていきます。

まずは、[製品紹介ページ](https://codecrafters.io/)にアクセスします。

![Screenshot from 2024-02-24 11-14-47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/1068b300-eb03-d279-6ad0-cfcb04075503.png)

画面右上の「Try now」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/de6c38dc-1ce5-dd99-77fd-cdc895086335.png)

「Challenges」の画面に切り替わります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/7f6e67f4-c922-e3eb-4064-65af1eeee5b0.png)

画面右上の「Sign in with GitHub」をクリックします。

![Screenshot from 2024-02-21 13-38-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/a8a5200b-6204-5716-3d0f-6ee577372e4e.png)

権限を確認して問題なければ「Authorize codecrafters-io」をクリックします。

![Screenshot from 2024-02-21 13-38-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/5117b2a4-65f3-f7fe-fd4f-60400dae8a0f.png)

いくつかアンケートが表示されるので適宜答えましょう。

![Screenshot from 2024-02-21 13-40-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/e709f63b-07d8-a5a1-514a-2899e971fa5f.png)

私は「[PHPerKaigi 2023](https://phperkaigi.jp/2023/)」の[げんえい](https://twitter.com/gennei)さんの[登壇](https://fortee.jp/phperkaigi-2023/proposal/dc54af9b-f879-47b6-9737-12ae6e84bf1d)で知ったので、「How did you hear about CodeCrafters?」の質問には「Friend」、「Conference」と回答しました。

![Screenshot from 2024-02-21 13-41-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/beda22cc-546f-b47a-572d-d87477819013.png)

---

### 「Introduction」のステップで利用言語やアンケートに回答

アンケートに回答すると「Challenges」の画面に戻ってくるので、「Build your own HTTP server」を選択して、「Start Building」をクリックします。

![Screenshot from 2024-02-21 13-43-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/198d3910-1c26-68d2-b866-6b71d2675ccd.png)

「Introduction」の画面に遷移し、どの言語を利用したいか選択肢が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/20337ece-01f0-7625-7175-26d34604fef2.png)

PHPで解くつもりだったのですが、未実装のようなので今回は「Java」を選択しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/b56cf37c-bf9b-de12-dce2-d472f44f71fb.png)

次に言語の習熟度についての質問が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/8dce1101-db09-2bcd-044a-cec8475d642c.png)

「Javaなんもわからん」なので「Beginner」を選択しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/05fa167b-ab93-e919-6fa6-c8227bd4194d.png)

次に言語の利用状況についての質問が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/0f6c953b-676e-2e76-3102-ca9d6298ccbe.png)

仕事で週に数回程度は触っているので「Few times a week」を選択しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/8a77298b-5297-ecf5-8621-6e5a197b3ca7.png)

最後にメールのオプトインに関する質問が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/5f59c672-8896-c94d-f36a-8730c4182168.png)

今回は不要なので「I'll pass」を選択しました。すると、画面下段に「Continue →」のボタンが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/0548d7b7-b299-b0e7-4cf5-8aa6d03932fd.png)

「Introduction」の質問にすべて回答すると画面上段に「Completed」と表示され、「View next step →」のボタンが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/951c93e3-9fe9-10ab-570e-4542ab4057eb.png)

画面左側のメニューの「Introduction」に✅が表示されます。
![Screenshot from 2024-02-24 15-48-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/8d3185da-6687-7729-2d2f-f6c5cb2df8bd.png)

画面上段の「View next step →」もしくは画面下段の「Continue →」をクリックします。

---

### 「Repository Setup」のステップでリポジトリのcloneとpushを実行

「Repository Setup」の画面に遷移し、ここから以降の作業で必要となるGitリポジトリのURLが表示されます。
![Screenshot from 2024-02-24 15-51-36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/edf290de-9878-9c16-c374-e6a71f633009.png)

「Step 1」としてリポジトリをcloneするように指示されていますので、表示されているコマンドを実行します。

```
$ git clone https://git.codecrafters.io/XXXXXXXXXXXXXXXX codecrafters-http-server-java && cd codecrafters-http-server-java
Cloning into 'codecrafters-http-server-java'...
remote: Enumerating objects: 12, done.
remote: Counting objects: 100% (12/12), done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 12 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (12/12), 2.78 KiB | 712.00 KiB/s, done.
```

「Step 2」では `--allow-empty` を使って空コミットを行うように指示されていますので、表示されているコマンドを実行します。

```
$ git commit --allow-empty -m 'test' && git push origin master
[master 8367fc1] test
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 172 bytes | 172.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
remote: ------------------------------------------------------------------------
remote: 
remote: 
remote:      ___            _          ___              __  _                   
remote:     / __\ ___    __| |  ___   / __\_ __  __ _  / _|| |_  ___  _ __  ___ 
remote:    / /   / _ \  / _` | / _ \ / /  | '__|/ _` || |_ | __|/ _ \| '__|/ __|
remote:   / /___| (_) || (_| ||  __// /___| |  | (_| ||  _|| |_|  __/| |   \__ 
remote:   \____/ \___/  \__,_| \___|\____/|_|   \__,_||_|   \__|\___||_|   |___/
remote: 
remote: 
remote:    Welcome to CodeCrafters! Your commit was received successfully.
remote: 
remote: ------------------------------------------------------------------------
remote: 
remote: Running tests on your codebase. Streaming logs...
remote: 
remote: [compile] [INFO] Scanning for projects...
remote: [compile] [INFO] 
remote: [compile] [INFO] ----------------< io.codecrafters:build-your-own-http >-----------------
remote: [compile] [INFO] Building build-your-own-http 1.0
remote: [compile] [INFO]   from pom.xml
remote: [compile] [INFO] --------------------------------[ jar ]---------------------------------
remote: [compile] [INFO] 
remote: [compile] [INFO] --- resources:3.3.1:resources (default-resources) @ build-your-own-http ---
remote: [compile] [INFO] skip non existing resourceDirectory /app/src/main/resources
remote: [compile] [INFO] 
remote: [compile] [INFO] --- compiler:3.11.0:compile (default-compile) @ build-your-own-http ---
remote: [compile] [INFO] Changes detected - recompiling the module! :source
remote: [compile] [INFO] Compiling 1 source file with javac [debug target 21] to target/classes
remote: [compile] [INFO] 
remote: [compile] [INFO] --- resources:3.3.1:testResources (default-testResources) @ build-your-own-http ---
remote: [compile] [INFO] skip non existing resourceDirectory /app/src/test/resources
remote: [compile] [INFO] 
remote: [compile] [INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ build-your-own-http ---
remote: [compile] [INFO] No sources to compile
remote: [compile] [INFO] 
remote: [compile] [INFO] --- surefire:3.1.2:test (default-test) @ build-your-own-http ---
remote: [compile] [INFO] No tests to run.
remote: [compile] [INFO] 
remote: [compile] [INFO] --- jar:3.3.0:jar (default-jar) @ build-your-own-http ---
remote: [compile] [INFO] Building jar: /app/target/build-your-own-http-1.0.jar
remote: [compile] [INFO] 
remote: [compile] [INFO] --- assembly:3.6.0:single (make-assembly) @ build-your-own-http ---
remote: [compile] [INFO] Building jar: /tmp/codecrafters-http-target/java_http.jar
remote: [compile] [WARNING] Configuration option 'appendAssemblyId' is set to false.
remote: [compile] Instead of attaching the assembly file: /tmp/codecrafters-http-target/java_http.jar, it will become the file for main project artifact.
remote: [compile] NOTE: If multiple descriptors or descriptor-formats are provided for this project, the value of this file will be non-deterministic!
remote: [compile] [WARNING] Replacing pre-existing project main-artifact file: /app/target/build-your-own-http-1.0.jar
remote: [compile] with assembly file: /tmp/codecrafters-http-target/java_http.jar
remote: [compile] [INFO] ------------------------------------------------------------------------
remote: [compile] [INFO] BUILD SUCCESS
remote: [compile] [INFO] ------------------------------------------------------------------------
remote: [compile] [INFO] Total time:  2.197 s
remote: [compile] [INFO] Finished at: 2024-02-24T08:16:50Z
remote: [compile] [INFO] ------------------------------------------------------------------------
remote: [compile] Compilation successful.
remote: 
remote: [stage-1] Running tests for Stage #1: Bind to a port
remote: [stage-1] Connecting to localhost:4221 using TCP
remote: [your_program] Logs from your program will appear here!
remote: [stage-1] Looks like your program has terminated. A HTTP server is expected to be a long-running process.
remote: [stage-1] Test failed (try setting 'debug: true' in your codecrafters.yml to see more details)
remote: 
remote: View stage instructions: https://app.codecrafters.io/courses/http-server.
remote: 
To https://git.codecrafters.io/XXXXXXXXXXXXXXXX
   c4bb38d..8367fc1  master -> master
```

pushが成功すると「Listening for a git push...」というメッセージが「🎉 Git push received! The first stage is now activated.」に切り替わり、画面下段に「Continue →」のボタンが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/d5e9054e-b542-cd41-b1ce-43458f02af9a.png)

「Repository Setup」のすべてのステップの対応が完了すると画面上段に「Completed」と表示され、「View next stage →」のボタンが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/080a9bf7-3ea8-4045-b54c-46a948b2d07f.png)

画面左側のメニューの「Repository Setup」に✅が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/bba13a21-a316-1cb7-f645-c8db8cc3ad8f.png)

画面上段の「View next stage →」もしくは画面下段の「Continue →」をクリックします。

---

### 「Bind to a port」のタスク

「Bind to a port」の画面に遷移するので、「Your Task」を参照します。
※テストの失敗については先程のpush実行時のログにも表示されていましたが、画面上にも表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/400c6df9-ff2c-5131-0dc1-562db9c2c1e7.png)

このステージで行うべきタスクの内容は以下のとおりです。
- 4221番ポートでTCPサーバーを起動すること。

「How to pass this stage」の「Step 1」にヒントというか答えが書いてあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/1825435f-b7c9-3439-43bf-80fd81fc88c5.png)

ヒントのとおりプログラムを修正して、「Step 2」の指示のとおりpushを実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/b7c0fc27-e230-9f45-af53-8e2b2a5932c3.png)

```
$ git add .
$ git commit -m "pass 1st stage"
[master 8489766] pass 1st stage
 1 file changed, 12 insertions(+), 12 deletions(-)
$ git push origin master
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (6/6), 483 bytes | 483.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0), pack-reused 0
remote: ------------------------------------------------------------------------
remote: 
remote: 
remote:      ___            _          ___              __  _                   
remote:     / __\ ___    __| |  ___   / __\_ __  __ _  / _|| |_  ___  _ __  ___ 
remote:    / /   / _ \  / _` | / _ \ / /  | '__|/ _` || |_ | __|/ _ \| '__|/ __|
remote:   / /___| (_) || (_| ||  __// /___| |  | (_| ||  _|| |_|  __/| |   \__ 
remote:   \____/ \___/  \__,_| \___|\____/|_|   \__,_||_|   \__|\___||_|   |___/
remote: 
remote: 
remote:    Welcome to CodeCrafters! Your commit was received successfully.
remote: 
remote: ------------------------------------------------------------------------
remote: 
remote: Running tests on your codebase. Streaming logs...
remote: 
remote: [compile] [INFO] Scanning for projects...
remote: [compile] [INFO] 
remote: [compile] [INFO] ----------------< io.codecrafters:build-your-own-http >-----------------
remote: [compile] [INFO] Building build-your-own-http 1.0
remote: [compile] [INFO]   from pom.xml
remote: [compile] [INFO] --------------------------------[ jar ]---------------------------------
remote: [compile] [INFO] 
remote: [compile] [INFO] --- resources:3.3.1:resources (default-resources) @ build-your-own-http ---
remote: [compile] [INFO] skip non existing resourceDirectory /app/src/main/resources
remote: [compile] [INFO] 
remote: [compile] [INFO] --- compiler:3.11.0:compile (default-compile) @ build-your-own-http ---
remote: [compile] [INFO] Changes detected - recompiling the module! :source
remote: [compile] [INFO] Compiling 1 source file with javac [debug target 21] to target/classes
remote: [compile] [INFO] 
remote: [compile] [INFO] --- resources:3.3.1:testResources (default-testResources) @ build-your-own-http ---
remote: [compile] [INFO] skip non existing resourceDirectory /app/src/test/resources
remote: [compile] [INFO] 
remote: [compile] [INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ build-your-own-http ---
remote: [compile] [INFO] No sources to compile
remote: [compile] [INFO] 
remote: [compile] [INFO] --- surefire:3.1.2:test (default-test) @ build-your-own-http ---
remote: [compile] [INFO] No tests to run.
remote: [compile] [INFO] 
remote: [compile] [INFO] --- jar:3.3.0:jar (default-jar) @ build-your-own-http ---
remote: [compile] [INFO] Building jar: /app/target/build-your-own-http-1.0.jar
remote: [compile] [INFO] 
remote: [compile] [INFO] --- assembly:3.6.0:single (make-assembly) @ build-your-own-http ---
remote: [compile] [INFO] Building jar: /tmp/codecrafters-http-target/java_http.jar
remote: [compile] [WARNING] Configuration option 'appendAssemblyId' is set to false.
remote: [compile] Instead of attaching the assembly file: /tmp/codecrafters-http-target/java_http.jar, it will become the file for main project artifact.
remote: [compile] NOTE: If multiple descriptors or descriptor-formats are provided for this project, the value of this file will be non-deterministic!
remote: [compile] [WARNING] Replacing pre-existing project main-artifact file: /app/target/build-your-own-http-1.0.jar
remote: [compile] with assembly file: /tmp/codecrafters-http-target/java_http.jar
remote: [compile] [INFO] ------------------------------------------------------------------------
remote: [compile] [INFO] BUILD SUCCESS
remote: [compile] [INFO] ------------------------------------------------------------------------
remote: [compile] [INFO] Total time:  2.186 s
remote: [compile] [INFO] Finished at: 2024-02-24T08:46:44Z
remote: [compile] [INFO] ------------------------------------------------------------------------
remote: [compile] Compilation successful.
remote: 
remote: [stage-1] Running tests for Stage #1: Bind to a port
remote: [stage-1] Connecting to localhost:4221 using TCP
remote: [your_program] Logs from your program will appear here!
remote: [stage-1] Success! Closing connection
remote: [stage-1] Test passed.
remote: [your_program] accepted new connection
remote: 
remote: All tests ran successfully. Congrats!
remote: 
remote: View instructions for the next stage: https://app.codecrafters.io/courses/http-server
remote: 
To https://git.codecrafters.io/XXXXXXXXXXXXXXXX
   8367fc1..8489766  master -> master
```

pushを実行すると、以下のようなメッセージからビルドとテストが実行されていることがわかります。
つまり、各ステージで提示されているタスク内容を元にプログラムの修正を行い、テストをパスすることで次のステージに進める仕組みのようです。

```
remote: [compile] [INFO] Building build-your-own-http 1.0
・
・
remote: [compile] [INFO] BUILD SUCCESS
・
・
remote: [compile] Compilation successful.
```

```
remote: [stage-1] Running tests for Stage #1: Bind to a port
remote: [stage-1] Connecting to localhost:4221 using TCP
・
・
remote: [stage-1] Test passed.
・
・
remote: All tests ran successfully. Congrats!
```


テストをパスすると「Your Task」の欄に「Completed」と表示され、「View Next Stage →」のボタンが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/2a52a133-09ea-183b-a3d9-216dde4bdd09.png)

「Bind to a port」のすべてのステップの対応が完了すると画面上段に「Completed」と表示され、「View next stage →」のボタンが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/a1be60de-c59a-bbda-c838-d33e548c9de4.png)

画面左側のメニューの「Bind to a port」に✅が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/a109aea3-7a84-2d7a-f722-f8a4521fcc2a.png)

画面上段もしくは「Your Task」の欄の「View Next Stage →」をクリックします。

---

### 「Respond with 200」のタスク

「Respond with 200」の画面に遷移するので、「Your Task」を参照します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/4aff81ae-952b-98cd-6a0a-1e35bac3ef52.png)

このステージで行うべきタスクの内容は以下のとおりです。
- TCP接続を受け付けます。
- TCP接続の受信内容を読み取ります。（読み取った内容の解析は後のステージで行います）
- HTTPレスポンスとして以下を返します。
    - ステータスライン( `HTTP/1.1 200 OK\r\n\r\n` )
- 受信した他の内容は無視して構いません。（「Parse headers」というステージが控えているので、あとでこのあたりは対応することになると思われます）

解き方がわからなければ「Code Examples」のタブを参考にしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/39af8ad8-a101-625b-e653-2a28fa2476eb.png)

プログラムを修正して、「Step 2」の指示のとおりpushを実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/05cf9c61-f2de-c500-cc18-2ec91a13fcad.png)

```
$ git add .
$ git commit -m "pass 2nd stage"
[master cbaf07a] pass 2nd stage
 1 file changed, 14 insertions(+), 4 deletions(-)
$ git push origin master
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (6/6), 674 bytes | 674.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0), pack-reused 0
remote: ------------------------------------------------------------------------
remote: 
remote: 
remote:      ___            _          ___              __  _                   
remote:     / __\ ___    __| |  ___   / __\_ __  __ _  / _|| |_  ___  _ __  ___ 
remote:    / /   / _ \  / _` | / _ \ / /  | '__|/ _` || |_ | __|/ _ \| '__|/ __|
remote:   / /___| (_) || (_| ||  __// /___| |  | (_| ||  _|| |_|  __/| |   \__ 
remote:   \____/ \___/  \__,_| \___|\____/|_|   \__,_||_|   \__|\___||_|   |___/
remote: 
remote: 
remote:    Welcome to CodeCrafters! Your commit was received successfully.
remote: 
remote: ------------------------------------------------------------------------
remote: 
remote: Running tests on your codebase. Streaming logs...
remote: 
remote: [compile] [INFO] Scanning for projects...
remote: [compile] [INFO] 
remote: [compile] [INFO] ----------------< io.codecrafters:build-your-own-http >-----------------
remote: [compile] [INFO] Building build-your-own-http 1.0
remote: [compile] [INFO]   from pom.xml
remote: [compile] [INFO] --------------------------------[ jar ]---------------------------------
remote: [compile] [INFO] 
remote: [compile] [INFO] --- resources:3.3.1:resources (default-resources) @ build-your-own-http ---
remote: [compile] [INFO] skip non existing resourceDirectory /app/src/main/resources
remote: [compile] [INFO] 
remote: [compile] [INFO] --- compiler:3.11.0:compile (default-compile) @ build-your-own-http ---
remote: [compile] [INFO] Changes detected - recompiling the module! :source
remote: [compile] [INFO] Compiling 1 source file with javac [debug target 21] to target/classes
remote: [compile] [INFO] 
remote: [compile] [INFO] --- resources:3.3.1:testResources (default-testResources) @ build-your-own-http ---
remote: [compile] [INFO] skip non existing resourceDirectory /app/src/test/resources
remote: [compile] [INFO] 
remote: [compile] [INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ build-your-own-http ---
remote: [compile] [INFO] No sources to compile
remote: [compile] [INFO] 
remote: [compile] [INFO] --- surefire:3.1.2:test (default-test) @ build-your-own-http ---
remote: [compile] [INFO] No tests to run.
remote: [compile] [INFO] 
remote: [compile] [INFO] --- jar:3.3.0:jar (default-jar) @ build-your-own-http ---
remote: [compile] [INFO] Building jar: /app/target/build-your-own-http-1.0.jar
remote: [compile] [INFO] 
remote: [compile] [INFO] --- assembly:3.6.0:single (make-assembly) @ build-your-own-http ---
remote: [compile] [INFO] Building jar: /tmp/codecrafters-http-target/java_http.jar
remote: [compile] [WARNING] Configuration option 'appendAssemblyId' is set to false.
remote: [compile] Instead of attaching the assembly file: /tmp/codecrafters-http-target/java_http.jar, it will become the file for main project artifact.
remote: [compile] NOTE: If multiple descriptors or descriptor-formats are provided for this project, the value of this file will be non-deterministic!
remote: [compile] [WARNING] Replacing pre-existing project main-artifact file: /app/target/build-your-own-http-1.0.jar
remote: [compile] with assembly file: /tmp/codecrafters-http-target/java_http.jar
remote: [compile] [INFO] ------------------------------------------------------------------------
remote: [compile] [INFO] BUILD SUCCESS
remote: [compile] [INFO] ------------------------------------------------------------------------
remote: [compile] [INFO] Total time:  2.214 s
remote: [compile] [INFO] Finished at: 2024-02-24T10:13:50Z
remote: [compile] [INFO] ------------------------------------------------------------------------
remote: [compile] Compilation successful.
remote: 
remote: [stage-1] Running tests for Stage #1: Bind to a port
remote: [stage-1] Connecting to localhost:4221 using TCP
remote: [your_program] Logs from your program will appear here!
remote: [stage-1] Success! Closing connection
remote: [stage-1] Test passed.
remote: 
remote: [stage-2] Running tests for Stage #2: Respond with 200
remote: [stage-2] You can use the following curl command to test this locally
remote: [stage-2] $ curl -v -X GET http://localhost:4221/
remote: [stage-2] Sending request (status line): GET / HTTP/1.1
remote: [your_program] Logs from your program will appear here!
remote: [stage-2] Test passed.
remote: 
remote: All tests ran successfully. Congrats!
remote: 
remote: View instructions for the next stage: https://app.codecrafters.io/courses/http-server
remote: 
To https://git.codecrafters.io/XXXXXXXXXXXXXXXX
   8489766..cbaf07a  master -> master
```

テストをパスすると「Your Task」の欄に「Completed」と表示され、「View Next Stage →」のボタンが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/9eb924aa-7e70-58d0-09fe-f41f284fc677.png)

「Respond with 200」のすべてのステップの対応が完了すると画面上段に「Completed」と表示され、「View next stage →」のボタンが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/4f2b11f0-76eb-949c-0a0f-0cc0214260e8.png)

画面左側のメニューの「Respond with 200」に✅が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/bb74c30d-faff-ec41-4793-ca5734c4fcc4.png)

画面上段もしくは「Your Task」の欄の「View Next Stage →」をクリックします。

---

### 「Respond with 404」のタスク

「Respond with 404」の画面に遷移します。ここで、「This stage requires a CodeCrafters Membership.」と表示され、有料会員になることが求められます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/4b4e161a-477c-c21e-9225-2fe6c5654c95.png)

ということで、ここから以降はそこそこの料金を支払う必要があるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/bbcf56f3-14bd-8a87-6aa5-9013945cf90f.png)

---

せっかくなので、「Respond with 404」以降のタスクの内容だけでも確認しましょう。

「Respond with 404」の「Your Task」を参照します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/68661ab9-9fef-d48e-d13e-40a836692d54.png)

このステージで行うべきタスクの内容は以下のとおりです。
- HTTPリクエストのリクエストライン（例: `GET /index.html HTTP/1.1` ）からパス部分を抽出します。
- 条件に合致する場合、HTTPレスポンスとして以下を返します。
    - HTTPメソッドが `GET` の場合
        - パスが `/` の場合
            - `HTTP/1.1 200 OK`
        - パスが `/` 以外の場合
            - `HTTP/1.1 404 Not Found`
- `Host: localhost:4221` と `User-Agent: curl/7.64.1` はリクエストヘッダーです。（今回のステージでは利用しません）

---

### 「Respond with content」のタスク

「Respond with content」の「Your Task」を参照します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/52f8c684-50a0-a106-dfef-9834e094fb97.png)

このステージで行うべきタスクの内容は以下のとおりです。
- ここまでのステージではHTTPレスポンスとしてステータスラインのみを返していましたが、このステージではbodyも返します。
- HTTPリクエストのリクエストライン（例: `GET /echo/abc HTTP/1.1` ）からパス部分を抽出します。
- 条件に合致する場合、HTTPレスポンスとして以下を返します。
    - HTTPメソッドが `GET` の場合
        - パスが `/echo/<ランダムな文字列>` の場合、 `/echo/` 以降の `<ランダムな文字列>` の部分をbodyとして返します。
            ```
            HTTP/1.1 200 OK
            Content-Type: text/plain
            Content-Length: <ランダムな文字列>に応じたサイズ
            
            <ランダムな文字列>
            ```

---

### 「Parse headers」のタスク

「Parse headers」の「Your Task」を参照します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/94023225-f415-35a0-8e92-230221cfbf94.png)

このステージで行うべきタスクの内容は以下のとおりです。
- HTTPリクエストのリクエストライン（例: `GET /user-agent HTTP/1.1` ）からパス部分を抽出します。
- 条件に合致する場合、HTTPレスポンスとして以下を返します。
    - HTTPメソッドが `GET` の場合
        - パスが `/user-agent` の場合
            - リクエストヘッダーに `User-Agent` を含む場合、 `User-Agent` の値をbodyとして返します。
                ```
                HTTP/1.1 200 OK
                Content-Type: text/plain
                Content-Length: <User-Agent>の値に応じたサイズ
                
                <User-Agent>の値
                ```

---

### 「Concurrent connections」のタスク

「Concurrent connections」の「Your Task」を参照します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/a5355f67-2a4b-0611-6797-1e23ca96238b.png)

このステージで行うべきタスクの内容は以下のとおりです。
- ここまでのステージでは、1つの接続（HTTPリクエスト）に対してのみ、HTTPレスポンスを返すように実装してきました。
- このステージでは複数同時接続を考慮し、HTTPリクエストが複数来てもそれぞれにHTTPレスポンスを返すように実装します。

---

### 「Get a file」のタスク

「Get a file」の「Your Task」を参照します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/544a4550-9f77-3ff5-55c4-2059574a3b50.png)

このステージで行うべきタスクの内容は以下のとおりです。
- テストでは、「 `./your_server.sh --directory <ディレクトリ名>` 」のようにプログラムを実行します。
- HTTPリクエストのリクエストライン（例: `GET /files/ファイル名 HTTP/1.1` ）からパス部分を抽出します。
- 条件に合致する場合、HTTPレスポンスとして以下を返します。
    - HTTPメソッドが `GET` の場合
        - パスが `/files/<ファイル名>` の場合
            - 対象ファイルが `--directory <ディレクトリ名>` で指定されたディレクトリ内に存在する場合
                ```
                HTTP/1.1 200 OK
                Content-Type: application/octet-stream
                Content-Length: 対象ファイルのサイズ
                
                対象ファイルの内容
                ```
            - 対象ファイルが `--directory <ディレクトリ名>` で指定されたディレクトリ内に存在しない場合
                ```
                HTTP/1.1 404 Not Found
                ```

---

### 「Post a file」のタスク

「Post a file」の「Your Task」を参照します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/6620d9dc-dd54-f44c-f779-ad59801ed002.png)

このステージで行うべきタスクの内容は以下のとおりです。
- テストでは、「 `./your_server.sh --directory <ディレクトリ名>` 」のようにプログラムを実行します。
- HTTPリクエストのリクエストライン（例: `POST /files/ファイル名 HTTP/1.1` ）からパス部分を抽出します。
- 条件に合致する場合、HTTPレスポンスとして以下を返します。
    - HTTPメソッドが `POST` の場合
        - パスが `/files/<ファイル名>` の場合
            - 対象ファイルを `--directory <ディレクトリ名>` で指定されたディレクトリ内に保存する。
            - ファイルの保存に成功したら以下を返す。
                ```
                HTTP/1.1 201 Created
                Content-Type: application/octet-stream
                Content-Length: 保存したファイルのサイズ
                
                保存したファイルの内容
                ```

---

### CodeCraftersをやってみた感想

有料版の壁の件を把握していなかったので、やる前の「HTTPサーバー作るぞ」という気持ちを打ち砕かれて、終盤はちょっと残念な感じになってしまいましたが、最後にCodeCraftersをやってみた感想を少しだけ。

今回は「Build your own HTTP server」を触ってみましたが、普段仕事で利用しているHTTPサーバーなどの仕組みを知るきっかけとしては、CodeCraftersはとても良い教材だと思いました。

もちろん、「Build your own HTTP server」の各ステージをクリアしただけでは、「HTTPサーバー完全に理解した」という域に達することにはなりませんが、こういった複雑で難しそうなアプリケーションも小さな機能の集合体なので、少しずつ理解を深めていくきっかけになるのではないでしょうか。

ということで、CodeCraftersには様々な言語とアプリケーションを学べるように準備されていますので、ぜひチャレンジしてみてください。