iRule [string range...] not chunking data properly
I have an irule (much of which I found here) that is to gather some much needed troubleshooting data I need in regards to the headers and payload I have coming in. The payload is obvisouly too large for a single log line so this was supposed to chunk it into manageable bytes.
I had to make some modifications to the original irule which did not work, but now it is working, sort of. It logs the first 900 bytes as it should, then something happens and skips a bunch, and then logs the final bytes of data.
I can't understand why it's not grabbing either the proper amount of data or failing to output this second chunk of missing data before making its final loop.
iRule is here:
when RULE_INIT {
# Log debug to /var/log/ltm? 1=yes, 0=no
set static::payload_dbg 1
# Limit payload collection to 5Mb
set static::max_collect_len 5368709
# Max characters to log locally (must be less than 1024 bytes)
# https://clouddocs.f5.com/api/irules/log.html
set static::max_chars 900
set static::min_chars 0
}
when HTTP_REQUEST {
# Only collect POST request payloads
if {[HTTP::method] equals "POST"}{
if {$static::payload_dbg}{log local0. "POST request"}
# Get the content length so we can request the data to be processed in the HTTP_REQUEST_DATA event.
if {[HTTP::header exists "Content-Length"]}{
set content_length [HTTP::header "Content-Length"]
} else {
set content_length 0
}
# content_length of 0 indicates chunked data (of unknown size)
if {$content_length > 0 && $content_length < $static::max_collect_len}{
set collect_length $content_length
} else {
set collect_length $static::max_collect_len
}
if {$static::payload_dbg}{log local0. "Content-Length: $content_length, Collect length: $collect_length"}
foreach aHeader [HTTP::header names] {
log local0. "HTTP Request Headers: $aHeader: [HTTP::header value $aHeader]"
}
#set payload [HTTP::collect $collect_length]
HTTP::collect $collect_length
}
}
when HTTP_REQUEST_DATA {
# Log the bytes collected
if {$static::payload_dbg}{log local0. "Collected [HTTP::payload length] bytes"}
# Log the payload locally
if {[HTTP::payload length] < $static::max_chars}{
log local0. "Payload=[HTTP::payload]"
} else {
# Initialize variables
set remaining [HTTP::payload]
set position 0
set count 1
set bytes_logged 0
# Loop through and log each chunk of the payload
while {[string length $remaining] > $static::min_chars}{
#chunk = 899
set chunk [expr {$position + $static::max_chars -1}]
log local0. "Chunk: $chunk"
log local0. "Position start: $position"
# Get the current chunk to log (subtract 1 from the end as string range is 0 indexed)
set current [string range $remaining $position $chunk]
log local0. "chunk $count=$current"
log local0. "Current chunks bytes: [string length $current]"
# Add the length of the current chunk to the position for the next chunk
incr position [string length $current]
# Get the next chunk to log
set remaining [string range $remaining $position end]
incr count
incr bytes_logged $position
log local0. "remaining bytes=[string length $remaining], \$position=$position, \$count=$count, \$bytes_logged=$bytes_logged"
}
if {[string length $remaining]}{
log local0. "chunk $count=$current"
incr bytes_logged [string length $remaining]
}
log local0. "Logged $count chunks for a total of $bytes_logged bytes"
}
}
when HTTP_RESPONSE {
foreach aHeader [HTTP::header names] {
log local0. "HTTP Request Headers: $aHeader: [HTTP::header value $aHeader]"
}
}
The image below shows what I'm talking about - it even says "Oh I found 3 chunks", but I'm only being presented 2.
I added some logging around the position, chunk value (aka end position), and bytes logged to help illustrate that it's clearly skipping over something.
Any help would be appreciated!
Thanks
In fact I have just grabbed this from an iRule i recently wrote. Almost the same, with fixed values. Note the end is 99 but the increment is 100. As you say, string range is zero-indexed
for {set start 0; set end 99} {$start < [HTTP::payload length]} {incr start 100;incr end 100} { log local0.debug "[string range [HTTP::payload] $start $end ]" }