blob: a7bfaaa534bb93e656b8e56d60cf39b522a9078a [file] [log] [blame]
#!/usr/bin/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.
use strict;
use warnings;
use Getopt::Long;
use Data::Dumper;
use Net::hostent;
use Socket;
use LWP::UserAgent;
use Digest::SHA1;
my $verbose = 0;
#----------------------------------------------------------------------------
sub usage()
{
print STDERR "USAGE: compare_hosts.pl --verbose level --host1 testing_host --host2 valid_host --file url_file\n\n";
print STDERR "\t--host1 The host running the newest version\n";
print STDERR "\t--host2 The host running the older version\n";
print STDERR "\t--file A file that contains a list of URLs\n";
print STDERR "\t--verbose verbose level 1-3, 1 is the least verbose\n\n";
print STDERR "Example:\n";
print STDERR "\tcompare_hosts.pl --host1 new_ats --host2 old_ats --file top_1000_urls\n";
exit 1;
}
#----------------------------------------------------------------------------
sub compareHeaderNames($$)
{
my ($response1, $response2) = @_;
my @names1 = $response1->header_field_names;
my @names2 = $response2->header_field_names;
my %hash2;
$hash2{$_} = 1 for (@names2);
my %hash1;
$hash1{$_} = 1 for (@names1);
my $return_val = 0; # header names match
foreach my $name (@names1) {
if (!defined $hash2{$name}) {
print "\t\t- $name header not found on host2\n" if $verbose >= 2;
$return_val = 1;
}
}
foreach my $name (@names2) {
if (!defined $hash1{$name}) {
print "\t\t- $name header not found on host1\n" if $verbose >= 2;
$return_val = 1;
}
}
return $return_val;
}
#----------------------------------------------------------------------------
sub compareHeaderValues($$)
{
my ($response1, $response2) = @_;
my @test_headers =
qw(ETag Cache-Control Connection Accept-Ranges Server Content-Type Access-Control-Allow-Methods Access-Control-Allow-Origin Strict-Transport-Security);
my $return_val = 0; # header value match
if ($verbose >= 3) {
foreach my $field ($response1->header_field_names) {
print "\t\t\t~ " . $field . ": " . $response1->header($field) . "\n";
}
print "\t\tHost2: \n";
foreach my $field ($response2->header_field_names) {
print "\t\t\t~ " . $field . ": " . $response2->header($field) . "\n";
}
}
# Test specific headers that are defined above
foreach my $field (@test_headers) {
my $value1 = $response1->header($field);
my $value2 = $response2->header($field);
if (defined $value1 && defined $value2) {
if ($value1 ne $value2) {
print "\t\t- $field: $value1 ne $value2\n" if $verbose;
print "\t\t\t - Via host1: " . $response1->header('Via') . " host2: " . $response2->header('Via') . "\n"
if $verbose;
print "\t\t\t - Last-Modified host1: "
. $response1->header('Last-Modified')
. " host2: "
. $response2->header('Last-Modified') . "\n"
if $verbose;
if (defined $response2->header('Content-Encoding')) {
print "\t\t\t - Content-Encoding host1: "
. $response1->header('Content-Encoding')
. " host2: "
. $response2->header('Content-Encoding') . "\n";
} else {
print "\t\t\t - Content-Encoding host1: " . $response1->header('Content-Encoding') . " host2: ''\n";
}
$return_val = 1;
} else {
print "\t\t- $field: $value1 eq $value2\n" if $verbose >= 2;
}
}
}
return $return_val;
}
#----------------------------------------------------------------------------
{
my %stats;
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = '0';
my ($host1, $host2, $file);
GetOptions(
"host1=s" => \$host1,
"host2=s" => \$host2,
"file=s" => \$file,
"verbose=f" => \$verbose
) || die $!;
usage() if (!defined $host1 || !defined $host2 || !defined $file);
my $count = 0;
my $status_error = 0;
my $sha_error = 0;
my $header_names_mismatch = 0;
my $header_values_mismatch = 0;
my $host1_addr = inet_ntoa(inet_aton($host1));
my $host2_addr = inet_ntoa(inet_aton($host2));
print "Testing with host1: $host1 ($host1_addr) - host2: $host2 ($host2_addr)\n";
print '-' x 78, "\n";
open(FILE, $file) || die $!;
# Create a user agent object
my $ua1 = LWP::UserAgent->new(keep_alive => 100);
$ua1->agent("MyApp/0.1 ");
# Create a user agent object
my $ua2 = LWP::UserAgent->new(keep_alive => 100);
$ua2->agent("MyApp/0.1 ");
while (my $url = <FILE>) {
next if ($url =~ m|hc.l.yimg.com|);
chomp $url;
my $exit = 0;
if ($url =~ m|(https?)://([^/]+)(.+)|) {
my $scheme = $1;
my $host = $2;
my $path = $3;
$count++;
print "Test $count - URL: $url\n";
my $port = 80;
$port = 443 if $scheme eq 'https';
my $request1 = HTTP::Request->new(GET => "${scheme}://${host1_addr}${path}");
$request1->header('Host' => $host);
my $response1 = $ua1->request($request1);
my $request2 = HTTP::Request->new(GET => "${scheme}://${host2_addr}${path}");
$request2->header('Host' => $host);
$request2->header('Accept-Encoding' => 'deflate');
my $response2 = $ua2->request($request2);
print "\tStatus code for host1: " . $response1->code . " - host2: " . $response2->code . "\n" if $verbose;
my $sha1 = Digest::SHA1->new;
$sha1->add($response1->content);
my $digest1 = $sha1->hexdigest;
open(FILE1, "> /tmp/tmp1");
open(FILE2, "> /tmp/tmp2");
print FILE1 $response1->content;
print FILE2 $response2->content;
close FILE1;
close FILE2;
#print $response1->content, "\n"; # for internal debugging
#print $response2->content, "\n"; # for internal debugging
my $sha2 = Digest::SHA1->new;
$sha2->add($response2->content);
my $digest2 = $sha2->hexdigest;
print "\tSHA hash for host1: $digest1 - host2: $digest2\n" if $verbose;
# Build up stats
if ($response1->status_line eq $response2->status_line) {
# Do the hashes
if ($digest1 eq $digest2) {
$stats{stat_line_match}->{$response1->code}->{sha_match}++;
print "\tResponse code: " . $response1->code . " - Status lines and SHA1 of response bodies match\n";
} else {
$stats{stat_line_match}->{$response1->code}->{sha_nomatch}++;
print "\tResponse code: " . $response1->code . " - Status lines match SHA1 doesn't match\n";
$sha_error++;
#$exit = 1 if $response1->code == 200; # for internal debugging
}
# Compare the header field names
if (compareHeaderNames($response1, $response2) == 0) {
$stats{stat_line_match}->{$response1->code}->{field_names_match}++;
} else {
$stats{stat_line_match}->{$response1->code}->{field_names_nomatch}++;
$header_names_mismatch++;
}
# Compare the values of the header fields
if (compareHeaderValues($response1, $response2) == 0) {
$stats{stat_line_match}->{$response1->code}->{field_values_match}++;
} else {
$stats{stat_line_match}->{$response1->code}->{field_values_nomatch}++;
$header_values_mismatch++;
}
} else {
$status_error++;
$stats{stat_line_nomatch}++;
print "\tERROR: status lines don't match\n";
}
last if $exit;
}
}
print '-' x 78, "\n";
print "SUMMARY:\n";
print "URLs tested: $count\n";
print "Status line mismatches: $status_error\n";
print "SHA1 mismatches: $sha_error\n";
print "Responses with header names mismatches: $header_names_mismatch\n";
print "Responses with header values mismatches: $header_values_mismatch\n";
print Dumper \%stats if $verbose;
}