cannot add \r\n to string

iApp gurus

I'm working on customizing the basic http iapp to send a user agent in the http header. It looks like the
f5.app_utils:create_monitor proc doesn't let me pass such an option so I'm trying to pass the entire thing inside $monitor_send and set $monitor_dns_name and $http_version to an empty string. I'm running into 2 issues with that.

1. I removed the http_version and dns_name section and set them to empty. When I paste the following http header

GET / HTTP/1.1\r\nHost: localhost\r\nUser-Agent: F5LTM/11\r\nConnection: Close\r\n\r\n
it creates the app just fine. However the resulting http monitor is actually truncated like this :

GET / HTTP/1.1\r\nHost: localhost\r\nUser-Agent: F5LTM/11\r\nConnection: Close\r\n

in other words it appears to chomp the last 2 \r\n so the pool is marked down.

2. I'd like to have this string as a default rather than GET / but it appears the string element does not accept the \r\n.

string monitor_send default "GET / HTTP/1.1\r\nHost: localhost\r\nUser-Agent: F5LTM/11\r\nConnection: Close\r\n\r\n" required display "xlarge"


01070734:3: Configuration error:
/Common/f5.http_clientssl: line 117,61: error 4: Unexpected character at 'r'
/Common/f5.http_clientssl: line 117,68: Invalid character (:)
/Common/f5.http_clientssl: line 117,79: Invalid character (\)
/Common/f5.http_clientssl: line 117,81: Invalid character (\)
/Common/f5.http_clientssl: line 117,87: Invalid character (-)
/Common/f5.http_clientssl: line 117,93: Invalid character (:)
/Common/f5.http_clientssl: line 117,100: Invalid character (/)
/Common/f5.http_clientssl: line 117,101: Invalid character (1)
/Common/f5.http_clientssl: line 117,102: Invalid character (1)
/Common/f5.http_clientssl: line 117,103: Invalid character (\)
/Common/f5.http_clientssl: line 117,105: Invalid character (\)
/Common/f5.http_clientssl: line 117,117: Invalid character (:)
/Common/f5.http_clientssl: line 117,124: Invalid character (\)
/Common/f5.http_clientssl: line 117,126: Invalid character (\)
/Common/f5.http_clientssl: line 117,128: Invalid character (\)

I tried single quoting but it causes an error :

string monitor_send default 'GET / HTTP/1.1\r\nHost: localhost\r\nUser-Agent: F5LTM/11\r\nConnection: Close\r\n\r\n' required display "xlarge"

