Papy is an open-source framework that can be used to stress test API endpoints with GET requests or an influx of POST request in the form of JSON packages.
Some of the key features include:
- Customized targetting (server address and endpoint)
- Customizable payloads
- Pseudo randomized payloads
- Verbose or compact response reporting
- HTTP and HTTPS traffic capabilities
- Traffic controls (Spike traffic, Ramp traffic, Rate limited traffic)
The project has 3 main dependencies:
- nlohmann/json version 3.11.3
- httplib.h version 0.18.1
- OpenSSL version 3.4.0
The following is a step-by-step set of instructions for installing and accessing Papy.
Clone the repo:
git clone https://github.com/noahpop77/Papy.gitNavigate to the cloned Papy directory:
cd PapyYou can determine if you have Make installed by using:
make --versionThe command to build Papy is the following once you are in the project root directory.
make rebuildNotes
On Ubuntu based (and other linux systems) systems you might have to install `libssl-dev` and `zlib1g-dev`
After the build the Papy Binary/executable will be in the bin directory.
Navigate to the Papy/bin directory:
cd binPapy will be in the bin directory. Run the Papy help command to get a sense of what flags you can make use of and to verify that papy was built successfully.
./papy --helpLets launch some requests! The following are examples of possible use cases and the commands that would go along with them.
Papy is highly configurable though so there are many more possible configurations depending on what you are trying to achieve.
If you want to launch a bunch of GET requests to a specific site:
./papy --threads 4 --target "https://www.{YOUR_TARGET_IP_ADDR}.com"If you want to send a static payload from a JSON file then simply specify the file path to your JSON file.
The following command looks to the directory structure ../archive/mappingFiles/testPayload.json for example to send testPayload.json as the body of the POST requests.
This command also displays the functionality of the --rate flag which rate limits the requests by adding a delay of X milliseconds between each request.
./papy --threads 1 --target "http://10.0.0.7" --endpoint "/printJson" --payload "../archive/mappingFiles/testPayload.json" --rate 2000The contents of testPayload.json are as follows:
{
"overrides": {
"business_unit" : {
"name" : "BOB"
},
"application" : {
"name" : "BOB"
},
"project" : {
"name" : "BOB"
}
}
}
The following is an example of me testing the database of a locally deployed web application I created called M-Track.
This execution run will use the randomized payload generation for League of Legends.
The lol payload will be a randomized League of Legends match file and send that to the API endpoint of M-Track.
./papy --threads 4 --target "http://10.0.0.7" --endpoint "/addMatch" --payload lolSince this was designed to be simple as well as a Command Line Interface tool the UI follows this paradigm. You can see the UI information of Papy with any execution of the Papy command like:
./papy [Flag] {Value} [Flag] {Value} [Flag] {Value} ...This parameter lets you specify the amount of CPU threads you want to use for the programs execution. The more you add the more concurrent requests will be sent.
If you try to assign more threads that you have physically then the speed will not necessarily increase due to the CPU having to switch between the active tasks anyways so there is no real point to assigning more threads that you physically have on your CPU.
Faster threads however do assist in the speed of requests per thread.
Assigns the url of the target. Should be in the format http://www.mtrack.com.
Specifically the http:// or https:// portion of the address must be included.
This is because this is how Papy determines which protocols to use to send the requests.
Specifies the endpoint of the specific server. This endpoint string gets appended to the target address.
So if you want to query the target https://www.mtrack.com and the endpoint /addMatch you can use the command:
./papy --threads 1 --target "https://www.mtrack.com" --endpoint "/addMatch"The --parameter flag lets you specify end of URL paramaters. For example, the following Papy command will yield the final url of https://www.mtrack.com/addMatch?variable=BOB.
./papy --threads 1 --target "https://www.mtrack.com" --endpoint "/addMatch" --parameter "?variable=BOB"This parameter will let you specify the amount of payloads that each thread will launch.
If you have a single thread and specify --count to be 10 then Papy will launch 10 requests.
If you however have --threads set to 4 and you have --count set to 10 it will launch 40 requests. The count number is FOR EACH THREAD.
--rate specifies the delay in milliseconds between payloads being sent out.
If you specify --rate 2000 then there will be a 2 secon delay between each set of packets being sent out.
Once again if you have the threadcount set to 4 and a delay of 2000 then 4 packets will be sent out every 2 seconds. The delay is also per thread.
This flag has no parameter. If it is present in the command line arguments it will enable verbose output.
It will show you the response of each request being sent out. Without this flag all you will see in terms of the responses of the requests is the main statistics line for Papy.
Total Sent: 36 | Successful: 36 | Failed: 0 | Packets/s: 1 | Elapsed Time: 70099
This flag lets you specify a "spike" time. What happens is that whatever delay in ms you set for this flag will be used to calculate when the payloads will be sent out.
Each request will be sent out at a random delay between zero and the number that you set. This makes the traffic much more chaotic and similar to real world situations.
This flag lets you specify test a ramping simulation. The traffic will have a delay of the one you set for the --ramp flag and then get halved each time a payload is sent.
It will ramp faster and faster until it runs at the max speed capable of your hardware.
This is where a good amount of the functionality is. Depending on the payload that you set you will have behavior vary drastically.
At the moment there are 3 main operating modes:
- No payload: If no payload is set then Papy will send GET requests to the specified address and endpoint.
lol: If this is set then it will generate a custom pseudo-random payload.{filepath}: If a file path is specified then Papy will look for a JSON file and parse it. That parsed JSON will then be used as a body for the payload.
If you would like to contribute to this project follow the Getting Started section and that will get you up and running.
Regarding actually contributing code, please fork the repository and open a pull request to the main branch.
Naming Variables:
- I use camel case for all variable and class names.
Structure:
- Each logical fucntion is seperated into its own
.cppfile with an accompanying.hpp. - All sub
.hppfiles are connected tocommon.hppand that is#includedinto themain.cppfile.
The directory structure that will be used as a reference will be:
project_name/
|-- src/
| |-- main.cpp
| |-- module1/
| | |-- module1.cpp
| | |-- module1.h
| |-- module2/
| | |-- module2.cpp
| | |-- module2.h
|-- include/
| |-- project_name/
| | |-- module1.h
| | |-- module2.h
|-- lib/
|-- tests/
| |-- unit_tests.cpp
|-- build/
|-- doc/
|-- CMakeLists.txt
|-- README.md
The following is a set of helper functions or terminal settings I use for my personal setup and are by no means required for Papy. They are just useful.
# This will export the following zshrc PS1 terminal settings and get my
# terminal looking like how I preffer
# Looks like:
#
# bsawa@Z-Drive src
# ->
export PS1="%{$(tput setaf 36)%}%n%{$(tput setaf 36)%}@%{$(tput setaf 36)%}%m %{$(tput setaf 36)%}%1~
%{$(tput sgr0)%}-> "
# This function is meant to be added to the end of your ~/.bashrc file
# so that you can more easily compile your project
function comp {
local filename="${1%.*}.out"
sudo g++ -w "$1" -o "$filename" && "./$filename" "${@:2}"
}Command to run build and execution with a test
sudo g++ main.cpp apiClient.cpp clock.cpp commandLine.cpp match.cpp matchBuilder.cpp myRandom.cpp payloadBuilder.cpp threadWorks.cpp -std=c++23 && ./a.out --threads 1 --target "http://10.0.0.7" --type GETNotes
Buiding with `make rebuild -j$(nproc)` works but is a little inconsistent and sometimes requires two attempts.
Time savings of multi-threaded building of the binary is not really worth it and the usual `make rebuild` is fast enough build time wise and more consistent.
Also if you are building this on MacOS you will need to make a single change to the Makefile as it stands.
The flag `-std=c++23` in the line `CXXFLAGS = -std=c++23 -I$(OPENSSL_DIR) # Include local OpenSSL headers` will need to be changed to `-std=c++2b`.
Game Name + Tag: bsawatestuser#test
Before anything you will need the Perf tool and the FlameGraph:
git clone --depth 1 https://github.com/brendangregg/perf-toolsgit clone https://github.com/brendangregg/FlameGraph.gitWhen using WSL you might encounter issues which can be fixed by doing the following steps:
clone --depth 1 https://github.com/microsoft/WSL2-Linux-Kernelcd WSL2-Linux-Kernel/tools/perfmake -j$(nproc)sudo cp perf /usr/local/bin//usr/local/bin/perf --version- Record
perf record -F 99 -g -- ./bin/papy --threads 16 --endpoint "/printJson" --target "http://localhost" --payload lol --count 600- Translate the data
perf script > out.perf- Convert it to readeable format for flamegraph
./stackcollapse-perf.pl out.perf > out.folded- Then create a visual out of the data
./flamegraph.pl out.folded > flamegraph.svgAssuming you are inside Papy/src directory point both the stack and flamegraph files to the FlameGraph directory.
-
DO NOT USE THIS FOR MALICIOUS PURPOSES
-
GET PERMISSION FROM THE OWNER OF RESOURCES YOU WILL USE THIS TOOL AGAINST
-
I TAKE NO RESPONSIBILITY FOR THE ACTIONS OF USERS OF THIS APPLICATION








