A guide on how to manually test your "42 Coding School" project "webserv" (October 2022) and a beta version of an automated tester.
Next: How to perform a stress test [Contents]
There are many tools that you can use to send specific HTTP requests to test how your server responds. To name some of them there are curl, netcat and postman which are all available on the schools iMacs.
Curl is a command-line utility for transferring data from or to a server.
The -X option lets you define the request method (by default it is GET)
The -H option lets you add, replace or remove request header fields (curl adds some by default)
The --data option lets you add a request body.
The --resolve option allows you to internally redirect the requests for a host to an IP address. You can use this to be able to send requests to hosts other than 127.0.0.1 or localhost.
Here are a few examples of how to use it:
curl -X POST -H "Content-Type: plain/text" --data "request body text" http://localhost:8080/new_file.txt
curl --resolve www.webserv.com:8080:127.0.0.1 http://www.webserv.com:8080/
curl --resolve webserv.com:80:127.0.0.1 http://webserv.com/index.html
(port 80 is the default port for HTTP)
Netcat is a computer networking utility for reading from and writing to network connections using TCP or UDP. You can use it to send a freely written request to your server. This is nice beacuse this way you could also send invalid requests. An easy way of using netcat is to echo your custom request and pipe it into netcat as follows:
echo "GET / HTTP/1.1\r\nHost: webserv\r\n\r\n" | nc localhost 8080
Postman is an API platform for building and using APIs. You can use it to send requests to your server. Download it to to your school iMac via the "Managed Software Center".
Click on the plus to create a new request.
Select the method, enter a url and add a request body and / or header fields (note that there are some hidden default header fileds, that can be removed if needed).
After the request got received, the status code is shown and you can check out its header fileds and body.
Next: Automated tester Previous: How to manually send a specific HTTP request [Contents]
Siege is a HTTP load test and benchmark utility and can be used to stress a web server. If you use it with the -b option it will send the request without delays in between and until you exit it (e.g. with ctrl+c). It will then show a summary of the test where you can see the availability. The evaluation sheet asks for an availibility > 99.5%.
For example the command:
siege -b http://localhost:8080/empty.html
could give you an output similar to this one:
You can install siege on the school iMacs by using brew, as described below.
The following command installs brew and adds the path to its binary to .zshrc, so it can be used without the path. If you want to use it in bash, replace "zsh" with "bash".
rm -rf $HOME/.brew && git clone --depth=1 <https://github.com/Homebrew/brew> $HOME/.brew && echo 'export PATH=$HOME/.brew/bin:$PATH' >> $HOME/.zshrc && source $HOME/.zshrc && brew update
To install siege you need brew. Use the command brew install siege
. If you get "Error: Xcode alone is not sufficient on Catalina." install the xcode Command Line Tools with xcode-select --install
. This will open the following installation window:
Click on install -> aggree -> done and then use brew install siege
again.
Previous: How to perform a stress test [Contents]
The automated tester is kind of a beta version (private tester made public) and lacks a lot of testing and errorhandling, but I guess it can be usefull anyway. Because some tests depend on the implementation of the server it is also possible that the behaviour of your server might be correct although the tester marks it as wrong or vice versa.
The tester will send different requests (test cases) to your server and compare the response it receives (for the custom tests it is the entire response, for the others it's only the response body) with the "expected outcome string". There are three stages of comparison. As soon as a comparison for a test case succeeds, no further comparisons for this test case will be made.
In the first stage the tester checks for an exact match between the response body and the expected result. On success the tester shows "OK".
If it is not an exact match the expected result string gets interpreted as status code (if possible) and gets checked against the response's status code. On success the tester shows "OK status code: " followed by the status code.
For the last stage of comparison the response body is checked for an occurrence of the "expected outcome string". If it is found the tester shows "OK found: " followed by the found string. This comparison is very unexact, therefore the "expected output string" should be as special as possible to lower the change of false positives.
If none of the comparisons succeeds, the tester will show "KO" followed by the received response.
The output looks like this:
The blue text shows the file and line number of the test case. You can press the command key and left-click on it to jump there.
On each run the tester will create the following directory structure within make-42-webserv-great-again/server/ and delete it afterwards:
root/
├── dir/
│ ├── %file
│ ├── custom/
│ ├── index/
│ │ ├── custom/
│ │ │ └── custom.html
│ │ ├── index.html
│ │ └── no/
│ │ ├── autoindex/
│ │ ├── no_autoindex/
│ │ └── no_permission_dir/
│ ├── no_permission_dir/
│ │ ├── file
│ │ └── file.cgi
│ ├── one/
│ │ ├── custom.html
│ │ └── two/
│ │ └── index.html
│ ├── permission_dir/
│ │ ├── .cgi
│ │ ├── file
│ │ ├── file.cgi
│ │ └── no_permission_file
│ └── uploads/
│ ├── file.cgi
│ ├── no_permission_dir/
│ │ └── file
│ ├── no_permission_file
│ └── no_permission_file.cgi
├── index.html
├── server1/
│ ├── custom/
│ │ └── custom.html
│ ├── file
│ └── file.cgi
└── server2/
├── file
└── file.cgi
Clone the "make-42-webserv-great-again" repository into the root directory of your "webserv" repository.
Create a configuration file with the following settings:
server_name: webserv
port: 80
root: make-42-webserv-great-again/server/root/
max_body_size: 100
autoindex: false
index_page: index.html
cgi .cgi: should be executed using the executable "make-42-webserv-great-again/server/cgi_bin/cgi".
route /route/
allowed methods: GET
routed to: make-42-webserv-great-again/server/root/dir/
route /route/one/
allowed methods: GET
index_page: custom.html
routed to: make-42-webserv-great-again/server/root/dir/one
route /route/one/two/
allowed methods: GET
index_page: index.html
routed to: make-42-webserv-great-again/server/root/dir/index/
route /uploads/
allowed methods: GET, POST, DELETE
routed to: make-42-webserv-great-again/server/root/dir/uploads/
route /index/
allowed methods: GET
routed to: make-42-webserv-great-again/server/root/dir/index/
route /index/no/autoindex/
allowed methods: GET
autoindex: true
routed to: make-42-webserv-great-again/server/root/dir/index/no/autoindex/
route /index/no/no_autoindex/
allowed methods: GET
autoindex: false
routed to: make-42-webserv-great-again/server/root/dir/index/no/no_autoindex/
route /index/custom/
allowed methods: GET
index_page: custom.html
routed to: make-42-webserv-great-again/server/root/dir/index/custom/
server_name: server1
port: 6000
root: make-42-webserv-great-again/server/root/server1/
error_page 404: make-42-webserv-great-again/server/root/server1/custom/custom.html
cgi .cgi: should be executed using the executable "make-42-webserv-great-again/server/cgi_bin/no_permission_cgi".
server_name: server2
port: 8080, 8081
root: make-42-webserv-great-again/server/root/server2/
cgi .cgi: should be executed using the executable "doesntexist".
route /
allowed methods: none
autoindex: false
route /route/
allowed methods: GET POST
Relation of subject expression to the used keywords:
"default error page" = error_page
"client body size" = max_body_size
"directory listing" = autoindex (true / false)
"default file to answer if the request is a directory" = index_page (the name of the file)
Start your server with the configuration described in Setup and use make run
in the command line from the root of the "make-42-webserv-great-again" repository.
To add, remove or change test cases, edit the corresponding file within the root of the "make-42-webserv-great-again" repository, as described below. To add, remove or change the known host:port combinations for the tester, edit the file 0_hosts.cpp as follows: add_host("uri-host", "port");
For the custom tests a simple client is used to send a request. You can for example use it to send invalid requests or requests with certain (invalid) header fields. Edit the file 1_custom.cpp as follows: custom_test("HTTP request", "expected resonse or status code", FILE_LINE);
The default port for the custom requests is port 80. Make sure your server is listening on it, or change it by editing uint16_t g_port_for_custom_requests = 80;
For the GET request tests the libcurl API is used to send a GET request to the url of your choice. Header fields get added automatically. Edit the file 2_get.cpp as follows: GET_test("url", "expected resonse body or status code", FILE_LINE);
For the POST request tests the libcurl API is used to send a POST request with the body: "This is my POST body with length of 39.", to the url of your choice. Header fields get added automatically. Edit the file 3_post.cpp as follows: POST_test("url", "expected resonse body or status code", FILE_LINE);
For the DELETE request tests the libcurl API is used to send a DELETE request to the url of your choice. Header fields get added automatically. Edit the file 4_delete.cpp as follows: DELETE_test("url", "expected resonse body or status code", FILE_LINE);