#!/usr/bin/perl -w # Copyright 2004-2006 Corey Goldberg (corey@goldb.org) # # This file is part of WebInject. # # WebInject is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # WebInject is distributed in the hope that it will be useful, # but without any warranty; without even the implied warranty of # merchantability or fitness for a particular purpose. See the # GNU General Public License for more details. use Tk; use Tk::Stderr; use Tk::ROText; use Tk::Compound; use Tk::ProgressBar::Mac; use Tk::NoteBook; use Tk::PNG; $| = 1; #don't buffer output to STDOUT $mw = MainWindow->new( -title => 'WebInject - HTTP Test Tool (version 1.41)', -bg => '#666699', -takefocus => '1', #start on top ); $mw->geometry("750x650+0+0"); #size and screen placement $mw->InitStderr; #redirect all STDERR to a window $mw->raise; #put application in front at startup $mw->bind('' => \&engine); #F5 key makes it run if (-e "icon.gif") { #if icon graphic exists, use it $mw->update(); $icon = $mw->Photo(-file => 'icon.gif'); $mw->iconimage($icon); } if (-e "logo.gif") { #if logo graphic exists, use it $mw->Photo('logogif', -file => "logo.gif"); $mw->Label( -image => 'logogif', -bg => '#666699', )->place(qw/-x 305 -y 12/); $mw->update(); } $menubar = $mw->Frame(qw/-relief flat -borderwidth 2/); $menubar->place(qw/-x 0 -y 0/); $menubar->configure(-background => '#666699'); #menu outline $filemenu = $menubar->Menubutton( -text => 'File', -foreground => 'white', -background => '#666699', -activebackground => '#666699', -activeforeground => 'black', -tearoff => '0', )->pack(qw/-side left/); $filemenu->command( -label => 'Restart', -background => '#666699', -activebackground => '#EFEFEF', -foreground => 'white', -activeforeground => 'black', -command => sub{gui_restart();} ); $filemenu->command( -label => 'Exit', -background => '#666699', -activebackground => '#EFEFEF', -foreground => 'white', -activeforeground => 'black', -command => sub{exit;} ); $viewmenu = $menubar->Menubutton( -text => 'View', -foreground => 'white', -background => '#666699', -activebackground => '#666699', -activeforeground => 'black', -tearoff => '0', )->pack(qw/-side left/); $viewmenu->command( -label => 'config.xml', -background => '#666699', -activebackground => '#EFEFEF', -foreground => 'white', -activeforeground => 'black', -command => sub{viewconfig();} ); $aboutmenu = $menubar->Menubutton( -text => 'About', -foreground => 'white', -background => '#666699', -activebackground => '#666699', -activeforeground => 'black', -tearoff => '0', )->pack(qw/-side left/); $aboutmenu->command( -label => 'About WebInject', -background => '#666699', -activebackground => '#EFEFEF', -foreground => 'white', -activeforeground => 'black', -command => sub{about();} ); $mw->Label( -text => 'Engine Status:', -bg => '#666699', -fg => '#FFFFFF', )->place(qw/-x 12 -y 100/); $mw->update(); $out_window = $mw->Scrolled(ROText, #engine status window -scrollbars => 'e', -background => '#EFEFEF', -width => '103', -height => '7', )->place(qw/-x 12 -y 118/); $mw->update(); $tabs = $mw->NoteBook( -backpagecolor => '#666699', -background => '#EFEFEF', #color for active tab -foreground => 'black', #text color for active tab -inactivebackground => '#BFBFBF', #color for inactive tabs )->place(qw/-x 12 -y 240/); #outer notebook object $status_tab = $tabs->add('statustab', -label => 'Status'); $mw->update(); $statustab_canvas = $status_tab->Canvas( -width => '719', -height => '365', -highlightcolor => '#CCCCCC', -background => '#EFEFEF', )->pack(); $mw->update(); #canvas to fill tab (to place widgets into) $statustab_buttoncanvas = $statustab_canvas->Canvas( -width => '700', -height => '24', -background => '#666699', )->place(qw/-x 10 -y 334/); $mw->update(); #canvas to place buttons into $minimalcheckbx = 'minimal_off'; #give it a default value $statustab_buttoncanvas->Label( -text => 'Minimal Output', -bg => '#666699', -fg => 'white', )->place(qw/-x 49 -y 4/); $mw->update(); $statustab_buttoncanvas->Checkbutton( -text => '', #using a text widget instead -onvalue => 'minimal_on', -offvalue => 'minimal_off', -variable => \$minimalcheckbx, -background => '#666699', -activebackground => '#666699', -highlightbackground => '#666699', )->place(qw/-x 20 -y 2/); $mw->update(); $timercheckbx = 'timer_off'; #give it a default value $statustab_buttoncanvas->Label( -text => 'Response Timer Output', -bg => '#666699', -fg => 'white', )->place(qw/-x 199 -y 4/); $mw->update(); $statustab_buttoncanvas->Checkbutton( -text => '', #using a text widget instead -onvalue => 'timer_on', -offvalue => 'timer_off', -variable => \$timercheckbx, -background => '#666699', -activebackground => '#666699', -highlightbackground => '#666699', )->place(qw/-x 170 -y 2/); $mw->update(); $status_window = $statustab_canvas->Scrolled(ROText, #test case status monitor window -scrollbars => 'e', -background => '#EFEFEF', -width => '102', -height => '23', )->place(qw/-x 0 -y 0/); $mw->update(); $status_window->tagConfigure('red', -foreground => '#FF3333'); #define tag for font color $status_window->tagConfigure('green', -foreground => '#009900'); #define tag for font color $monitorenabledchkbx = 'monitor_on'; #give it a default value $mw->Label( -text => 'Disable Monitor', -bg => '#666699', -fg => 'white', )->place(qw/-x 189 -y 242/); $mw->update(); $monitor_enabledchkbx = $mw->Checkbutton( -text => '', #using a text widget instead -onvalue => 'monitor_off', -offvalue => 'monitor_on', -variable => \$monitorenabledchkbx, -background => '#666699', -activebackground => '#666699', -highlightbackground => '#666699', -command => sub{monitor_enable_disable();}, )->place(qw/-x 160 -y 240/); $mw->update(); monitor_enable_disable(); #call sub to enable and create monitor $stop_button = $mw->Button->Compound; $stop_button->Text(-text => "Stop"); $stop_button = $mw->Button( -width => '50', -height => '13', -background => '#EFEFEF', -activebackground => '#666699', -foreground => '#000000', -activeforeground => '#FFFFFF', -borderwidth => '3', -image => $stop_button, -command => sub{$stop = 'yes';} )->place; $mw->update(); #create this button but don't place it yet $rtc_button = $mw->Button->Compound; $rtc_button->Text(-text => "Run"); $rtc_button = $mw->Button( -width => '50', -height => '13', -background => '#EFEFEF', -activebackground => '#666699', -foreground => '#000000', -activeforeground => '#FFFFFF', -borderwidth => '3', -image => $rtc_button, -command => sub{engine();} )->place(qw/-x 110 -y 65/); $mw->update(); $rtc_button->focus(); $progressbar = $mw->ProgressBar( -width => '420', -bg => '#666699' )->place(qw/-x 176 -y 65/); $mw->update(); $status_ind = $mw->Canvas( -width => '28', #engine status indicator -height => '9', -background => '#666699', )->place(qw/-x 621 -y 69/); $mw->update(); #load the Engine if (-e "./webinject.pl") { do "./webinject.pl" } #test if the Engine was loaded unless (defined &engine){ print STDERR "Error: I can not load the test engine (webinject.pl)!\n\n"; print STDERR "Check to make sure webinject.pl exists.\n"; print STDERR "If it is not missing, you are most likely missing some Perl modules it requires.\n"; print STDERR "Try running the engine by itself and see what modules it complains about.\n\n"; } MainLoop; #------------------------------------------------------------------ sub gui_initial { #this runs when engine is first loaded #vars set in test engine $currentcasefile = ''; $latency = ''; $casecount = ''; $case{description1} = ''; $totalruncount = ''; $runcount = ''; $failedcount = ''; $passedcount = ''; $casefailedcount = ''; $casepassedcount = ''; $totalruntime = ''; $stop = 'no'; $plotclear = 'no'; $out_window->delete('0.0','end'); #clear window before starting $status_window->delete('0.0','end'); #clear window before starting $status_ind->configure(-background => '#FF9900'); #change status color amber while running $rtc_button->placeForget; #remove the run button $stop_button->place(qw/-x 110 -y 65/); #place the stop button $monitor_enabledchkbx->configure(-state => 'disabled'); #disable button while running $out_window->insert("end", "Starting Webinject Engine... \n\n"); $out_window->see("end"); } #------------------------------------------------------------------ sub gui_restart { #kill the entire app and restart it if ($0 =~ /webinjectgui.pl/) { exec 'perl ./webinjectgui.pl'; } if ($0 =~ /webinjectgui.exe/) { exec './webinjectgui.exe'; } } #------------------------------------------------------------------ sub gui_processing_msg { $out_window->insert("end", "processing test case file:\n$currentcasefile\n\n", 'bold'); $out_window->see("end"); } #------------------------------------------------------------------ sub gui_statusbar { $percentcomplete = ($runcount/$casecount)*100; $progressbar->set($percentcomplete); #update progressbar with current status } #------------------------------------------------------------------ sub gui_tc_descript { unless ($minimalcheckbx eq "minimal_on") { unless ($case{description1} =~ /dummy test case/) { $status_window->insert("end", "- $case{description1}\n"); $status_window->see("end"); } } } #------------------------------------------------------------------ sub gui_status_passed { $status_window->insert("end", "PASSED\n", 'green'); $status_window->see("end"); } #------------------------------------------------------------------ sub gui_status_failed { if ($1 and $2) { $status_window->insert("end", "FAILED ($1$2)\n", 'red'); $status_window->see("end"); } else { $status_window->insert("end", "FAILED\n", 'red'); $status_window->see("end"); } } #------------------------------------------------------------------ sub gui_timer_output { if ($timercheckbx eq "timer_on") { $status_window->insert("end", "$latency s\n"); $status_window->see("end"); } } #------------------------------------------------------------------ sub gui_final { $out_window->insert("end", "Execution Finished... see results.html file for detailed output report"); $out_window->see("end"); $status_window->insert("end", "\n\n------------------------------\nTotal Run Time: $totalruntime seconds\n"); $status_window->insert("end", "\nTest Cases Run: $totalruncount\nTest Cases Passed: $casepassedcount\nTest Cases Failed: $casefailedcount\nVerifications Passed: $passedcount\nVerifications Failed: $failedcount\n"); $status_window->see("end"); if ($failedcount > 0) { #change status color to reflect failure or all tests passed $status_ind->configure(-background => '#FF3333'); #red } else { $status_ind->configure(-background => '#009900'); #green } $monitor_enabledchkbx->configure(-state => 'normal'); #re-enable button after finish } #------------------------------------------------------------------ sub gui_updatemontab { if ($monitorenabledchkbx ne 'monitor_off') { #don't try to update if monitor is disabled in gui if ((-e "plot.png") and (($graphtype ne 'nograph') or ($plotclear ne 'yes'))) { #if plot graphic exists, put it in canvas $montab_plotcanvas->Photo('plotgraph', -file => "plot.png"); $montab_plotcanvas->Label(-image => 'plotgraph')->place(qw/-x 7 -y 0/); } } } #------------------------------------------------------------------ sub gui_updatemonstats { #update timers and counts in monitor tab if ($monitorenabledchkbx ne 'monitor_off') { #don't try to update if monitor is disabled in gui $mintime_text->configure(-text => "Min: $minresponse sec"); $maxtime_text->configure(-text => "Max: $maxresponse sec"); $avgtime_text->configure(-text => "Avg: $avgresponse sec"); $runcounttotal_text->configure(-text => "Total: $totalruncount"); $runcountcasespassed_text->configure(-text => "Passed: $casepassedcount"); $runcountcasespfailed_text->configure(-text => "Failed: $casefailedcount"); } } #------------------------------------------------------------------ sub gui_stop { #flip button and do cleanup when user clicks Stop $stop_button->placeForget; #remove the stop botton $rtc_button->place(qw/-x 110 -y 65/); #place the stop button $progressbar->set(-1); #update progressbar back to zero $mw->update(); gui_final(); } #------------------------------------------------------------------ sub gui_cleargraph { #remove graph if (-e "plot.png") { unlink "plot.png"; } #delete a plot file if it exists so an old one is never rendered $montab_plotcanvas->destroy; #destroy the canvas $montab_plotcanvas = $montab_canvas->Canvas( -width => '718', -height => '240', -background => '#EFEFEF', )->place(qw/-x 0 -y 0/); $mw->update(); #canvas to place graph into } #------------------------------------------------------------------ sub gui_cleargraph_button { #remove graph then set value to truncate log gui_cleargraph(); $plotclear = 'yes'; #set value so engine knows to truncate plot log } #------------------------------------------------------------------ sub about { $about = MainWindow->new( -title => 'About WebInject', -bg => '#666699', -takefocus => '1', #start on top ); $about->raise; #put in front $about->geometry("320x200+200+200"); #size and screen placement if (-e "icon.gif") { #if icon graphic exists, use it $about->update(); $icon = $about->Photo(-file => 'icon.gif'); $about->iconimage($icon); } $about_text = $about->ROText( -width => '100', #make these big. window size is controlled by geometry instead -height => '100', -background => '#666699', -foreground => 'white', )->pack; $about_text->insert("end", qq| WebInject ©2004-2006 Corey Goldberg Please visit www.webinject.org for information and documentation. WebInject is Free and Open Source. Licensed under the terms of the GNU GPL. |); } #------------------------------------------------------------------ sub viewconfig { $viewconfig = MainWindow->new( -title => 'config.xml', -bg => '#666699', -takefocus => '1', #start on top ); $viewconfig->raise; #put in front $viewconfig->geometry("500x400+200+200"); #size and screen placement if (-e "logo.gif") { #if icon graphic exists, use it $viewconfig->update(); $icon = $viewconfig->Photo(-file => 'icon.gif'); $viewconfig->iconimage($icon); } $config_text = $viewconfig->ROText( -width => '100', #make these big. window size is controlled by geometry instead -height => '100', -background => '#666699', -foreground => 'white', )->pack; open(CONFIG, "config.xml") or die "\nERROR: Failed to open config.xml file\n\n"; #open file handle @configfile = ; #read the file into an array $config_text->insert("end", @configfile); close(CONFIG); } #------------------------------------------------------------------ sub monitor_enable_disable { if ($monitorenabledchkbx eq 'monitor_on') { #create the monitor tab and all it's widgets $mon_tab = $tabs->add('montab', -label => 'Monitor'); $mw->update(); #add the notebook tab $montab_canvas = $mon_tab->Canvas( -width => '719', -height => '365', -background => '#EFEFEF', )->place(qw/-x 0 -y 0/); $mw->update(); #canvas to fill tab (to place widgets into) $montab_plotcanvas = $montab_canvas->Canvas( -width => '718', -height => '240', -background => '#EFEFEF', )->place(qw/-x 0 -y 0/); $mw->update(); #canvas to place graph into $clear_graph = $mon_tab->Button->Compound; $clear_graph->Text(-text => "Clear Graph"); $clear_graph = $mon_tab->Button( -width => '70', -height => '13', -background => '#EFEFEF', -activebackground => '#666699', -foreground => '#000000', -activeforeground => '#FFFFFF', -borderwidth => '3', -image => $clear_graph, -command => sub{gui_cleargraph_button();} )->place(qw/-x 630 -y 310/); $mw->update(); $montab_buttoncanvas = $montab_canvas->Canvas( -width => '700', -height => '26', -background => '#666699', )->place(qw/-x 10 -y 334/); $mw->update(); #canvas to place buttons into $montab_buttoncanvas->Label( -text => 'Line Graph', -bg => '#666699', -fg => 'white', )->place(qw/-x 49 -y 4/); $mw->update(); $radiolinegraph = $montab_buttoncanvas->Radiobutton( -value => 'lines', -variable => \$graphtype, -indicatoron => 'true', -background => '#666699', -activebackground => '#666699', -highlightbackground => '#666699', )->place(qw/-x 20 -y 2/); $mw->update(); $radiolinegraph->select; #select as default $montab_buttoncanvas->Label( -text => 'Impulse Graph', -bg => '#666699', -fg => 'white', )->place(qw/-x 199 -y 4/); $mw->update(); $montab_buttoncanvas->Radiobutton( -value => 'impulses', -variable => \$graphtype, -background => '#666699', -activebackground => '#666699', -highlightbackground => '#666699', )->place(qw/-x 170 -y 2/); $mw->update(); $montab_buttoncanvas->Label( -text => 'No Graph', -bg => '#666699', -fg => 'white', )->place(qw/-x 349 -y 4/); $mw->update(); $montab_buttoncanvas->Radiobutton( -value => 'nograph', -variable => \$graphtype, -background => '#666699', -activebackground => '#666699', -highlightbackground => '#666699', -command => sub{gui_cleargraph();} #remove graph from view )->place(qw/-x 320 -y 2/); $mw->update(); $resptime_label = $montab_canvas->Label( -width => '25', -height => '1', -background => '#EFEFEF', -foreground => 'black', -relief => 'flat', -anchor => 'w', )->place(qw/-x 12 -y 245/); $mw->update(); $resptime_label->configure(-text => 'Response Times:'); $minresponse = 'N/A'; #set initial value for timer display $mintime_text = $montab_canvas->Label( -width => '25', -height => '1', -background => '#EFEFEF', -foreground => 'black', -relief => 'flat', -anchor => 'w', )->place(qw/-x 32 -y 265/); $mw->update(); $mintime_text->configure(-text => "Min: $minresponse sec"); $maxresponse = 'N/A'; #set initial value for timer display $maxtime_text = $montab_canvas->Label( -width => '25', -height => '1', -background => '#EFEFEF', -foreground => 'black', -relief => 'flat', -anchor => 'w', )->place(qw/-x 32 -y 285/); $mw->update(); $maxtime_text->configure(-text => "Max: $maxresponse sec"); $avgresponse = 'N/A'; #set initial value for timer display $avgtime_text = $montab_canvas->Label( -width => '25', -height => '1', -background => '#EFEFEF', -foreground => 'black', -relief => 'flat', -anchor => 'w', )->place(qw/-x 32 -y 305/); $mw->update(); $avgtime_text->configure(-text => "Avg: $avgresponse sec"); $runcount_label = $montab_canvas->Label( -width => '25', -height => '1', -background => '#EFEFEF', -foreground => 'black', -relief => 'flat', -anchor => 'w', )->place(qw/-x 250 -y 245/); $mw->update(); $runcount_label->configure(-text => 'Runtime Counts:'); $totalruncount = 'N/A'; #set initial value for count display $runcounttotal_text = $montab_canvas->Label( -width => '25', -height => '1', -background => '#EFEFEF', -foreground => 'black', -relief => 'flat', -anchor => 'w', )->place(qw/-x 270 -y 265/); $mw->update(); $runcounttotal_text->configure(-text => "Total: $totalruncount"); $casepassedcount = 'N/A'; #set initial value for count display $runcountcasespassed_text = $montab_canvas->Label( -width => '25', -height => '1', -background => '#EFEFEF', -foreground => 'black', -relief => 'flat', -anchor => 'w', )->place(qw/-x 270 -y 285/); $mw->update(); $runcountcasespassed_text->configure(-text => "Passed: $casepassedcount"); $casefailedcount = 'N/A'; #set initial value for count display $runcountcasespfailed_text = $montab_canvas->Label( -width => '25', -height => '1', -background => '#EFEFEF', -foreground => 'black', -relief => 'flat', -anchor => 'w', )->place(qw/-x 270 -y 305/); $mw->update(); $runcountcasespfailed_text->configure(-text => "Failed: $casefailedcount"); } #end monitor create if ($monitorenabledchkbx eq 'monitor_off') { #delete the tab when disabled $mon_tab = $tabs->delete('montab', -label => 'Monitor'); $mw->update(); } } #------------------------------------------------------------------ sub gui_no_plotter_found { #if gnuplot not specified, notify on gui $montab_plotcanvas->Label( -text => "Sorry, I can't display the graph.\nMake sure you have gnuplot on your system and it's location is specified in config.xml. ", -bg => '#EFEFEF', -fg => 'black', )->place(qw/-x 95 -y 100/); $mw->update(); } #------------------------------------------------------------------