Skip to content

Commit fa55de0

Browse files
authored
Merge pull request #39 from aykhans/feat/add-proxy-check
Add 'no-proxy-check' parameter
2 parents e3cbe1e + d392d4a commit fa55de0

File tree

10 files changed

+232
-55
lines changed

10 files changed

+232
-55
lines changed

README.md

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<h1 align="center">Dodo is a simple and easy-to-use HTTP benchmarking tool.</h1>
22
<p align="center">
3-
<img width="30%" height="30%" src="https://raw.githubusercontent.com/aykhans/dodo/main/assets/dodo.png">
3+
<img width="30%" height="30%" src="https://ftp.aykhans.me/web/client/pubshares/hB6VSdCnBCr8gFPeiMuCji/browse?path=%2Fdodo.png">
44
</p>
55

66
## Installation
@@ -33,7 +33,7 @@ Follow the steps below to build dodo:
3333
3. **Build the project:**
3434

3535
```sh
36-
go build -o dodo
36+
go build -ldflags "-s -w" -o dodo
3737
```
3838

3939
This will generate an executable named `dodo` in the project directory.
@@ -58,8 +58,9 @@ You can find an example config structure in the [config.json](https://github.com
5858
{
5959
"method": "GET",
6060
"url": "https://example.com",
61-
"timeout": 10000,
62-
"dodos_count": 50,
61+
"no_proxy_check": false,
62+
"timeout": 2000,
63+
"dodos_count": 10,
6364
"request_count": 1000,
6465
"params": {},
6566
"headers": {},
@@ -77,7 +78,7 @@ You can find an example config structure in the [config.json](https://github.com
7778
]
7879
}
7980
```
80-
Send 1000 GET requests to https://example.com with 5 parallel dodos (threads) and a timeout of 10000 milliseconds:
81+
Send 1000 GET requests to https://example.com with 10 parallel dodos (threads) and a timeout of 2000 milliseconds:
8182

8283
```sh
8384
dodo -c /path/config.json
@@ -101,17 +102,18 @@ docker run --rm -v ./path/config.json:/dodo/config.json -i aykhans/dodo -u https
101102
## CLI and JSON Config Parameters
102103
If the Headers, Params, Cookies and Body fields have multiple values, each request will choose a random value from the list.
103104

104-
| Parameter | JSON config file | CLI Flag | CLI Short Flag | Type | Description | Default |
105-
| ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- |
106-
| Config file | - | --config-file | -c | String | Path to the JSON config file | - |
107-
| Yes | - | --yes | -y | Boolean | Answer yes to all questions | false |
108-
| URL | url | --url | -u | String | URL to send the request to | - |
109-
| Method | method | --method | -m | String | HTTP method | GET |
110-
| Request count | request_count | --request-count | -r | Integer | Total number of requests to send | 1000 |
111-
| Dodos count (Threads) | dodos_count | --dodos-count | -d | Integer | Number of dodos (threads) to send requests in parallel | 1 |
112-
| Timeout | timeout | --timeout | -t | Integer | Timeout for canceling each request (milliseconds) | 10000 |
113-
| Params | params | - | - | Key-Value {String: [String]} | Request parameters | - |
114-
| Headers | headers | - | - | Key-Value {String: [String]} | Request headers | - |
115-
| Cookies | cookies | - | - | Key-Value {String: [String]} | Request cookies | - |
116-
| Body | body | - | - | [String] | Request body | - |
117-
| Proxy | proxies | - | - | List[Key-Value {string: string}] | List of proxies (will check active proxies before sending requests) | - |
105+
| Parameter | JSON config file | CLI Flag | CLI Short Flag | Type | Description | Default |
106+
| --------------------- | ---------------- | --------------- | -------------- | -------------------------------- | ------------------------------------------------------------------- | ----------- |
107+
| Config file | - | --config-file | -c | String | Path to the JSON config file | - |
108+
| Yes | - | --yes | -y | Boolean | Answer yes to all questions | false |
109+
| URL | url | --url | -u | String | URL to send the request to | - |
110+
| Method | method | --method | -m | String | HTTP method | GET |
111+
| Request count | request_count | --request-count | -r | Integer | Total number of requests to send | 1000 |
112+
| Dodos count (Threads) | dodos_count | --dodos-count | -d | Integer | Number of dodos (threads) to send requests in parallel | 1 |
113+
| Timeout | timeout | --timeout | -t | Integer | Timeout for canceling each request (milliseconds) | 10000 |
114+
| No Proxy Check | no_proxy_check | --no-proxy-check| - | Boolean | Disable proxy check | false |
115+
| Params | params | - | - | Key-Value {String: [String]} | Request parameters | - |
116+
| Headers | headers | - | - | Key-Value {String: [String]} | Request headers | - |
117+
| Cookies | cookies | - | - | Key-Value {String: [String]} | Request cookies | - |
118+
| Body | body | - | - | [String] | Request body | - |
119+
| Proxy | proxies | - | - | List[Key-Value {string: string}] | List of proxies (will check active proxies before sending requests) | - |

assets/dodo.png

-230 KB
Binary file not shown.

config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"method": "GET",
33
"url": "https://example.com",
4+
"no_proxy_check": true,
45
"timeout": 10000,
56
"dodos_count": 50,
67
"request_count": 1000,

config/config.go

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
)
1212

