- A single-threaded asynchronous web server implemented in C++ 98, mimicking Nginx's behavior.
- Developed GET, POST, DELETE, PUT, HEAD methods compliant with the HTTP 1.1 protocol.
- Can be configured with a configuration file like Nginx.
- Supports virtual hosts with multiple ports.
- Made server-side advanced tasks easier with CGI functionality.
- Handles client requests asynchronously.
- Supports the default page (index.html) and error pages.
- Implemented external dependencies like configurations using the Singleton Pattern.
- Connection & Request Timeout
flowchart TD
A[Server Initialized<br/>non-blocking socket<br/>+<br/>kqueue]
I[Event Loop]
J[kevent wait]
K[accept]
L[fcntl O_NONBLOCK client_fd]
M[kevent register client_fd READ]
N[recv loop]
O[HTTP parse]
P[Request handler]
Q[Build response]
R[kevent switch WRITE]
S[send loop]
T{Done?}
U{Keep Alive?}
V[Switch to READ]
W[Register TIMER]
X[close fd]
A --> I
I --> J
J --> K --> L --> M --> I
J --> N --> O --> P --> Q --> R --> I
J --> S --> T
T -->|no| S
T -->|yes| U
U -->|yes| V --> W --> I
U -->|no| X --> I
make
./webserv (option: [path_to_conf_file])
curl -i http://localhost:8100/
curl -i http://localhost:8100/not-found
It supports redirection:
Unsupported HTTP method:
Request Timeout:
Health check:
curl -I http://localhost:8100/
curl -i -X POST http://localhost:8100/post_body -F "file=@sample.txt"
check the uploaded file: curl -i http://localhost:8100/directory/sample.txt
curl -i -T sample.txt http://localhost:8100/put_test/sample.txt
Check the uploaded file:
Replace the file with a new one: curl -i -T new_sample.txt http://localhost:8100/put_test/sample.txt
Check the changed content:
curl -i -X DELETE http://localhost:8100/put_test/sample.txt
Check if the file is deleted:
It is not allowed to delete a directory. Upload deletion is only allowed per-file:
Calling a method to a location which does not allow the method:
| Response Size | TPS (webserv) | TPS (nginx) | Relative TPS (%) | Latency (webserv, s) | Latency (Nginx, s) | Failure Rate (webserv, %) | Failure Rate (nginx, %) | Longest Txn (webserv, s) | Longest Txn (Nginx, s) |
|---|---|---|---|---|---|---|---|---|---|
| 0B | 13,756 | 25,828 | 53.3% | 0.01 | 0.01 | 0.0104% | 0.0839% | 0.57 | 0.06 |
| 612B | 10,386 | 23,214 | 44.7% | 0.02 | 0.01 | 0.0022% | 0.0821% | 0.75 | 0.16 |
| 974B | 9,660 | 23,270 | 41.5% | 0.02 | 0.01 | 0.0027% | 0.0846% | 0.81 | 0.16 |
| 2000B | 6,530 | 23,402 | 27.9% | 0.03 | 0.01 | 0.0075% | 0.0852% | 0.84 | 0.14 |
1. Github (Issue and configuration management)
2. Notion (Communication)
3. Slack (Communication)
4. VSCode (Development)
- C++98
- POSIX
- CGI
- Kernel Queue
- HTML
- CSS
-
feat: Adding a new feature to the application or library.fix: Fixing a bug.build: Changes that affect the build system or external dependencies (e.g., gulp, broccoli, npm).ci: Changes to CI configuration files and scripts (e.g., Travis, Circle, BrowserStack, SauceLabs).chore: Other changes that don't modify source code.docs: Documentation changes only.perf: Code changes that improve performance.refactor: Code changes that neither fix a bug nor add a feature.revert: Reverting a previous commit.style: Changes that do not affect the meaning of the code (white space, formatting, missing semicolons, etc.).test: Adding or updating tests.wip: Work in progress.
-
Git Branches
main: Deploymentdevelop: Branch for merging developed features.#[Tracker ID] [Commit Convention Name] / [Function Name]: Branch for developing each feature.
📦srcs
┣ 📂clients
┃ ┣ 📂candidate_fields
┃ ┃ ┣ 📂include
┃ ┃ ┃ ┣ 📜CandidateFields.hpp
┃ ┃ ┃ ┗ 📜ICandidateFields.hpp
┃ ┃ ┗ 📂srcs
┃ ┃ ┃ ┗ 📜CandidateFields.cpp
┃ ┣ 📂cgi
┃ ┃ ┣ 📂include
┃ ┃ ┃ ┣ 📜CGI.hpp
┃ ┃ ┃ ┗ 📜ICGI.hpp
┃ ┃ ┗ 📂src
┃ ┃ ┃ ┗ 📜CGI.cpp
┃ ┣ 📂client
┃ ┃ ┣ 📂include
┃ ┃ ┃ ┗ 📜Client.hpp
┃ ┃ ┗ 📂src
┃ ┃ ┃ ┗ 📜Client.cpp
┃ ┣ 📂method
┃ ┃ ┣ 📂include
┃ ┃ ┃ ┣ 📜DELETE.hpp
┃ ┃ ┃ ┣ 📜DummyMethod.hpp
┃ ┃ ┃ ┣ 📜GET.hpp
┃ ┃ ┃ ┣ 📜IMethod.hpp
┃ ┃ ┃ ┗ 📜POST.hpp
┃ ┃ ┗ 📂src
┃ ┃ ┃ ┣ 📜DELETE.cpp
┃ ┃ ┃ ┣ 📜DummyMethod.cpp
┃ ┃ ┃ ┣ 📜GET.cpp
┃ ┃ ┃ ┗ 📜POST.cpp
┃ ┣ 📂request
┃ ┃ ┣ 📂include
┃ ┃ ┃ ┣ 📜IRequest.hpp
┃ ┃ ┃ ┗ 📜Request.hpp
┃ ┃ ┣ 📂request_parser
┃ ┃ ┃ ┣ 📂include
┃ ┃ ┃ ┃ ┣ 📜IRequestParser.hpp
┃ ┃ ┃ ┃ ┗ 📜RequestParser.hpp
┃ ┃ ┃ ┗ 📂src
┃ ┃ ┃ ┃ ┗ 📜RequestParser.cpp
┃ ┃ ┗ 📂src
┃ ┃ ┃ ┗ 📜Request.cpp
┃ ┣ 📂response
┃ ┃ ┣ 📂include
┃ ┃ ┃ ┣ 📜IResponse.hpp
┃ ┃ ┃ ┗ 📜Response.hpp
┃ ┃ ┗ 📂src
┃ ┃ ┃ ┗ 📜Response.cpp
┃ ┗ 📜.DS_Store
┣ 📂config
┃ ┣ 📂child_config
┃ ┃ ┣ 📂include
┃ ┃ ┃ ┗ 📜IChildConfig.hpp
┃ ┃ ┣ 📂location_config
┃ ┃ ┃ ┣ 📂include
┃ ┃ ┃ ┃ ┣ 📜ILocationConfig.hpp
┃ ┃ ┃ ┃ ┗ 📜LocationConfig.hpp
┃ ┃ ┃ ┗ 📂src
┃ ┃ ┃ ┃ ┗ 📜LocationConfig.cpp
┃ ┃ ┣ 📂mime_types_config
┃ ┃ ┃ ┣ 📂include
┃ ┃ ┃ ┃ ┣ 📜IMimeTypesConfig.hpp
┃ ┃ ┃ ┃ ┗ 📜MimeTypesConfig.hpp
┃ ┃ ┃ ┗ 📂src
┃ ┃ ┃ ┃ ┗ 📜MimeTypesConfig.cpp
┃ ┃ ┣ 📂proxy_config
┃ ┃ ┃ ┣ 📂include
┃ ┃ ┃ ┃ ┣ 📜IProxyConfig.hpp
┃ ┃ ┃ ┃ ┗ 📜ProxyConfig.hpp
┃ ┃ ┃ ┗ 📂src
┃ ┃ ┃ ┃ ┗ 📜ProxyConfig.cpp
┃ ┃ ┣ 📂root_config
┃ ┃ ┃ ┣ 📂include
┃ ┃ ┃ ┃ ┣ 📜IRootConfig.hpp
┃ ┃ ┃ ┃ ┗ 📜RootConfig.hpp
┃ ┃ ┃ ┗ 📂src
┃ ┃ ┃ ┃ ┗ 📜RootConfig.cpp
┃ ┃ ┗ 📂server_config
┃ ┃ ┃ ┣ 📂include
┃ ┃ ┃ ┃ ┣ 📜IServerConfig.hpp
┃ ┃ ┃ ┃ ┗ 📜ServerConfig.hpp
┃ ┃ ┃ ┗ 📂src
┃ ┃ ┃ ┃ ┗ 📜ServerConfig.cpp
┃ ┣ 📂include
┃ ┃ ┣ 📜Config.hpp
┃ ┃ ┗ 📜IConfig.hpp
┃ ┣ 📂parser
┃ ┃ ┣ 📂include
┃ ┃ ┃ ┣ 📜ConfigParser.hpp
┃ ┃ ┃ ┗ 📜IConfigParser.hpp
┃ ┃ ┗ 📂src
┃ ┃ ┃ ┗ 📜ConfigParser.cpp
┃ ┗ 📂src
┃ ┃ ┗ 📜Config.cpp
┣ 📂exception
┃ ┣ 📂include
┃ ┃ ┣ 📜ExceptionThrower.hpp
┃ ┃ ┗ 📜errorMessage.hpp
┃ ┗ 📂src
┃ ┃ ┗ 📜ExceptionThrower.cpp
┣ 📂server
┃ ┣ 📂include
┃ ┃ ┣ 📜EventHandler.hpp
┃ ┃ ┣ 📜Kqueue.hpp
┃ ┃ ┣ 📜Server.hpp
┃ ┃ ┗ 📜ServerManager.hpp
┃ ┗ 📂src
┃ ┃ ┣ 📜EventHandler.cpp
┃ ┃ ┣ 📜Kqueue.cpp
┃ ┃ ┣ 📜Server.cpp
┃ ┃ ┗ 📜ServerManager.cpp
┣ 📂utils
┃ ┣ 📂checker
┃ ┃ ┣ 📂include
┃ ┃ ┃ ┣ 📜FileChecker.hpp
┃ ┃ ┃ ┣ 📜IChecker.hpp
┃ ┃ ┃ ┗ 📜IFileChecker.hpp
┃ ┃ ┗ 📂src
┃ ┃ ┃ ┗ 📜FileChecker.cpp
┃ ┣ 📂reader
┃ ┃ ┣ 📂include
┃ ┃ ┃ ┣ 📜IReader.hpp
┃ ┃ ┃ ┗ 📜Reader.hpp
┃ ┃ ┗ 📂src
┃ ┃ ┃ ┗ 📜Reader.cpp
┃ ┗ 📂util
┃ ┃ ┣ 📂include
┃ ┃ ┃ ┣ 📜Color.hpp
┃ ┃ ┃ ┣ 📜Status.hpp
┃ ┃ ┃ ┣ 📜Utils.hpp
┃ ┃ ┃ ┗ 📜Utils.tpp
┃ ┃ ┗ 📂src
┃ ┃ ┃ ┣ 📜Status.cpp
┃ ┃ ┃ ┗ 📜Utils.cpp
┗ 📜main.cpp