@@ -84,7 +84,12 @@ func ParseConfig(args []string, getenv func(string) string, stderr io.Writer) (O
8484 fs .Var (stringSliceFlag {& opts .Headers }, "H" , "Custom header (repeatable)" )
8585 fs .Var (stringSliceFlag {& opts .WorkerAddrs }, "W" , "Worker address (repeatable)" )
8686 fs .Var (stringSliceFlag {& opts .WorkerAddrs }, "w" , "Worker address alias" )
87- if err := fs .Parse (args ); err != nil {
87+ // flag.Parse stops at the first non-flag argument, so a command like
88+ // "http_bench -n 100 -m POST <url> -body '{}' -W host:port" would
89+ // silently swallow every flag after the URL (the worker then never
90+ // receives a task). Reorder positional args to the end so flags and
91+ // the positional URL can be freely mixed (README documents this style).
92+ if err := fs .Parse (reorderArgs (args )); err != nil {
8893 return Options {}, err
8994 }
9095 // Detect whether -d was explicitly set on the command line. When the
@@ -133,6 +138,44 @@ func ParseConfig(args []string, getenv func(string) string, stderr io.Writer) (O
133138 return opts , nil
134139}
135140
141+ // boolFlags lists the flags that take no value argument. reorderArgs uses it
142+ // to decide whether the token following a flag is its value or a positional
143+ // argument.
144+ var boolFlags = map [string ]bool {
145+ "disable-compression" : true ,
146+ "disable-keepalive" : true ,
147+ "insecure" : true ,
148+ "example" : true ,
149+ "h" : true ,
150+ "help" : true ,
151+ }
152+
153+ // reorderArgs moves positional (non-flag) arguments behind all flags so that
154+ // flag.Parse — which stops consuming at the first non-flag token — parses
155+ // every flag. A flag consumes the next token as its value unless it is a
156+ // boolean flag or uses the -flag=value form.
157+ func reorderArgs (args []string ) []string {
158+ var flags , positional []string
159+ for i := 0 ; i < len (args ); i ++ {
160+ a := args [i ]
161+ if len (a ) > 1 && a [0 ] == '-' {
162+ flags = append (flags , a )
163+ name := strings .TrimLeft (a , "-" )
164+ if strings .Contains (name , "=" ) || boolFlags [name ] {
165+ continue
166+ }
167+ // Value flag: consume the next token as its value.
168+ if i + 1 < len (args ) {
169+ i ++
170+ flags = append (flags , args [i ])
171+ }
172+ continue
173+ }
174+ positional = append (positional , a )
175+ }
176+ return append (flags , positional ... )
177+ }
178+
136179// stringSliceFlag implements flag.Value for repeatable string flags.
137180type stringSliceFlag struct { target * []string }
138181
0 commit comments