9 Commits

Author SHA1 Message Date
0aeeb484e2 Merge pull request #96 from aykhans/refactor/general
All checks were successful
golangci-lint / lint (push) Successful in 3m58s
💄 General refactoring
2025-03-19 05:29:13 +04:00
fc3244dc33 💄 General refactoring 2025-03-19 05:28:14 +04:00
aa6ec450b8 Merge pull request #95 from aykhans/fix/types
🐛 Fix 'AppendByKey' method of the '[]KeyValue[string, []string]' types
2025-03-19 04:06:47 +04:00
e31f5ad204 🐛 Fix 'AppendByKey' method of the '[]KeyValue[string, []string]' types 2025-03-19 04:06:10 +04:00
de9a4bb355 Merge pull request #94 from aykhans/dependabot/go_modules/go_modules-c153b83258
Bump golang.org/x/net from 0.35.0 to 0.36.0 in the go_modules group
2025-03-19 02:31:20 +04:00
dependabot[bot]
234ca01e41 Bump golang.org/x/net from 0.35.0 to 0.36.0 in the go_modules group
Bumps the go_modules group with 1 update: [golang.org/x/net](https://github.com/golang/net).


Updates `golang.org/x/net` from 0.35.0 to 0.36.0
- [Commits](https://github.com/golang/net/compare/v0.35.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
  dependency-group: go_modules
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 22:29:02 +00:00
cc490143ea Merge pull request #92 from aykhans/refactor/config
Restructure entire project logic
2025-03-19 02:28:13 +04:00
a8c3efe198 🔨 Refactor 'releaseDodos' function 2025-03-19 01:18:36 +04:00
3c2a0ee1b2 📚 Update README.md 2025-03-18 23:41:20 +04:00
8 changed files with 48 additions and 49 deletions

View File

@@ -1,11 +1,11 @@
<h1 align="center">Dodo is a fast and easy-to-use HTTP benchmarking tool.</h1>
<h1 align="center">Dodo - A Fast and Easy-to-Use HTTP Benchmarking Tool</h1>
<p align="center">
<img width="30%" height="30%" src="https://ftp.aykhans.me/web/client/pubshares/VzPtSHS7yPQT7ngoZzZSNU/browse?path=%2Fdodo.png">
</p>
## Installation
### With Docker (Recommended)
### Using Docker (Recommended)
Pull the Dodo image from Docker Hub:
@@ -13,26 +13,26 @@ Pull the Dodo image from Docker Hub:
docker pull aykhans/dodo:latest
```
If you use Dodo with Docker and a local config file, you must provide the config.json file as a volume to the Docker run command (not as the "-f config.json" argument).
When using Dodo with Docker and a local config file, you must provide the config.json file as a volume to the Docker run command (not as the "-f config.json" argument):
```sh
docker run -v /path/to/config.json:/config.json aykhans/dodo
```
If you use it with Docker and provide config file via URL, you do not need to set a volume.
If you're using Dodo with Docker and providing a config file via URL, you don't need to set a volume:
```sh
docker run aykhans/dodo -f https://raw.githubusercontent.com/aykhans/dodo/main/config.json
```
### With Binary File
### Using Binary Files
You can grab binaries in the [releases](https://github.com/aykhans/dodo/releases) section.
You can download pre-built binaries from the [releases](https://github.com/aykhans/dodo/releases) section.
### Build from Source
### Building from Source
To build Dodo from source, you need to have [Go1.24+](https://golang.org/dl/) installed. <br>
Follow the steps below to build dodo:
To build Dodo from source, you need to have [Go 1.24+](https://golang.org/dl/) installed.
Follow these steps:
1. **Clone the repository:**
@@ -56,7 +56,7 @@ This will generate an executable named `dodo` in the project directory.
## Usage
You can use Dodo with CLI arguments, a JSON config file, or both. If you use both, CLI arguments will always override JSON config arguments if there is a conflict.
You can use Dodo with CLI arguments, a JSON config file, or both. When using both, CLI arguments will override JSON config values if there's a conflict.
### 1. CLI
@@ -72,7 +72,7 @@ With Docker:
docker run --rm -i aykhans/dodo -u https://example.com -m GET -d 10 -r 1000 -t 2s
```
### 2. JSON config file
### 2. JSON Config File
Send 1000 GET requests to https://example.com with 10 parallel dodos (threads) and a timeout of 800 milliseconds:
@@ -152,7 +152,7 @@ docker run --rm -i -v /path/to/config.json:/config.json aykhans/dodo
docker run --rm -i aykhans/dodo -f https://example.com/config.json
```
### 3. Both (CLI & JSON)
### 3. Combined (CLI & JSON)
Override the config file arguments with CLI arguments:
@@ -168,17 +168,17 @@ docker run --rm -i -v /path/to/config.json:/config.json aykhans/dodo -u https://
## CLI and JSON Config Parameters
If `Headers`, `Params`, `Cookies`, `Body`, and `Proxy` fields have multiple values, each request will choose a random value from the list.
If `Headers`, `Params`, `Cookies`, `Body`, or `Proxy` fields have multiple values, each request will choose a random value from the list.
| Parameter | JSON config file | CLI Flag | CLI Short Flag | Type | Description | Default |
| --------------- | ---------------- | ------------ | -------------- | ------------------------------ | --------------------------------------------------------------- | ------- |
| Config file | - | -config-file | -f | String | Path to the local config file or http(s) URL of the config file | - |
| Config file | - | -config-file | -f | String | Path to local config file or http(s) URL of the config file | - |
| Yes | yes | -yes | -y | Boolean | Answer yes to all questions | false |
| URL | url | -url | -u | String | URL to send the request to | - |
| Method | method | -method | -m | String | HTTP method | GET |
| Requests | requests | -requests | -r | UnsignedInteger | Total number of requests to send | 1000 |
| Dodos (Threads) | dodos | -dodos | -d | UnsignedInteger | Number of dodos (threads) to send requests in parallel | 1 |
| Timeout | timeout | -timeout | -t | Duration | Timeout for canceling each request (milliseconds) | 10000 |
| Timeout | timeout | -timeout | -t | Duration | Timeout for canceling each request | 10s |
| Params | params | -param | -p | [{String: String OR [String]}] | Request parameters | - |
| Headers | headers | -header | -H | [{String: String OR [String]}] | Request headers | - |
| Cookies | cookies | -cookie | -c | [{String: String OR [String]}] | Request cookies | - |

View File

@@ -27,7 +27,7 @@ Usage with all flags:
-u https://example.com -m POST \
-d 10 -r 1000 -t 3s \
-b "body1" -body "body2" \
-H "header1: value1" -header "header2: value2" \
-H "header1:value1" -header "header2:value2" \
-p "param1=value1" -param "param2=value2" \
-c "cookie1=value1" -cookie "cookie2=value2" \
-x "http://proxy.example.com:8080" -proxy "socks5://proxy2.example.com:8080" \

2
go.mod
View File

@@ -13,7 +13,7 @@ require (
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/net v0.36.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.29.0 // indirect
golang.org/x/text v0.22.0 // indirect

4
go.sum
View File

@@ -21,8 +21,8 @@ github.com/valyala/fasthttp v1.59.0 h1:Qu0qYHfXvPk1mSLNqcFtEk6DpxgA26hy6bmydotDp
github.com/valyala/fasthttp v1.59.0/go.mod h1:GTxNb9Bc6r2a9D0TWNSPwDz78UxnTGBViY3xZNEqyYU=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=

View File

@@ -60,23 +60,22 @@ func releaseDodos(
requestCountPerDodo uint
dodosCount uint = requestConfig.GetValidDodosCountForRequests()
dodosCountInt int = int(dodosCount)
requestCount uint = requestConfig.RequestCount
responses = make([][]*Response, dodosCount)
increase = make(chan int64, requestCount)
increase = make(chan int64, requestConfig.RequestCount)
)
wg.Add(dodosCountInt)
streamWG.Add(1)
streamCtx, streamCtxCancel := context.WithCancel(context.Background())
go streamProgress(streamCtx, &streamWG, int64(requestCount), "Dodos Working🔥", increase)
go streamProgress(streamCtx, &streamWG, int64(requestConfig.RequestCount), "Dodos Working🔥", increase)
for i := range dodosCount {
if i+1 == dodosCount {
requestCountPerDodo = requestCount - (i * requestCount / dodosCount)
requestCountPerDodo = requestConfig.RequestCount - (i * requestConfig.RequestCount / dodosCount)
} else {
requestCountPerDodo = ((i + 1) * requestCount / dodosCount) -
(i * requestCount / dodosCount)
requestCountPerDodo = ((i + 1) * requestConfig.RequestCount / dodosCount) -
(i * requestConfig.RequestCount / dodosCount)
}
go sendRequest(

View File

@@ -21,7 +21,7 @@ func (cookies Cookies) String() string {
displayLimit := 3
for i, item := range cookies {
for i, item := range cookies[:min(len(cookies), displayLimit)] {
if i > 0 {
buffer.WriteString(",\n")
}
@@ -96,18 +96,18 @@ func (cookies *Cookies) Set(value string) error {
return nil
}
func (cookies *Cookies) AppendByKey(key string, value string) {
if existingValue := cookies.GetValue(key); existingValue != nil {
*cookies = append(*cookies, KeyValue[string, []string]{Key: key, Value: append(existingValue, value)})
func (cookies *Cookies) AppendByKey(key, value string) {
if item := cookies.GetValue(key); item != nil {
*item = append(*item, value)
} else {
*cookies = append(*cookies, KeyValue[string, []string]{Key: key, Value: []string{value}})
}
}
func (cookies *Cookies) GetValue(key string) []string {
for _, cookie := range *cookies {
if cookie.Key == key {
return cookie.Value
func (cookies Cookies) GetValue(key string) *[]string {
for i := range cookies {
if cookies[i].Key == key {
return &cookies[i].Value
}
}
return nil

View File

@@ -21,7 +21,7 @@ func (headers Headers) String() string {
displayLimit := 3
for i, item := range headers {
for i, item := range headers[:min(len(headers), displayLimit)] {
if i > 0 {
buffer.WriteString(",\n")
}
@@ -96,18 +96,18 @@ func (headers *Headers) Set(value string) error {
return nil
}
func (headers *Headers) AppendByKey(key string, value string) {
if existingValue := headers.GetValue(key); existingValue != nil {
*headers = append(*headers, KeyValue[string, []string]{Key: key, Value: append(existingValue, value)})
func (headers *Headers) AppendByKey(key, value string) {
if item := headers.GetValue(key); item != nil {
*item = append(*item, value)
} else {
*headers = append(*headers, KeyValue[string, []string]{Key: key, Value: []string{value}})
}
}
func (headers *Headers) GetValue(key string) []string {
for _, header := range *headers {
if header.Key == key {
return header.Value
func (headers Headers) GetValue(key string) *[]string {
for i := range headers {
if headers[i].Key == key {
return &headers[i].Value
}
}
return nil

View File

@@ -21,7 +21,7 @@ func (params Params) String() string {
displayLimit := 3
for i, item := range params {
for i, item := range params[:min(len(params), displayLimit)] {
if i > 0 {
buffer.WriteString(",\n")
}
@@ -96,18 +96,18 @@ func (params *Params) Set(value string) error {
return nil
}
func (params *Params) AppendByKey(key string, value string) {
if existingValue := params.GetValue(key); existingValue != nil {
*params = append(*params, KeyValue[string, []string]{Key: key, Value: append(existingValue, value)})
func (params *Params) AppendByKey(key, value string) {
if item := params.GetValue(key); item != nil {
*item = append(*item, value)
} else {
*params = append(*params, KeyValue[string, []string]{Key: key, Value: []string{value}})
}
}
func (params *Params) GetValue(key string) []string {
for _, param := range *params {
if param.Key == key {
return param.Value
func (params Params) GetValue(key string) *[]string {
for i := range params {
if params[i].Key == key {
return &params[i].Value
}
}
return nil