blob: 7dcf39a5fb06013f297743e95c9a7bdde4757dd5 [file] [log] [blame]
#!/usr/bin/env perl
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Script to decode via header
#
# @File traffic_via.pl
# @Author Meera Mosale Nataraja
#
# Usage: Use it in 2 ways
# 1. Pass Via Header with -s option \n";
# traffic_via [-s viaheader]";
# or
# 2. Pipe curl output
# curl -v -H "X-Debug: Via" http://ats_server:port 2>&1| ./traffic_via.pl
#
use strict;
use warnings;
use Data::Dumper qw(Dumper);
use Getopt::Long;
my $via_header;
my $help;
#Proxy request header flags and titles
my @proxy_header_array = (
{
"Request headers received from client:",
{
'I' => "If Modified Since (IMS)",
'C' => "cookie",
'E' => "error in request",
'S' => "simple request (not conditional)",
'N' => "no-cache",
' ' => "unknown?",
},
},
{
"Result of Traffic Server cache lookup for URL:",
{
'A' => "in cache, not acceptable (a cache \"MISS\")",
'H' => "in cache, fresh (a cache \"HIT\")",
'S' => "in cache, stale (a cache \"MISS\")",
'R' => "in cache, fresh Ram hit (a cache \"HIT\")",
'M' => "miss (a cache \"MISS\")",
' ' => "unknown?",
},
},
{
"Response information received from origin server:",
{
'E' => "error in response",
' ' => "no server connection needed",
'S' => "served",
'N'=> "not-modified",
}
},
{
"Result of document write-to-cache:",
{
'U' => "updated old cache copy",
'D' => "cached copy deleted",
'W' => "written into cache (new copy)",
' ' => "no cache write performed",
},
},
{
"Proxy operation result:",
{
'R' => "origin server revalidated",
' ' => "unknown?",
'S' => "served",
'N' => "not-modified",
},
},
{
"Error codes (if any):",
{
'A' => "authorization failure",
'H' => "header syntax unacceptable",
'C' => "connection to server failed",
'T' => "connection timed out",
'S' => "server related error",
'D' => "dns failure",
'N' => "no error",
'F' => "request forbidden",
},
},
{
"Tunnel info:",
{
' ' => "no tunneling",
'U' => "tunneling because of url (url suggests dynamic content)",
'M' => "tunneling due to a method (e.g. CONNECT)",
'O' => "tunneling because cache is turned off",
'F' => "tunneling due to a header field (such as presence of If-Range header)",
},
},
{
"Cache type:",
{
'I' => "icp",
' ' => "cache miss or no cache lookup",
'C' => "cache",
},
},
{
"Cache lookup result:",
{
' ' => "no cache lookup",
'S' => "cache hit, but expired",
'U' => "cache hit, but client forces revalidate (e.g. Pragma: no-cache)",
'D' => "cache hit, but method forces revalidated (e.g. ftp, not anonymous)",
'I' => "conditional miss (client sent conditional, fresh in cache, returned 412)",
'H' => "cache hit",
'M' => "cache miss (url not in cache)",
'C' => "cache hit, but config forces revalidate",
'N' => "conditional hit (client sent conditional, doc fresh in cache, returned 304)",
},
},
{
"ICP status:",
{
' ' => "no icp",
'S' => "connection opened successfully",
'F' => "connection open failed",
},
},
{
"Parent proxy connection status:",
{
' ' => "no parent proxy",
'S' => "connection opened successfully",
'F' => "connection open failed",
},
},
{
"Origin server connection status:",
{
' ' => "no server connection",
'S' => "connection opened successfully",
'F' => "connection open failed",
},
},
);
##Print script usage
sub usage
{
print "\nPass Via Header with -s option \n";
print "Usage: traffic_via [-s viaheader]";
print "\n or \n";
print "\nPipe curl command output to this program";
print "\nEg: curl xxxx | traffic_via\n";
print "\n-h for help\n";
exit;
}
if (@ARGV == 0) {
#if passed through standard input
my @userinput = <STDIN>;
my $via_string;
for my $element (@userinput) {
#Pattern matching for Via
if ($element =~ /Via:(.*)\[(.*)\]/) {
#Search and grep via header
$via_string = $2;
chomp($via_string);
print "Via Header is [$via_string]";
decode_via_header($via_string);
}
}
} else {
usage() if (!GetOptions('s=s' => \$via_header,
'help|?' => \$help) or
defined $help);
if (defined $via_header) {
#if passed through commandline dashed argument
print "Via Header is [$via_header]";
decode_via_header($via_header);
}
}
#Subroutine to decode via header
sub decode_via_header {
my($header) = @_;
my $hdrLength;
my $newHeader;
#Check via header syntax
if ($header =~ /([a-zA-Z: ]+)/) {
#Get via header length
$hdrLength = length($header);
# Valid Via header length is 24 or 6.
# When Via header length is 24, it will have both proxy request header result and operational results.
if ($hdrLength == 24) {
#Split via header: proxy result and operational result
$newHeader = join('', split(':', $header));
} elsif ($hdrLength == 6) {
$newHeader = $header;
} elsif ($hdrLength == 5) {
# When Via header length is 5, it might be missing last field. Fill it and decode header.
my $newHeader = "$header"." ";
} else {
# Invalid header size, come out.
print "\nInvalid VIA header. VIA header length should be 6 or 24 characters\n";
return;
}
convert_header_to_array($newHeader);
}
}
sub convert_header_to_array {
my ($viaHeader) = @_;
my @ResultArray;
#Convert string header into character array
while ($viaHeader =~ /(.)/g) {
#Only capital letters indicate flags
if ($1 !~ m/[a-z]+/) {
push(@ResultArray, $1);
}
}
print "\nVia Header details: \n";
for (my $arrayIndex=0; $arrayIndex < scalar(@ResultArray); $arrayIndex++ ) {
get_via_header_flags(\@proxy_header_array, $arrayIndex, $ResultArray[$arrayIndex]);
}
}
#Get values from header arrays
sub get_via_header_flags {
my ($arrayName, $inputIndex, $flag) = @_;
my %flagValues;
my @flagKeys;
my %flags;
my @keys;
my @array = @$arrayName;
%flagValues = %{$array[$inputIndex]};
@flagKeys = keys (%flagValues);
foreach my $keyEntry ( @flagKeys ) {
printf ("%-55s", $keyEntry);
%flags = %{$flagValues{$keyEntry}};
@keys = keys (%flags);
foreach my $key ( @keys ) {
if ($key =~ /$flag/) {
#print $flags{$key};
printf("%s",$flags{$key});
print "\n";
}
}
}
}