[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