#!/usr/bin/perl -w
#-------------------------------------------------------
# HTTP Debugger
#
# Copyright (c) 1999 John Nolan. All rights reserved.
# This program is free software. You may modify and/or
# distribute it under the same terms as Perl itself.
# This copyright notice must remain attached to the file.
#
# You can run this file through either pod2man or pod2html
# to produce pretty documentation in manual or html file format
# (these utilities are part of the Perl 5 distribution).
#-------------------------------------------------------
=head1 NAME
B - A tool for debugging HTTP transactions
=head1 SYNOPSIS
httpdebug [-p port] [-t timeout]
=head1 README
This is a tool to help you debug HTTP transactions. It uses both
the HTTP server and HTTP client functionalities of the LWP bundle.
Using this script, you can easily and quickly mimic and tweak transactions
between servers and clients. You operate this program using a Web browser.
=head1 DESCRIPTION
When you launch this program from the command line, it becomes
a tiny HTTP daemon. For example, if you launch this program with
the parameter "-p 8080", then it will become a Web server
on port 8080. You can then access it using a browser at the URL
"http://host.domain.com:8080/c". The page that you will
see is a control panel for the program.
With any other URL besides "/c" (and a few other paths),
this little server will only print out a brief test page (i.e.,
test headers and a test document). From the control panel,
you can specifically adjust the test headers and the test document
that the server (this program) sends to the client (something else),
and then watch how the client responds.
All transactions are logged, and you can view these
transaction logs right from the browser, by using
the path "/l" or "/log".
You can use the debugger's HTTP client functionality to interact with
a remote web server. From the control panel, you can specify a URL,
and the debugger (as HTTP client) will send that request to a remote
Web server and save the response headers and document.
If you want, you can manually adjust the header data and
request lines that the HTTP client uses during this transaction.
After fetching a document like this, the debugger's server functionality
can immediately use this information to mimic that remote server.
In this way, you can very easily simulate the interactions between
a remote server and a remote client, by just making your little server
behave exactly like the remote server.
You can very carefully tweak the headers and document data
that you are sending and receiving. This can be useful for
locating otherwise obscure errors.
The debugger has a built-in timeout, which by default is 180 seconds.
This helps prevent you from launching the HTTP daemon and then
forgetting that it's running, which could be a security issue.
When you launch the program from the command line, use the -t option
to specify a timeout (in seconds). The program will exit
after that number of seconds of idle time.
=head1 The Log page
The debugger has a log page, where it records the data transferred
(both headers and data) during HTTP transactions. On the log page,
this is the color scheme:
Remote client: blue italics
Local server: black italics
Local client: black roman
Remote server: green roman
Headers and data are all the same color. They are separated
by two newlines, of course.
The debugger does not log transactions made when it
serves up the control panel, the log page, nor this help page.
=head1 Special URLs
Below is a list of all the URLs that are "special" for this
Web server:
Control panel: /c /con /cons /console /control
Log page: /l /log
Help page: /i /info /h /help /q
Any other URLs will result in the sending of the test page
as a response.
=head1 Do I really need this thing?
Maybe not. You can do practically all of these things
from the command line using netcat. But it's a lot
trickier that way, especially if you are not a die-hard
command-line jockey. This interface is certainly faster,
and it keeps a nice handy log of all transactions.
Plus it has pretty colors.
=head1 SCRIPT CATEGORIES
Web
CGI
=head1 PREREQUISITES
You basically need the LWP bundle and CGI.pm. If your version of
CGI.pm does not have the noDebug pragma, then consider downloading
a later version of CGI.pm from CPAN.
=head1 AUTHOR
John Nolan jpnolan@sonic.net February 1999.
=cut
#-------------------------------------------------------
use CGI qw(:standard :noDebug);
use HTTP::Daemon;
use HTTP::Status;
use HTTP::Request;
use LWP::UserAgent;
use Getopt::Std;
use Sys::Hostname;
use strict;
use vars qw( $opt_p $opt_t $Progname $nontext $menubar );
$|++;
# NOTE: Near the end of this program is a BEGIN block
# where some important variables are initialized.
# It's at the end of the program, rather than up here,
# only because it's really long.
getopts('p:t:');
#----------------------------------------------
# Setup Global variables
#
my $PORT = (defined $opt_p ? $opt_p : 0 );
my $TIMEOUT = (defined $opt_t ? $opt_t : 180 );
# NOTE: hostname() does not return the FQDN, only the hostname.
# You may want to just hard-code your hostname here, instead.
#
my $HOST = hostname();
chomp($HOST);
my $req_counter = 1;
my $res_counter = 1;
my $d = new HTTP::Daemon (LocalAddr => $HOST);
$d = new HTTP::Daemon (LocalAddr => $HOST, LocalPort => $PORT) if $PORT;
unless (defined $d) {
warn "Could not bind to port. I'm going to have to exit. Sorry.\n";
exit(-1);
}
my $url = $d->url;
my @helpinfo = ; # Read the info at end of code
my $log = ""; # Where we store transaction logs
my $delim = ('-') x 60 . "\n"; # Delimiter for displaying logs
my $agentname = "Mozilla (compatible: LWP $LWP::VERSION)";
my %res_headers; # Hash will hold response headers that we serve
my %res_content; # Hash will hold response content that we serve
my %request; # Hash will hold request data that we send
$res_headers{'current'} = ($res_headers{'HTML'} or "");
$res_content{'current'} = ($res_content{'HTML'} or "

Found

Authorization Required

This server could not verify that you
are authorized to access the document
requested. Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.