{"id":19054827,"url":"https://github.com/zhuagenborn/echo-web-server","last_synced_at":"2025-08-20T14:30:39.211Z","repository":{"id":41962045,"uuid":"495994019","full_name":"Zhuagenborn/Echo-Web-Server","owner":"Zhuagenborn","description":"☁️ A C++20 echo web server using a thread pool, an epoll and non-blocking sockets to process requests, consisting of a YAML-based configuration, a customizable logger and a min-heap-based timer.","archived":false,"fork":false,"pushed_at":"2024-10-22T15:15:46.000Z","size":94,"stargazers_count":58,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-11T10:37:15.120Z","etag":null,"topics":["cpp20","epoll","googletest","heap","http","linux","logger","network","socket","thread-pool","timer","website"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Zhuagenborn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-24T21:31:45.000Z","updated_at":"2024-10-22T15:17:07.000Z","dependencies_parsed_at":"2024-02-16T01:27:20.019Z","dependency_job_id":"7400f64f-8cea-400f-9575-0303b02b1a5d","html_url":"https://github.com/Zhuagenborn/Echo-Web-Server","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zhuagenborn%2FEcho-Web-Server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zhuagenborn%2FEcho-Web-Server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zhuagenborn%2FEcho-Web-Server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zhuagenborn%2FEcho-Web-Server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Zhuagenborn","download_url":"https://codeload.github.com/Zhuagenborn/Echo-Web-Server/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230431100,"owners_count":18224655,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp20","epoll","googletest","heap","http","linux","logger","network","socket","thread-pool","timer","website"],"created_at":"2024-11-08T23:39:53.802Z","updated_at":"2025-08-20T14:30:39.194Z","avatar_url":"https://github.com/Zhuagenborn.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Echo Web Server\n\n![C++](docs/badges/C++.svg)\n[![CMake](docs/badges/Made-with-CMake.svg)](https://cmake.org)\n[![Docker](docs/badges/Made-with-Docker.svg)](https://www.docker.com)\n[![GitHub Actions](docs/badges/Made-with-GitHub-Actions.svg)](https://github.com/features/actions)\n![Linux](docs/badges/Linux.svg)\n![License](docs/badges/License-MIT.svg)\n\n## Introduction\n\nA *C++20* echo web server running on *Linux*.\n\nIf a user inputs a name `\u003cuser\u003e` and a message `\u003cmsg\u003e`, the server will reply with `\u003cuser\u003e said \"\u003cmsg\u003e\"`.\n\n- Using a *YAML*-based configuration system, supporting the notification of value changes and parsing containers and custom types.\n- Using a customizable logging system, supporting synchronous and asynchronous modes.\n- Using auto-expandable buffers to store data.\n- Using a state machine to parse *HTTP* requests.\n- Using a thread pool, an epoll and non-blocking sockets to process *HTTP* requests.\n- Using a timer system based on a min-heap to close timed-out connections.\n- Unit tests using *GoogleTest*.\n\n## Getting Started\n\n### Prerequisites\n\n- Install and start [*Docker*](https://www.docker.com).\n\n### Building\n\nSet the location to the project folder and run:\n\n```bash\ndocker image build . -t \u003cimage\u003e\n```\n\n`\u003cimage\u003e` should be replaced with a custom *Docker* image name.\n\n### Running Tests\n\n```bash\ndocker container run \u003cimage\u003e ctest --test-dir .. -VV\n```\n\n## Usage\n\n### Configuration\n\n`config.yaml` is the default configuration. It will be copied to *Docker* during the building.\n\n```yaml\nserver:\n  # The TCP listening port.\n  port: 10000\n  # The website folder.\n  asset_folder: \"assets\"\n  # The maximum alive time for client timers (in seconds).\n  # When a client's timer reaches zero and it has no activity, it will disconnect.\n  alive_time: 60\nloggers:\n  - name: root\n    level: info\n    appenders:\n      - type: stdout\n```\n\nHere are two ways to make a new configuration effective.\n\n- Change `config.yaml` and build a new *Docker* image.\n- Enter an existing *Docker* container and change `build/bin/config.yaml`.\n\nSee `src/log/README.md` for more details if you want to change logger configuration.\n\n### Running the Server\n\n```bash\ndocker container run -p \u003ccontainer-port\u003e:\u003chost-port\u003e \u003cimage\u003e\n```\n\n`\u003ccontainer-port\u003e` should be equal to `server.port` in `config.yaml`. `\u003chost-port\u003e` can be any available port of the host machine. `-p \u003ccontainer-port\u003e:\u003chost-port\u003e` binds `\u003ccontainer-port\u003e` of the container to `\u003chost-port\u003e` of the host machine.\n\nAfter the server is running, open a browser and access `http://localhost:\u003chost-port\u003e` on the host machine to use it.\n\nYou can run the following command and access `http://localhost:10000` if you are using the default configuration.\n\n```bash\ndocker container run -p 10000:10000 \u003cimage\u003e\n```\n\n## Unit Tests\n\nThe unit tests perform using the [*GoogleTest*](http://google.github.io/googletest) framework, consisting of public and private tests.\n\n- Public tests are in the `tests` folder.\n- Private tests are in the same folder as the corresponding modules.\n\nThe name of an unit test file ends with `_test`.\n\n## Documents\n\nThe code comment style follows the [*Doxygen*](http://www.doxygen.nl) specification.\n\nThe class diagram follows the [*Mermaid*](https://mermaid-js.github.io/mermaid/#) specification.\n\n## Structure\n\n```\n.\n├── CITATION.cff\n├── CMakeLists.txt\n├── Dockerfile\n├── LICENSE\n├── README.md\n├── .github\n│   └── workflows\n│       └── cmake-gtest.yaml\n├── assets\n│   ├── favicon.ico\n│   ├── http-status.html\n│   └── index.html\n├── config.yaml\n├── docs\n│   └── badges\n│       ├── C++.svg\n│       ├── License-MIT.svg\n│       ├── Linux.svg\n│       ├── Made-with-CMake.svg\n│       ├── Made-with-GitHub-Actions.svg\n│       └── Made-with-Docker.svg\n├── include\n│   ├── config.h\n│   ├── containers\n│   │   ├── block_deque.h\n│   │   ├── buffer.h\n│   │   ├── epoller.h\n│   │   ├── heap_timer.h\n│   │   └── thread_pool.h\n│   ├── http.h\n│   ├── io.h\n│   ├── ip.h\n│   ├── log.h\n│   ├── test_util.h\n│   ├── util.h\n│   └── web_server.h\n├── src\n│   ├── CMakeLists.txt\n│   ├── config\n│   │   ├── CMakeLists.txt\n│   │   ├── README.md\n│   │   └── config.cpp\n│   ├── containers\n│   │   ├── CMakeLists.txt\n│   │   ├── buffer\n│   │   │   ├── CMakeLists.txt\n│   │   │   ├── README.md\n│   │   │   └── buffer.cpp\n│   │   ├── epoller\n│   │   │   ├── CMakeLists.txt\n│   │   │   └── epoller.cpp\n│   │   └── thread_pool\n│   │       ├── CMakeLists.txt\n│   │       └── thread_pool.cpp\n│   ├── http\n│   │   ├── CMakeLists.txt\n│   │   ├── README.md\n│   │   ├── http.cpp\n│   │   ├── request.cpp\n│   │   ├── request.h\n│   │   ├── request_test.cpp\n│   │   ├── response.cpp\n│   │   ├── response.h\n│   │   └── response_test.cpp\n│   ├── io\n│   │   ├── CMakeLists.txt\n│   │   ├── README.md\n│   │   └── io.cpp\n│   ├── ip\n│   │   ├── CMakeLists.txt\n│   │   ├── README.md\n│   │   └── ip.cpp\n│   ├── log\n│   │   ├── CMakeLists.txt\n│   │   ├── README.md\n│   │   ├── appender.cpp\n│   │   ├── config_init.cpp\n│   │   ├── config_init.h\n│   │   ├── config_init_test.cpp\n│   │   ├── field.cpp\n│   │   ├── field.h\n│   │   ├── field_test.cpp\n│   │   └── log.cpp\n│   ├── main.cpp\n│   ├── test_util\n│   │   ├── CMakeLists.txt\n│   │   └── test_util.cpp\n│   └── util\n│       ├── CMakeLists.txt\n│       └── util.cpp\n└── tests\n    ├── CMakeLists.txt\n    ├── config_test.cpp\n    ├── containers\n    │   ├── block_deque_test.cpp\n    │   ├── buffer_test.cpp\n    │   ├── heap_timer_test.cpp\n    │   └── thread_pool_test.cpp\n    ├── http_test.cpp\n    ├── io_test.cpp\n    ├── ip_test.cpp\n    ├── log_test.cpp\n    └── util_test.cpp\n```\n\n## Dependencies\n\n- [*yaml-cpp*](https://github.com/jbeder/yaml-cpp)\n- [*{fmt}*](https://github.com/fmtlib/fmt)\n\n## References\n\n- [*WebServer*](https://github.com/markparticle/WebServer)\n- [*sylar*](https://github.com/sylar-yin/sylar)\n\n## License\n\nDistributed under the *MIT License*. See `LICENSE` for more information.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhuagenborn%2Fecho-web-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzhuagenborn%2Fecho-web-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhuagenborn%2Fecho-web-server/lists"}