Hi Aurélien,

On Wed, Apr 18, 2018 at 09:36:14AM +0200, Aurélien Nephtali wrote:
> > My worries come from your example above which splits the "set server"
> > command and some of you comments which seem to imply that the arguments
> > are looked up in the payload part.
> 
> Well, they are looked up in the payload part but only if the command
> parser is missing its mandadory ones.
> Let's use the "set server" keywords as an example. This command does not
> usually takes a payload but it's what I wanted to add: "multi-lines for
> everyone". But maybe the real point should be to add "payload for some" ?
> Here would be valid ways of using "set server":
> 
> # set server <<
> bk/fe state ready
> # set server bk/fe state ready
> # set server bk/fe <<
> state
> ready
> # set server <<
> bk/fe
> state
> ready
> 
> The parser will first call cli_resync_args().
> What that will do is consume the payload in order to reach
> its number of mandatory arguments. Internally the list of arguments will
> become: 'set' 'server 'bk/fe' 'state' 'ready' and the payload will be
> set to NULL. Then the parser will request tokenization (through
> cli_split_args()) and do its job.

I really don't like to mix this. It makes error control very hard,
and will make it even harder to later add optional arguments to
some commands, because they could optionally be looked up in the
payload if the previous command used to support one.

If we want to make some commands support getting one of its current
arguments as payload (such as ocsp), let's do it explicitly for the
command. For example it could be said that "set ssl ocsp-response"
supports either one argument on the command line, or a payload. But
making commands concatenate arguments and start of payload seems
very wrong to me because we're mixing data of different semantics.

Look at this totally made up example below. Let's say we implement
support for payload to fill in ACLs. The following command is used
to enter a list of new keywords that you want to detect in a query
string as potentially dangerous actions on a login page :

 > add acl dangerous_words <<
 + delete
 + clear
 + kill
 + close
 + remove
 +

Then later someone proposes a patch for the ACLs to perform an atomic
load after clearing existing ones, and suggests to append the optional
keyword "clear" on the command line arguments. The command becomes :

 > add acl foo clear <<
 + blah
 + foo
 + bar
 + zoo
 +

As you can see this has no apparent effect on the first command above.
But now the script used above to load the dangerous words sends them
sorted in alphabetical order for whatever reason (eg: deduplication) :

 > add acl dangerous_words <<
 + clear
 + delete
 + kill
 + close
 + remove
 +

And suddenly this "clear" word appearing first in the payload is mistakenly
used as an extension of the command line and silently destroys previous
contents before loading the 4 remaining words.

> There is no "real" split between arguments and payload. It will be
> command parsers that will decide what is the final payload according to
> what they need.

And this is exactly what prevents commands from being extended in the
future : you know what you used to support as arguments because it was
in the code, but you don't know what users used to feed via the payload
so you have no way to avoid causing conflicts.

I could make an analogy with HTTP headers vs payload. Each one has its own
role and you never want to look up a cookie or accept-encoding in the payload
of a POST for example. But at the same time it doesn't prevent specific
applications from specifically implementing support for picking the information
they need from the payload. It just doesn't happen this way in general.

> > Please keep in mind the example I proposed regarding
> > "add map" with HTTP status codes and reasons, to be sure that once your
> > change is applied, it finally becomes possible to add "404 Not Found" as
> > a payload where only the "add map" command decides how to parse that line
> > (ie: decide that 404 is the key and the rest is the value, which implies 
> > that
> > it's *not* tokenized). If this works easily, I'm quite confident we'll be on
> > a good track.
> > 
> 
> Well, it already does that :) :
> 
> $ cat tst3 | socat /tmp/sock1 -
> 
> $ socat /tmp/sock1 -
> show map #-1
> 0x7e6ad0 test.com bk
> 0x7f5260 200 OK
> 0x7f52a0 203 Non-Authoritative Information
> 0x82e3b0 204 No Content
> 0x82e4b0 301 Moved Permanently
> 0x82e5b0 302 Found
> 0x82e6b0 303 See Other
> 0x82e7b0 400 Bad Request
> 
> $ cat tst3
> add map <<
> #-1
> 100 Continue
> 200 OK
> 203 Non-Authoritative Information
> 204 No Content
> 301 Moved Permanently
> 302 Found
> 303 See Other
> 400 Bad Request
> 
> $

Do you realize that as a *user* I don't understand how to safely and
reliably use this ? It makes me feel like I just throw a random amount
of words to the command and that it will figure by itself which ones
are arguments and which ones are data to be loaded :-/

I can possibly understand why there may be a benefit to support
argument-as-payload for *some* commands, but these ones will also be
the ones which will need to be improved to support batched actions.
Your "set server" example could be one of these. Right now (unless I'm
mistaken) we can set a single setting per command on "set server". We
could extend the command to support a list of settings at once, but it
would quickly become a mess and be limited by the number of arguments.
Alternatively we could have a "set server bk/sv at-once <<" command
via which we load one setting per *line* of payload (ie \n is really
used as a setting delimitor there), all of them for the same server.

Then the horrors below :

 > # set server <<
 > bk/fe state ready
 > # set server bk/fe state ready
 > # set server bk/fe <<
 > state
 > ready
 > # set server <<
 > bk/fe
 > state
 > ready

Could become :

   # set server bk/fe at-once <<
   + state ready
   + weight 100%
   + agent-send "GET / HTTP/1.0\r\n\r\n"
   + fqdn server3
   + addr 10.0.1.2
   + port 3000
   +

Then the command is processed atomically for all these settings. And as
you see, if you'd tokenize this as words it would become the same mess
as having them on the command line.

Hoping this helps,
Willy

Reply via email to