Stress Testing with cURL
Tags: bash, powershell, curl
Published: 2022-09-15 12:06:11

---
title: Stress Testing with cURL
published: true
description: 
tags: bash, powershell, curl
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
canonical_url: https://www.aloneguid.uk/posts/2022/09/curl-stress-testing/
---

There are plenty of tools for stress testing, read [RapidAPI](https://rapidapi.com/products/api-testing/), [paw](https://paw.cloud/), [SoapUI](https://www.soapui.org/), [Postman](https://www.postman.com/), [rest-assured](https://rest-assured.io/), [JMeter](https://jmeter.apache.org/) and so on! I'm sure they are amazing, however that's all big and heavy, slow, sometimes paid tools!

If all you need is just simple (or not, depending on what you want) stress testing, [cURL](https://curl.se/) is your hidden gem! cURL works pretty much everywhere, and even Windows has curl installed [out of the box](https://docs.microsoft.com/en-us/virtualization/community/team-blog/2017/20171219-tar-and-curl-come-to-windows)! 

To remind, to issue a simple cURL request, just issue it like `curl http://localhost/path1`. 

## A bit more

What if you need to test path1, path2 and path3? Easy:

```bash
curl http://localhost/path{1,2,3}
```

that will issue:

```
http://localhost/path1
http://localhost/path2
http://localhost/path3
```

that can be also replaced with `curl http://localhost/path[1-3]` to the same effect, i.e. you can use ranges!

Ranges can be mixed i.e.

```bash
curl http://localhost/path{1,2,3}/subpath[1-3]
```

will issue

```
http://localhost/path1/subpath1
http://localhost/path1/subpath2
http://localhost/path1/subpath3
http://localhost/path2/subpath1
http://localhost/path2/subpath2
http://localhost/path2/subpath3
http://localhost/path3/subpath1
http://localhost/path3/subpath2
http://localhost/path3/subpath3
```

you can also use letters i.e. `http://localhost/path-[a-z]` will issue queries from `http://localhost/path-a` to `http://localhost/path-z` (26 requests total).

That is already cool!

All the requests are executed **sequentially** so if that's ok with you (and most of the times it is) you should be fine.

## Serious offense

Ok, what about a parallel load? [`xargs`](https://linuxconfig.org/xargs-for-beginners-with-examples) will come to rescue! Specifically the [multi-threaded version](https://linuxconfig.org/multi-threaded-xargs-with-examples). As you should know, `xargs` (stands for *extended arguments*) allows to fork execution from an input to an execution per line. Combined with [`seq`](https://www.howtogeek.com/693549/how-to-use-the-seq-command-on-linux/) you can start an offensive 😜`seq` can generate input you want (numbers only) i.e. `seq 1 5` will produce 5 lines:

```
1
2
3
4
5
```

then piping this into `xargs` allows 5 executions i.e. `seq 1 5 | xargs -I{} curl http://localhost/path{}` will invoke sequentially:

```
http://localhost/path1
http://localhost/path2
http://localhost/path3
http://localhost/path4
http://localhost/path5
```

but passing `-P` will allow you to paralellise requests! So this is how you issue 500 requests with 5 always going in parallel:

```bash
seq 1 500 | xargs -P5 -I{} curl http://localhost/path{}
```

If you need to absolutely exhaust the target, pass a higher number into `-P`, or to max it out pass `0` as parallelism. From official man pages:

>  If max-procs is 0, xargs will run  as  many processes  as  possible  at  a time.

You do lose some ability of more powerful cURL ranges, especially with characters, as `seq` only produces numbers. However even this can be fixed. 

`seq` supports `-f` switch allowing you to pass a custom format string, however that's not very useful because you are already formatting with `xargs` (`-I{}`)

You can do even better - generate a lot of word permutations! Take `crunch` for example (may need to install it i.e. `apt install crunch`) and generate words 5 character length:

```bash
crunch 5 5 -o 5words.txt
```

The file is quite large (67mb) and takes a few seconds to generate, hence we save it locally. Then take this "dictionary" as an input of a stress test:

```bash
cat 5words.txt | xargs -n1 -P5 -I{} curl http://localhost/words/{}
```

That will issue 11881376 (11 million!) requests in parallel! More than enough if you ask me. 

So is there a need for a dedicated stress tool? I don't think so.

### PowerShell Friends

```powershell
1..10 | % -Parallel { curl http://localhost/path$_ }
```

`1..10` is a "range operator", equivalent to `seq 1 10` (at least something is shorter in PS ;)

`%` is an alias for [`Foreach-Object`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/foreach-object?view=powershell-7.2) which can run in parallel mode optionally.

`-Parallel` flag is only available in PowerShell 7 and higher. One can use `-ThrottleLimit` parameter to further limit number of parallel "threads", otherwise it's unlimited (equivalent to `xargs`' `-P`)

**Ranges in PowerShell** can also do letters, but it's not obvious - `[char]'a'..[char]'z'` will produce

```
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
```

You can do a *reverse range* by doing `5..1` which produces

```
5
4
3
2
1
```