1313
const (
14-
VERSION string = "0.5.1"
14+
VERSION string = "0.5.2"
1515
DefaultUserAgent string = "Dodo/" + VERSION
1616
ProxyCheckURL string = "https://www.google.com"
1717
DefaultMethod string = "GET"
@@ -21,10 +21,6 @@ const (
2121
MaxDodosCountForProxies uint = 20 // Max dodos count for proxy check
2222
)
2323

24-
type IConfig interface {
25-
MergeConfigs(newConfig IConfig) IConfig
26-
}
27-
2824
type RequestConfig struct {
2925
Method string
3026
URL *url.URL
@@ -37,6 +33,7 @@ type RequestConfig struct {
3733
Proxies []Proxy
3834
Body []string
3935
Yes bool
36+
NoProxyCheck bool
4037
}
4138

4239
func (config *RequestConfig) Print() {
@@ -47,6 +44,12 @@ func (config *RequestConfig) Print() {
4744
{Number: 2, WidthMax: 50},
4845
})
4946

47+
newHeaders := make(map[string][]string)
48+
newHeaders["User-Agent"] = []string{DefaultUserAgent}
49+
for k, v := range config.Headers {
50+
newHeaders[k] = v
51+
}
52+
5053
t.AppendHeader(table.Row{"Request Configuration"})
5154
t.AppendRow(table.Row{"Method", config.Method})
5255
t.AppendSeparator()
@@ -56,16 +59,18 @@ func (config *RequestConfig) Print() {
5659
t.AppendSeparator()
5760
t.AppendRow(table.Row{"Dodos", config.DodosCount})
5861
t.AppendSeparator()
59-
t.AppendRow(table.Row{"Request", config.RequestCount})
62+
t.AppendRow(table.Row{"Requests", config.RequestCount})
6063
t.AppendSeparator()
6164
t.AppendRow(table.Row{"Params", utils.MarshalJSON(config.Params, 3)})
6265
t.AppendSeparator()
63-
t.AppendRow(table.Row{"Headers", utils.MarshalJSON(config.Headers, 3)})
66+
t.AppendRow(table.Row{"Headers", utils.MarshalJSON(newHeaders, 3)})
6467
t.AppendSeparator()
6568
t.AppendRow(table.Row{"Cookies", utils.MarshalJSON(config.Cookies, 3)})
6669
t.AppendSeparator()
6770
t.AppendRow(table.Row{"Proxies Count", len(config.Proxies)})
6871
t.AppendSeparator()
72+
t.AppendRow(table.Row{"Proxy Check", !config.NoProxyCheck})
73+
t.AppendSeparator()
6974
t.AppendRow(table.Row{"Body", utils.MarshalJSON(config.Body, 3)})
7075

7176
t.Render()
@@ -87,11 +92,32 @@ func (config *RequestConfig) GetMaxConns(minConns uint) uint {
8792
}
8893

8994
type Config struct {
90-
Method string `json:"method" validate:"http_method"` // custom validations: http_method
91-
URL string `json:"url" validate:"http_url,required"`
92-
Timeout uint32 `json:"timeout" validate:"gte=1,lte=100000"`
93-
DodosCount uint `json:"dodos_count" validate:"gte=1"`
94-
RequestCount uint `json:"request_count" validation_name:"request-count" validate:"gte=1"`
95+
Method string `json:"method" validate:"http_method"` // custom validations: http_method
96+
URL string `json:"url" validate:"http_url,required"`
97+
Timeout uint32 `json:"timeout" validate:"gte=1,lte=100000"`
98+
DodosCount uint `json:"dodos_count" validate:"gte=1"`
99+
RequestCount uint `json:"request_count" validation_name:"request-count" validate:"gte=1"`
100+
NoProxyCheck utils.Option[bool] `json:"no_proxy_check"`
101+
}
102+
103+
func NewConfig(
104+
method string,
105+
timeout uint32,
106+
dodosCount uint,
107+
requestCount uint,
108+
noProxyCheck utils.Option[bool],
109+
) *Config {
110+
if noProxyCheck == nil {
111+
noProxyCheck = utils.NewNoneOption[bool]()
112+
}
113+
114+
return &Config{
115+
Method: method,
116+
Timeout: timeout,
117+
DodosCount: dodosCount,
118+
RequestCount: requestCount,
119+
NoProxyCheck: noProxyCheck,
120+
}
95121
}
96122

97123
func (config *Config) MergeConfigs(newConfig *Config) {
@@ -110,6 +136,9 @@ func (config *Config) MergeConfigs(newConfig *Config) {
110136
if newConfig.RequestCount != 0 {
111137
config.RequestCount = newConfig.RequestCount
112138
}
139+
if !newConfig.NoProxyCheck.IsNone() {
140+
config.NoProxyCheck = newConfig.NoProxyCheck
141+
}
113142
}
114143

115144
func (config *Config) SetDefaults() {
@@ -125,6 +154,9 @@ func (config *Config) SetDefaults() {
125154
if config.RequestCount == 0 {
126155
config.RequestCount = DefaultRequestCount
127156
}
157+
if config.NoProxyCheck.IsNone() {
158+
config.NoProxyCheck = utils.NewOption(false)
159+
}
128160
}
129161

130162
type Proxy struct {
@@ -134,16 +166,29 @@ type Proxy struct {
134166
}
135167

136168
type JSONConfig struct {
137-
Config
169+
*Config
138170
Params map[string][]string `json:"params"`
139171
Headers map[string][]string `json:"headers"`
140172
Cookies map[string][]string `json:"cookies"`
141173
Proxies []Proxy `json:"proxies" validate:"dive"`
142174
Body []string `json:"body"`
143175
}
144176

177+
func NewJSONConfig(
178+
config *Config,
179+
params map[string][]string,
180+
headers map[string][]string,
181+
cookies map[string][]string,
182+
proxies []Proxy,
183+
body []string,
184+
) *JSONConfig {
185+
return &JSONConfig{
186+
config, params, headers, cookies, proxies, body,
187+
}
188+
}
189+
145190
func (config *JSONConfig) MergeConfigs(newConfig *JSONConfig) {
146-
config.Config.MergeConfigs(&newConfig.Config)
191+
config.Config.MergeConfigs(newConfig.Config)
147192
if len(newConfig.Params) != 0 {
148193
config.Params = newConfig.Params
149194
}
@@ -162,13 +207,23 @@ func (config *JSONConfig) MergeConfigs(newConfig *JSONConfig) {
162207
}
163208

164209
type CLIConfig struct {
165-
Config
210+
*Config
166211
Yes bool `json:"yes" validate:"omitempty"`
167212
ConfigFile string `validation_name:"config-file" validate:"omitempty,filepath"`
168213
}
169214

215+
func NewCLIConfig(
216+
config *Config,
217+
yes bool,
218+
configFile string,
219+
) *CLIConfig {
220+
return &CLIConfig{
221+
config, yes, configFile,
222+
}
223+
}
224+
170225
func (config *CLIConfig) MergeConfigs(newConfig *CLIConfig) {
171-
config.Config.MergeConfigs(&newConfig.Config)
226+
config.Config.MergeConfigs(newConfig.Config)
172227
if newConfig.ConfigFile != "" {
173228
config.ConfigFile = newConfig.ConfigFile
174229
}

main.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ import (
2121

2222
func main() {
2323
validator := validation.NewValidator()
24-
conf := config.Config{}
25-
jsonConf := config.JSONConfig{}
24+
conf := config.NewConfig("", 0, 0, 0, nil)
25+
jsonConf := config.NewJSONConfig(
26+
config.NewConfig("", 0, 0, 0, nil), nil, nil, nil, nil, nil,
27+
)
2628

2729
cliConf, err := readers.CLIConfigReader()
2830
if err != nil || cliConf == nil {
@@ -51,11 +53,11 @@ func main() {
5153
),
5254
)
5355
}
54-
jsonConf = *jsonConfNew
55-
conf.MergeConfigs(&jsonConf.Config)
56+
jsonConf = jsonConfNew
57+
conf.MergeConfigs(jsonConf.Config)
5658
}
5759

58-
conf.MergeConfigs(&cliConf.Config)
60+
conf.MergeConfigs(cliConf.Config)
5961
conf.SetDefaults()
6062
if err := validator.Struct(conf); err != nil {
6163
utils.PrintErrAndExit(
@@ -81,6 +83,7 @@ func main() {
8183
Proxies: jsonConf.Proxies,
8284
Body: jsonConf.Body,
8385
Yes: cliConf.Yes,
86+
NoProxyCheck: conf.NoProxyCheck.ValueOrPanic(),
8487
}
8588
requestConf.Print()
8689
if !cliConf.Yes {

readers/cli.go

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import (
1313
func CLIConfigReader() (*config.CLIConfig, error) {
1414
var (
1515
returnNil = false
16-
cliConfig = &config.CLIConfig{}
16+
cliConfig = config.NewCLIConfig(config.NewConfig("", 0, 0, 0, nil), false, "")
1717
dodosCount uint
1818
requestCount uint
1919
timeout uint32
20+
noProxyCheck bool
2021
rootCmd = &cobra.Command{
2122
Use: "dodo [flags]",
2223
Example: ` Simple usage only with URL:
@@ -26,17 +27,7 @@ func CLIConfigReader() (*config.CLIConfig, error) {
2627
dodo -c /path/to/config/file/config.json
2728
2829
Usage with all flags:
29-
dodo -c /path/to/config/file/config.json -u https://example.com -m POST -d 10 -r 1000 -t 2000`,
30-
Short: `
31-
██████████ ███████ ██████████ ███████
32-
░░███░░░░███ ███░░░░░███ ░░███░░░░███ ███░░░░░███
33-
░███ ░░███ ███ ░░███ ░███ ░░███ ███ ░░███
34-
░███ ░███░███ ░███ ░███ ░███░███ ░███
35-
░███ ░███░███ ░███ ░███ ░███░███ ░███
36-
░███ ███ ░░███ ███ ░███ ███ ░░███ ███
37-
██████████ ░░░███████░ ██████████ ░░░███████░
38-
░░░░░░░░░░ ░░░░░░░ ░░░░░░░░░░ ░░░░░░░
39-
`,
30+
dodo -c /path/to/config/file/config.json -u https://example.com -m POST -d 10 -r 1000 -t 2000 --no-proxy-check -y`,
4031
Run: func(cmd *cobra.Command, args []string) {},
4132
SilenceErrors: true,
4233
SilenceUsage: true,
@@ -51,6 +42,7 @@ func CLIConfigReader() (*config.CLIConfig, error) {
5142
rootCmd.Flags().UintVarP(&dodosCount, "dodos-count", "d", config.DefaultDodosCount, "Number of dodos(threads)")
5243
rootCmd.Flags().UintVarP(&requestCount, "request-count", "r", config.DefaultRequestCount, "Number of total requests")
5344
rootCmd.Flags().Uint32VarP(&timeout, "timeout", "t", config.DefaultTimeout, "Timeout for each request in milliseconds")
45+
rootCmd.Flags().BoolVar(&noProxyCheck, "no-proxy-check", false, "Do not check for proxies")
5446
if err := rootCmd.Execute(); err != nil {
5547
utils.PrintErr(err)
5648
rootCmd.Println(rootCmd.UsageString())
@@ -68,6 +60,8 @@ func CLIConfigReader() (*config.CLIConfig, error) {
6860
cliConfig.RequestCount = requestCount
6961
case "timeout":
7062
cliConfig.Timeout = timeout
63+
case "no-proxy-check":
64+
cliConfig.NoProxyCheck = utils.NewOption(noProxyCheck)
7165
}
7266
})
7367
if returnNil {

readers/json.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@ import (
55
"os"
66

77
"github.com/aykhans/dodo/config"
8-
"github.com/aykhans/dodo/custom_errors"
8+
customerrors "github.com/aykhans/dodo/custom_errors"
99
)
1010

1111
func JSONConfigReader(filePath string) (*config.JSONConfig, error) {
1212
data, err := os.ReadFile(filePath)
1313
if err != nil {
1414
return nil, customerrors.OSErrorFormater(err)
1515
}
16-
jsonConf := &config.JSONConfig{}
16+
jsonConf := config.NewJSONConfig(
17+
config.NewConfig("", 0, 0, 0, nil),
18+
nil, nil, nil, nil, nil,
19+
)
1720
err = json.Unmarshal(data, &jsonConf)
1821

1922
if err != nil {

0 commit comments

Comments
 (0)