01070734:3: Configuration error:
/Common/f5.http_clientssl: line 117,45: Invalid character (')
/Common/f5.http_clientssl: line 117,50: Invalid character (/)
/Common/f5.http_clientssl: line 117,56: Invalid character (/)
/Common/f5.http_clientssl: line 117,57: Invalid character (1)
/Common/f5.http_clientssl: line 117,59: Invalid character (1)
/Common/f5.http_clientssl: line 117,60: Invalid character (\)
/Common/f5.http_clientssl: line 117,62: Invalid character (\)
/Common/f5.http_clientssl: line 117,68: Invalid character (:)
/Common/f5.http_clientssl: line 117,79: Invalid character (\)
/Common/f5.http_clientssl: line 117,81: Invalid character (\)
/Common/f5.http_clientssl: line 117,87: Invalid character (-)
/Common/f5.http_clientssl: line 117,93: Invalid character (:)
/Common/f5.http_clientssl: line 117,100: Invalid character (/)
/Common/f5.http_clientssl: line 117,101: Invalid character (1)
/Common/f5.http_clientssl: line 117,102: Invalid character (1)

I CAN quote the \ and it does let me save it this way :

string monitor_send default "GET / HTTP/1.1\\r\\nHost: localhost\\r\\nUser-Agent: F5LTM/11\\r\\nConnection: Close\\r\\n\\r\\n" required display "xlarge"

However, now the presentation layer shows this string with \\ included although it does remove them when it actually creates the monitor but it truncates the last 2 chars again.

I suppose I'm hitting a string lenght limitation ? Then again I can manually create this http header in the gui just fine.

Any insight would be appreciated.

btw if anyone cares how I'm doing this I just removed the dns_name and http_version sections from the presentation and changed the implementation a bit since I seem to be forced to pass these 2 options empty or not.

set monitor_recv \"$::server_pools__monitor_recv\"
            set monitor_send \"$::server_pools__monitor_send\"
            set http_version $::EMPTY_STRING
            set monitor_dns_name $::EMPTY_STRING
            set monitor_type http

7 Answer(s):

just wanted to mention I know I could create the monitor first and then point to it during the presentation but I'm trying to build a fully self-sufficient template.

There is a drop-down labeled with "What HTTP version do your HTTP servers expect clients to use?" which has two options "Version 1.0" and "Version 1.1". It defaults to version 1.0. For what you are trying to do, you need to switch it to "Version 1.1" The reason why is the HTTP version 1.0 requests have just a single \r\n and version 1.1 requests have two of them. You are sending an HTTP version 1.1 send string, but the HTTP version is still set to version 1.0. This is causing you problems. If you switch it to version 1.1, it should solve the truncation problem. You can change the default on that control to version 1.1, or even remove that control and hard-code version 1.1.

I agree that its frustrating that you get the double backslashes in the presentation. I don't have a solution for that. Its a limitation of the display widget. However, I do have a suggestion that might make it work better. Instead of presenting the entire send string with the user-agent header there, you could leave that default as "GET /" and add a new string or choice input field that just asks for the user-agent to specify. Then you could build the full send string from the URI and this input. It might make for a more readable presentation.
There appears to be a bug in the create_monitor proc within f5.app_utils where when using HTTP/1.0, one of the CRLFs is stripped incorrectly. It seems that when you removed the inputs for the http version and call that procedure with a blank value for the version (but still had HTTP/1.1 in the send string) that you're hitting this bug even though you're not explicitly specifying HTTP/1.0.

Workarounds for this:

1. call that proc but specify "Version 1.1" for the http_version parameter
2. don't use that proc at all and just call tmsh::create directly to instantiate the monitor
3. make a copy of the f5.app_utils cli script (from tmsh: cp cli script f5.app_utils stucky101.app_utils) and change the behavior of the create_monitor procedure to do the right thing (from tmsh: edit cli script stuck101.app_utils), and then call that instead of the one in f5.app_utils
4. as you already said, create the monitor by hand outside of the iApp and then reference it within

Thanks for bringing this to our attention.
Thanks for your input. I changed the code as follows:

if { $::server_pools__create_new_monitor == $::CREATE_NEW_MONITOR_OPTION} {
set monitor_interval $::server_pools__monitor_interval
set monitor_recv \"$::server_pools__monitor_recv\"
set monitor_send \"$::server_pools__monitor_send\"
set http_version "\"Version 1.1\""
set monitor_dns_name $::EMPTY_STRING
set monitor_type http

set monitor_name [tmsh::run_proc f5.app_utils:create_monitor \
$tmsh::app_name $monitor_type $monitor_interval "$monitor_send" \
"$monitor_recv" $http_version $monitor_dns_name]

but the resulting http header is still truncated as before.

Maybe I'm misinterpreting what iApps are for ? From what I've seen so far one can use this one of 2 ways.

A. Create single objects like monitor, persistence profile, http profile etc... before - then just tie them all together via the template.
The issues I have with that are :
1. People still have to do a lot of manual work
2. Objects won't automatically be named causing messy naming (As we all know everyone has their own idea of what something should be called)
3. When I remove an iApp it leaves behind all the objects that werent created within the template.


B. Put everything inside the template and only ever change things via the "Reconfigure" button. This seems clean and perfect to me except, we are far from that at this time. The more I think about it the more I wonder if this is even feasable. Looking at an http profile alone there are 20 options. Is the idea to eventually include all that into the template ? It'd grow to a possibly unmanageable size wouldn't it ?

I can't help feeling you guys are more leaning towards solution A. In this case I wouldn't have to bother creating http monitors within the template at all. One thing I'm confused about is this. After creating an iApp I'm told I cannot change some objects since they are tied to the app and "strict updates" is enabled. Yet other changes can be made without error. I don't see a system right now.
This sends mixed signals. On one side I think I'm not supposed to make changes to objects once tied to an iApp - on the other hand you guys seem to suggest to do just that since the template is missing a lot of stuff.
What if I need to make such a change (lets say to an http profile) at a later time for legitimate reasons ? There is no way to use the "Reconfigure" option so I'd have to do it in the object directly. Wouldn't that break strick checking ?

Maybe someone can give me some conceptual pointers.

On further review, I see that there is definitely a but in the create_monitor procedure. It works for many cases, but not this one. I am including a new version of this proc that you can add to your template and call instead. You won't have to sent the version string to this one for this usage.

proc create_monitor_2 { name_prefix
} {
set monitor_name "${name_prefix}_${monitor_type}_monitor"

set http10_header "HTTP/1.0"
set http11_header "HTTP/1.1"
set monitor_ending "\\r\\n"

# make sure that the send string is formatted correctly,
# even if we have to edit it
# convert converted \r and \n back to two char \r\n
set temp_string ""
regsub -all {\r} $monitor_send "\\r" temp_string
set monitor_send $temp_string
regsub -all {\n} $monitor_send "\\n" temp_string
set monitor_send $temp_string

set monitor_timeout [ expr { [ expr {$monitor_interval * 3} ] + 1 } ]
set monitor_ending_length [string length $monitor_ending]
set send_length [string length $monitor_send]
set send_length_minus_end [ expr {$send_length - $monitor_ending_length} ]

# clear off real \r\n
while { [string last $monitor_ending $monitor_send] == $send_length_minus_end } {
set send_length_minus_end [expr { $send_length_minus_end - 1 }]
set monitor_send [string range $monitor_send 0 $send_length_minus_end]

set send_length [string length $monitor_send]
set send_length_minus_end [ expr {$send_length - $monitor_ending_length} ]

if { [string first $http11_header $monitor_send] == -1 } {
if { $http_version == "Version 1.1" || $http_version == "version_1_1" } {
append monitor_send " HTTP/1.1\\r\\nHost: "
append monitor_send $dns_name
append monitor_send "\\r\\nConnection: Close"

append monitor_send $monitor_ending
append monitor_send $monitor_ending

do_tmsh_create "/ ltm monitor $monitor_type" "$monitor_name \
defaults-from $monitor_type \
interval $monitor_interval \
timeout $monitor_timeout \
send \"$monitor_send\" \
recv \"$monitor_recv\" \
destination *:*"

return $monitor_name
Let us know if Mitra's suggestion didn't get you up and running. It might be that you would be best-served by bypassing the convenience proc and just issuing the tmsh::create call for the monitor directly.

I had the exact same problem and I found this nice little workaround:

string monquery default tcl { set results {GET / HTTP/1.1\r\nHost: localhost\r\nUser-Agent: F5LTM/11\r\nConnection: Close\r\n\r\n} return $results } required display “xlarge"

Your answer: