[asterisk-users] How to escape the & in BackGround
asterisk at phreaknet.org
asterisk at phreaknet.org
Thu Jan 27 16:52:54 CST 2022
On 1/27/2022 3:58 PM, Antony Stone wrote:
> On Thursday 27 January 2022 at 21:31:35, Kingsley Tart wrote:
>> Does asterisk follow HTTP redirects? If so can you use something like
>> tinyurl.com to produce an alternative URL?
> I'm (pretty) sure that that would work.
>
> The other similar idea I had was to use a reverse proxy server to accept an
> Asterisk-compatible URL and convert it into whatever the outisde world
> requires.
Or alternately, download the file, rename it, and then use it. I do this
in some cases with MP3s that MP3Player() doesn't play but Playback()
will, or if files need to be processed before they can be played.
>> Or, base64 encode the URL, and then set a variable with
>> Set(url=${BASE64_DECODE(${encodedURL})) ?
> No, doesn't work - I tried several things yesterday to see if I could get this
> to work, and you don't even need to use Base64 en/de-coding - you can set an
> Asterisk variable to the URL including the &, and then pass that to the
> Background() command, and it fails.
> I tried it pointing to a web server I run, so I can see the requests which are
> sent, and a ? gets through, but a & doesn't. Converting it to %26 simply
> sends that through as-is, which fails at the web server end.
>
> So, I think this is a bug/feature-fail in Asterisk, which can't be worked
> around.
I think some helpful context is required as to the way text parsing and
applications work in Asterisk, as there seems to be a lack of
understanding at how the dialplan parses things.
1. Doing fancy things with variables and encoding is not going to work.
Asterisk works differently from other languages and this can be hard to
understand from a different background, where stronger notions of
strings and variables exist. When an application call is made, the PBX
core does variable substitution on the data contents (this also includes
function calls). Let's go through two examples:
same => n,Background(${BASE64_DECODE(wsghosrghodrhgo)})
The BASE64_DECODE function is evaluated before Background() even sees
any of the contents of what was there.
same => n,Background(${myvar})
Likewise, the myvar variable is evaluated by the variable substituter
before Background() itself is invoked.
Background has *nothing* to do with variables or function calls -
absolutely nothing. No matter what you do, this is what Background will
see - after all function calls and variables have been resolved:
same => n,Background(https://example.com/myurl?query=something)
This is not like a typical programming language, where you pass a
"variable" into a "function" (application), like Background, which then
"evaluates" it. Applications generally don't individually load and parse
variables (though some functions do, and there are a few exceptions for
applications, but these do extra work to do that). All they see is the
end-result of evaluated data. Generally, this is desirable behavior; we
wouldn't want each application itself to be individually responsible for
evaluating functions and variables passed into it. Background doesn't
have any fancy logic that will resolve any variables or functions. This
is all done by the PBX core *before* the application is invoked.
If that didn't make sense, this might be more clear:
same => n,GotoIf($[${somevar}=${somevar2}]&$["1"="2"|"3"="4"]]?true:false)
GotoIf never sees any of that. What to GotoIf sees is basically this:
GotoIf(1?true:false) or GotoIf(0?true:false)
Another way to think of it is like macros in C. All of your #define's
don't exist in the final compiled program; those all get replaced by the
specified values. Likewise, dialplan applications never see your
variables. They just see the data after all those things are resolved.
In this case, if you think of every dialplan call as a compilation, the
variable substituter (preprocessor) converts everything down to raw data
before the action actually starts.
That brings me to my next point:
2. Background, as do many applications in Asterisk, uses strsep on the &
delimeter to delimit files for playback. You can look at the code
yourself here:
https://github.com/asterisk/asterisk/blob/master/main/pbx_builtins.c#L1237
strsep does not handle escaping. It is a very simple C function. There
is *nothing* you can do that will make it work - might as well stop
wasting time trying. strsep will simply cut on the delimeter. There is
nothing more, nothing less.
There are only two solutions to your problem here:
1) Whatever you pass *into* Background cannot have an & unless it's a
delimeter. Trying to "hide" the & using variables, functions, etc. won't
work, because it'll just appear in the end after those are all resolved.
The actual file needs to be a URL without an & or a renamed file on
disk. In either case, the dialplan never sees the &. That's what matters.
2) The code for Background, and any other applications, would need to
modified to use a parsing function that supports escaping. There are
places in Asterisk where this is done, but the audio-related
applications aren't among them. It's not hard, but somebody would need
to make the changes to do this. That might also have other unanticipated
side effects.
Personally, I think you are better off going with option 1, either
proxying or downloading the file as suggested. Just my two cents.
NA
More information about the asterisk-users
mailing list