C++ HTTPサーバー/クライアントを作る

# Google OSSのヘッダファイルを借りて、<br>HTTPサーバー/クライアントを作る。
## 概要
※2023/5/24時点の情報

簡単にhttpサーバー/クライアントを作る方法を調べた。
GoogleのchromiumOSのhttplib.hを借りると簡単に作れる。

以下がhttplib.hのリンク
[chromium.googlesource.com/httplib.h](https://chromium.googlesource.com/crashpad/crashpad/+/a7859e9bc63e54e972906745cbcc1b8543a4fe10/third_party/cpp-httplib/cpp-httplib/httplib.h)

使い方は一つ上の階層に展開されている。
[cpp-httplib/README.md](https://chromium.googlesource.com/crashpad/crashpad/+/a7859e9bc63e54e972906745cbcc1b8543a4fe10/third_party/cpp-httplib/cpp-httplib)

※補足(修正:2023/5/25)
@prickleさんから教えていただきました。
httplib.hはGoogle Chromeの作成物ではなく、yhiroseさんが作成したものを取り込んでいる。
https://github.com/yhirose/cpp-httplib

使い方のままであるが、一応サンプルアプリの作成手順を下記に残す。

## 手順
* [httplib.hのダウンロード/コピー](#httplib.hをローカルにダウンロード/コピー)
* [サンプルアプリの作成](#サンプルアプリの作成)
* [サンプルアプリのビルド](#アプリのビルド)
* [サンプルアプリの実行](#アプリの実行)

## 環境
以下の実行環境であることを前提にしている。
* Linux or WSL2
* Git
* CMake

## httplib.hのダウンロード/コピー
### コピペでの手順
ローカルにhttplib.hのファイルを作り、コピペでリンクのソースをコピーする。
```shell
touch httplib.h
```
[chromium.googlesource.com/httplib.h](https://chromium.googlesource.com/crashpad/crashpad/+/a7859e9bc63e54e972906745cbcc1b8543a4fe10/third_party/cpp-httplib/cpp-httplib/httplib.h)をコピーし、作成したファイルにペーストする。

### ダウンロードでの手順
Gitがインストール済であることを前提に以下のコマンドを実施する。
```shell
git clone https://chromium.googlesource.com/crashpad/crashpad/
cp -p crashpad/third_party/cpp-httplib/cpp-httplib/httplib.h ./
```

## サンプルアプリの作成
severSample.cppとclientSample.cppを作成する。
```shell
touch severSample.cpp
touch clientSample.cpp
```

ソースコードはそれぞれ以下のように記載する。
[cpp-httplib/README.md](https://chromium.googlesource.com/crashpad/crashpad/+/a7859e9bc63e54e972906745cbcc1b8543a4fe10/third_party/cpp-httplib/cpp-httplib)に書かれている内容からコンソールログを追加したぐらいのコード。

**severSample.cpp**
```C++
#include "httplib.h"
#include <iostream>

int main(void)
{
    using namespace httplib;
    Server svr;

    std::cout << "start Server" << std::endl;
    svr.Get("/hi", [](const Request& req, Response& res) {
        res.set_content("Hello World!", "text/plain");
    });

    svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
        auto numbers = req.matches[1];
        res.set_content(numbers, "text/plain");
    });

    svr.listen("localhost", 1234);
}
```

**clientSample.cpp**
```C++
#include "httplib.h"
#include <iostream>

int main(void)
{
    httplib::Client cli("localhost", 1234);

    auto res = cli.Get("/hi");
    if (res && res->status == 200) {
        std::cout << res->body << std::endl;
    }
}
```

## アプリのビルド
cmakeをインストール済であることを前提に、適当にCMakeLists.txtを作る。

**CMakeLists.txt**
```cmake
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# set the project name and version
project(httpSample CXX)

# find package
find_package(Threads REQUIRED)

# compile executable file
add_executable(serverSample serverSample.cpp)
add_executable(clientSample clientSample.cpp)

# module, library, target link
target_link_libraries(serverSample PUBLIC "-pthread")
target_link_libraries(clientSample PUBLIC "-pthread")
```
* Point!
    * 忘れてはいけないのは、threadをfind packageすること。
    * 見つけたpackageをtarget linkすること。
        * 理由は**httplib.h**内でthread処理をしている。

ビルドを実行する。
```shell
mkdir build
cd build
cmake ..
make
```

buildフォルダ内に以下のファイルが生成される。
```
serverSample
clientSample
```

## アプリの実行
コンソールを2つ用意する。
1つはserver用コンソール。もう1つはclient用コンソール。
それぞれのコンソールで以下を実行すると、HTTP通信ができる。

**server用コンソール**
```
$ ./serverSample 
start Server
```

**client用コンソール**
```
$ ./clientSample 
Hello World!
```

# 最後に
以上で終了です。
ソースコードの解説はありません。

**severSample.cpp**について、あえて触れるならば、
```C++
svr.Get("/hi", [](const Request& req, Response& res) {
    res.set_content("Hello World!", "text/plain");
});
```
"text/plain"は、HTTPヘッダのContent-Typeになります。
"text/plain"を指定して、clientへ"Hello World!"を送っています。

Content-Typeについてはググるとそれなりに出てきます。
Content-Type一覧は以下の記事が見やすかったです。
https://qiita.com/AkihiroTakamura/items/b93fbe511465f52bffaa

初投稿になりますが、ご参考になれば幸いです。