diff --git a/HttpPing.Tests/HttpPing.Tests.csproj b/HttpPing.Tests/HttpPing.Tests.csproj index 192d4e2..8421e75 100644 --- a/HttpPing.Tests/HttpPing.Tests.csproj +++ b/HttpPing.Tests/HttpPing.Tests.csproj @@ -38,6 +38,32 @@ prompt 4 + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + + + x86 + bin\x86\Debug\ + + + x86 + bin\x86\Release\ + ..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll diff --git a/HttpPing.Tests/ProgramTests.cs b/HttpPing.Tests/ProgramTests.cs index 5f2b55e..56eed9c 100644 --- a/HttpPing.Tests/ProgramTests.cs +++ b/HttpPing.Tests/ProgramTests.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Text; +using web_ping; namespace HttpPing.Tests { @@ -22,48 +23,172 @@ public void Init() } [TestMethod] - public void When_params_are_empty_should_return_usage_test() + public void When_params_are_empty_should_return_help_test() { - var expectedValue = "USAGE: HttpPing web_address [-d] [-t] [-ts] [-https] [-n count] [-i interval] [-l] [-nc] [-r redirectCount] \r\n"; + string expectedValue = Program.HelpMessage.Replace("\r\n", ""); string[] parameters = new string[]{}; - web_ping.Program.Main(parameters, _environmentServiceForTestPurpose); + web_ping.Program.Run(parameters, _environmentServiceForTestPurpose); + string actualOutput = _consoleOutput.ToString().Replace("\r\n", ""); + Assert.IsTrue(actualOutput.ToString().Equals(expectedValue)); + } + + [TestMethod] + public void When_show_help_argument_show_help_message_test() + { + string expectedValue = Program.HelpMessage.Replace("\r\n", ""); - Assert.IsTrue(_consoleOutput.ToString().Equals(expectedValue)); + string[] parameters = new string[] { "-help" }; + + web_ping.Program.Run(parameters, _environmentServiceForTestPurpose); + string actualOutput = _consoleOutput.ToString().Replace("\r\n", ""); + + Assert.IsTrue(actualOutput.ToString().Equals(expectedValue)); } + [TestMethod] + public void When_full_uri_path_should_be_displayed_test() + { + string expectedOutput = +@"Sending HTTPS requests to [https://github.com/Killeroo]: +Response from https://github.com/Killeroo: Code=200:OK Size=-1 +"; + + string[] parameters = new string[] { "https://github.com/Killeroo", + "-n", "1"}; + + web_ping.Program.Run(parameters, _environmentServiceForTestPurpose); + + Assert.IsTrue(_consoleOutput.ToString().Equals(expectedOutput)); + } [TestMethod] - public void When_params_webaddress_simple_count_1_interval_500ms_should_response_test() + public void When_hosts_only_argument_uri_path_should_not_be_displayed_test() { - var expectedValue = "Sending HTTP requests to [https://www.starwars.com]:\r\nResponse from www.starwars.com: Code=200:OK Size=-1\r\nResponse from www.starwars.com: Code=200:OK Size=-1\r\n"; + string expectedOutput = +@"Sending HTTPS requests to [https://github.com/Killeroo]: +Response from github.com: Code=200:OK Size=-1 +"; - string[] parameters = new string[] { "https://www.starwars.com", + string[] parameters = new string[] { "https://github.com/Killeroo", "-n", "1", - "-i", "500" }; + "-h"}; - web_ping.Program.Main(parameters, _environmentServiceForTestPurpose); + web_ping.Program.Run(parameters, _environmentServiceForTestPurpose); - Assert.IsTrue(_consoleOutput.ToString().Equals(expectedValue)); + Assert.IsTrue(_consoleOutput.ToString().Equals(expectedOutput)); } + [TestMethod] + public void When_bad_argument_throw_exception_test() + { + string expectedOutput = +@"Incorrect argument found +" + Program.UsageMessage + @" +"; + + string[] parameters = new string[] { "https://github.com/Killeroo", + "-n", "1", + "-notrealargument"}; + + web_ping.Program.Run(parameters, _environmentServiceForTestPurpose); + + Assert.IsTrue(_consoleOutput.ToString().Equals(expectedOutput)); + } [TestMethod] - public void When_params_webaddress_contains_dash_should_not_return_error_test() + public void When_request_count_is_one_only_one_request_is_sent_test() { - //var expectedValue = "Incorrect argument found\r\nUSAGE: HttpPing web_address [-d] [-t] [-ts] [-https] [-n count] [-i interval] [-l] [-nc] [-r redirectCount] \r\n"; - var expectedValue = "Sending HTTP requests to [https://www.star-wars.com]:\r\nResponse from www.star-wars.com: Code=200:OK Size=-1\r\nResponse from www.star-wars.com: Code=200:OK Size=-1\r\n"; + string expectedOutput = +@"Sending HTTPS requests to [https://github.com/Killeroo]: +Response from https://github.com/Killeroo: Code=200:OK Size=-1 +".Replace("\r\n", ""); + + string[] parameters = new string[] { "https://github.com/Killeroo", + "-n", "1"}; + + web_ping.Program.Run(parameters, _environmentServiceForTestPurpose); + string actualOutput = _consoleOutput.ToString().Replace("\r\n", ""); + + Assert.IsTrue(actualOutput.Equals(expectedOutput)); + } + [TestMethod] + public void When_request_count_is_two_then_two_requests_are_sent_test() + { + string expectedOutput = +@"Sending HTTPS requests to [https://github.com/]: +Response from https://github.com/: Code=200:OK Size=-1 +Response from https://github.com/: Code=200:OK Size=-1 +".Replace("\r\n", ""); + + string[] parameters = new string[] { "https://github.com/", + "-n", "2"}; + + web_ping.Program.Run(parameters, _environmentServiceForTestPurpose); + string actualOutput = _consoleOutput.ToString().Replace("\r\n", ""); + + Assert.IsTrue(actualOutput.Equals(expectedOutput)); + } + + [TestMethod] + public void When_no_params_url_is_google_http_should_respond_test() + { + string expectedOutput = +@"Sending HTTP requests to [http://www.google.com]: +Response from http://www.google.com/: Code=200:OK Size=-1 +Response from http://www.google.com/: Code=200:OK Size=-1 +Response from http://www.google.com/: Code=200:OK Size=-1 +Response from http://www.google.com/: Code=200:OK Size=-1 +Response from http://www.google.com/: Code=200:OK Size=-1 +".Replace("\r\n", ""); + + string[] parameters = new string[] { "http://www.google.com" }; + + web_ping.Program.Run(parameters, _environmentServiceForTestPurpose); + string actualOutput = _consoleOutput.ToString().Replace("\r\n", ""); + + Assert.IsTrue(actualOutput.Equals(expectedOutput)); + } + + [TestMethod] + public void When_no_params_url_is_google_https_should_respond_test() + { + string expectedOutput = +@"Sending HTTPS requests to [https://www.google.com]: +Response from https://www.google.com/: Code=200:OK Size=-1 +Response from https://www.google.com/: Code=200:OK Size=-1 +Response from https://www.google.com/: Code=200:OK Size=-1 +Response from https://www.google.com/: Code=200:OK Size=-1 +Response from https://www.google.com/: Code=200:OK Size=-1 +".Replace("\r\n", ""); + + string[] parameters = new string[] { "https://www.google.com" }; + + web_ping.Program.Run(parameters, _environmentServiceForTestPurpose); + string actualOutput = _consoleOutput.ToString().Replace("\r\n", ""); + + Assert.IsTrue(actualOutput.Equals(expectedOutput)); + } + + [TestMethod] + public void When_params_webaddress_contains_dash_should_not_return_error_test() + { + string expectedOutput = +@"Sending HTTPS requests to [https://www.star-wars.com]: +Response from https://www.starwars.com/: Code=200:OK Size=-1 +".Replace("\r\n", ""); string[] parameters = new string[] { "https://www.star-wars.com", "-n", "1", "-i", "500" }; - web_ping.Program.Main(parameters, _environmentServiceForTestPurpose); + web_ping.Program.Run(parameters, _environmentServiceForTestPurpose); + string actualOutput = _consoleOutput.ToString().Replace("\r\n", ""); - Assert.IsTrue(_consoleOutput.ToString().Equals(expectedValue)); + Assert.IsTrue(actualOutput.Equals(expectedOutput)); } } } diff --git a/HttpPing.sln b/HttpPing.sln index 4c9b8e6..8fa54b8 100644 --- a/HttpPing.sln +++ b/HttpPing.sln @@ -10,17 +10,37 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Debug|x64.ActiveCfg = Debug|x64 + {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Debug|x64.Build.0 = Debug|x64 + {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Debug|x86.ActiveCfg = Debug|x86 + {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Debug|x86.Build.0 = Debug|x86 {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Release|Any CPU.ActiveCfg = Release|Any CPU {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Release|Any CPU.Build.0 = Release|Any CPU + {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Release|x64.ActiveCfg = Release|x64 + {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Release|x64.Build.0 = Release|x64 + {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Release|x86.ActiveCfg = Release|x86 + {D4D36105-4AC4-4AD6-92DD-5EF9A05AF312}.Release|x86.Build.0 = Release|x86 {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Debug|x64.ActiveCfg = Debug|x64 + {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Debug|x64.Build.0 = Debug|x64 + {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Debug|x86.ActiveCfg = Debug|x86 + {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Debug|x86.Build.0 = Debug|x86 {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Release|Any CPU.ActiveCfg = Release|Any CPU {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Release|Any CPU.Build.0 = Release|Any CPU + {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Release|x64.ActiveCfg = Release|x64 + {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Release|x64.Build.0 = Release|x64 + {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Release|x86.ActiveCfg = Release|x86 + {6006C2E4-372B-4375-904E-A4E0D67BC2F2}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/HttpPing/HttpPing.csproj b/HttpPing/HttpPing.csproj index 77b987a..d0d8d18 100644 --- a/HttpPing/HttpPing.csproj +++ b/HttpPing/HttpPing.csproj @@ -33,6 +33,34 @@ prompt 4 + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + true + + + x86 + bin\x86\Debug\ + + + x86 + bin\x86\Release\ + diff --git a/HttpPing/Program.cs b/HttpPing/Program.cs index 55b5799..755b5ce 100644 --- a/HttpPing/Program.cs +++ b/HttpPing/Program.cs @@ -6,7 +6,8 @@ using System.Runtime.CompilerServices; using HttpPing.Interfaces; using HttpPing; - +using System.Security.Cryptography.X509Certificates; +using System.Net.Security; namespace web_ping { @@ -19,43 +20,72 @@ class Program private static bool NoColor { get; set; } = false; private static bool UseCommonLogFormat { get; set; } = false; private static bool ForceHttps { get; set; } = false; - private static int Interval { get; set; } = 30000; + private static bool ShowOnlyHostName { get; set; } = false; + private static int Interval { get; set; } = 1000; private static int Requests { get; set; } = 5; private static int Redirects { get; set; } = 4; - // Console Properties - private static ConsoleColor DefaultBackgroundColor { get; set; } - private static ConsoleColor DefaultForegroundColor { get; set; } - // Constants - private const string Usage = "USAGE: HttpPing web_address [-d] [-t] [-ts] [-https] [-n count] [-i interval] [-l] [-nc] [-r redirectCount] "; + public const string UsageMessage = "HttpPing.exe address [-d] [-t] [-ts] [-h] [-n count] [-i interval] [-r redirectCount] [-https]"; + public const string HelpMessage = +@"HttpPing 1.1 + +Description: + Send http requests as if they were pings! + +Usage: + HttpPing web_address [-d] [-t] [-ts] [-h] [-https] [-n count] [-i interval] [-l] [-nc] [-r redirectCount] + +Arguments: + [-d] Detailed mode: shows server and cache info + [-t] Infinite mode: Keep sending requests until stopped (Ctrl-C) + [-n count] Send a specific number of requests + [-ts] Include timestamp of when each request was sent + [-h] Only show the hostname in responses + [-i interval] Interval between each request in milliseconds (default 30000) + [-l] Use Common Log Format (https://en.wikipedia.org/wiki/Common_Log_Format) + [-nc] No color + [-r redirectCount] Follow redirect requests a maximum number of times (default 4) + [-https] Force requests to use https + +You can find the project and it's code on github: https://github.com/Killeroo/HttpPing +Maintained by Matthew Carney [matthewcarney64@gmail.com] +"; private static string resolvedAddress = ""; private static IEnvironmentService EnvironmentService; + /// + /// This method is the entry point of the program + /// + /// Array of strings that contains the command-line arguments passed to the program + internal static void Main(string[] args) + { + Run(args, new EnvironmentService()); + } + /// /// This method is the entry point of the program, with the test parameter environment it wrapper exit for test purpose /// /// Array of strings that contains the command-line arguments passed to the program /// Environment (wrapper for test) - internal static void Main(string[] args, IEnvironmentService environmentService) + internal static void Run(string[] args, IEnvironmentService environmentService) { EnvironmentService = environmentService; + // Some hack to get tests to work lol + ResetArgsForTest(); + // Arguments check if (args.Length == 0) { - Console.WriteLine(Usage); + Console.WriteLine(HelpMessage); EnvironmentService.Exit(0); return; } - // Save console colors - DefaultBackgroundColor = Console.BackgroundColor; - DefaultForegroundColor = Console.ForegroundColor; - // Parse arguments try { @@ -68,7 +98,11 @@ internal static void Main(string[] args, IEnvironmentService environmentService) case "-?": case "--?": case "/?": - Exit(); + case "-help": + case "--help": + case "/help": + Console.WriteLine(HelpMessage); + environmentService.Exit(0); break; case "-i": case "--i": @@ -105,6 +139,11 @@ internal static void Main(string[] args, IEnvironmentService environmentService) case "/ts": Timestamp = true; break; + case "-h": + case "--h": + case "/h": + ShowOnlyHostName = true; + break; case "-r": case "--r": case "/r": @@ -122,8 +161,15 @@ internal static void Main(string[] args, IEnvironmentService environmentService) default: if (count > 0) { - if (arg.Contains("-")) - throw new ArgumentException(); + if (arg.Contains("-") || arg.Contains("/")) + { + // If argument isn't a url then throw and exception + if (!Uri.IsWellFormedUriString(arg, UriKind.Absolute)) + { + throw new ArgumentException(); + } + } + } break; @@ -194,20 +240,29 @@ internal static void Main(string[] args, IEnvironmentService environmentService) // Results? } - - /// - /// This method is the entry point of the program - /// - /// Array of strings that contains the command-line arguments passed to the program - internal static void Main(string[] args) + public static void ResetArgsForTest() { - Main(args, new EnvironmentService()); + Infinite = false; + Detailed = false; + Timestamp = false; + NoColor = false; + UseCommonLogFormat = false; + ForceHttps = false; + ShowOnlyHostName = false; + Interval = 1000; + Requests = 5; + Redirects = 4; } - // SO: https://stackoverflow.com/questions/27108264/c-sharp-how-to-properly-make-a-http-web-get-request private static void HttpRequestLoop(string query) { + // Setup ServicePointManager to handle http verfication + // Source: https://stackoverflow.com/a/2904963 + ServicePointManager.Expect100Continue = true; + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ServerCertificateValidationCallback); + // Construct request HttpWebRequest request = (HttpWebRequest)WebRequest.Create(query); request.MaximumAutomaticRedirections = Redirects; @@ -215,21 +270,35 @@ private static void HttpRequestLoop(string query) request.Credentials = CredentialCache.DefaultCredentials; // Send requests - int index = 0; - Console.WriteLine("Sending HTTP requests to [{0}]:", query); + int sentRequests = 0; + Console.WriteLine("Sending HTTP{1} requests to [{0}]:", query, query.Contains("https://") ? "S" : ""); - while (Infinite || index <= Requests) + while(true) { var response = HttpRequest(request); if (response != null) - DisplayResponse(response, query); + DisplayResponse(response, response.ResponseUri); - index++; + sentRequests++; + + if (!Infinite && sentRequests == Requests) + { + // Finish loop if we have sent all the requests and not infinitely sending + break; + } + + // Wait interval before sending next request Thread.Sleep(Interval); } } + private static bool ServerCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + // Verify all requests to verify cerificates on our end + return true; + } + private static HttpWebResponse HttpRequest(HttpWebRequest req) { try @@ -249,12 +318,14 @@ private static HttpWebResponse HttpRequest(HttpWebRequest req) return null; } - private static void DisplayResponse(HttpWebResponse response, string address) + private static void DisplayResponse(HttpWebResponse response, Uri responseAddress) { // !!HACK ALERT!! if (!UseCommonLogFormat) - Console.Write("Response from {0}: Code=", new Uri(address).Host.ToString()); + { + Console.Write("Response from {0}: Code=", ShowOnlyHostName ? responseAddress.Host.ToString() : responseAddress.ToString()); + } if (!NoColor) { @@ -283,12 +354,11 @@ private static void DisplayResponse(HttpWebResponse response, string address) if (UseCommonLogFormat) { - Uri addrUri = new Uri(address); Console.WriteLine("{6} {0} [{1:dd/MMM/yyyy HH:mm:ss zzz}] \"GET {2} {3}/1.0\" {4} {5}", - addrUri.Host, + responseAddress.Host, DateTime.Now, - addrUri.AbsolutePath, - addrUri.Scheme.ToString().ToUpper(), + responseAddress.AbsolutePath, + responseAddress.Scheme.ToString().ToUpper(), ((int)response.StatusCode).ToString(), response.ContentLength, resolvedAddress); @@ -355,8 +425,7 @@ private static void Error(string msg) private static void ResetConsoleColors() { - Console.BackgroundColor = DefaultBackgroundColor; - Console.ForegroundColor = DefaultForegroundColor; + Console.ResetColor(); } private static void Exit(string message = null) @@ -364,7 +433,7 @@ private static void Exit(string message = null) if (!string.IsNullOrEmpty(message)) Error(message); - Console.WriteLine(Usage); + Console.WriteLine(UsageMessage); EnvironmentService.Exit(1); } } diff --git a/HttpPing/Properties/AssemblyInfo.cs b/HttpPing/Properties/AssemblyInfo.cs index a8ceee2..22c2520 100644 --- a/HttpPing/Properties/AssemblyInfo.cs +++ b/HttpPing/Properties/AssemblyInfo.cs @@ -37,5 +37,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.1.0.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] diff --git a/README.md b/README.md index f7b475f..643788e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # HttpPing -[![](https://img.shields.io/badge/version-1.0-brightgreen.svg)]() [![Build status](https://ci.appveyor.com/api/projects/status/q7lchn78v07pmemj?svg=true)](https://ci.appveyor.com/project/Killeroo/httpping) +[![](https://img.shields.io/badge/version-1.1-brightgreen.svg)](https://github.com/Killeroo/HttpPing/releases) A small tool that sends HTTP requests, presented in a ping-like style with status codes and colored results. -Download it here: [[Stable Releases]](https://github.com/Killeroo/HttpPing/releases) [[Nightly Build]](https://ci.appveyor.com/api/projects/killeroo/httpping/artifacts/HttpPing%2Fbin%2FDebug%2FHttpPing.exe) +Download it here: [[Stable Releases]](https://github.com/Killeroo/HttpPing/releases) *** ![alt text](HttpPing/Screenshots/screenshot1.png "HttpPing in action") @@ -16,13 +16,14 @@ Download it here: [[Stable Releases]](https://github.com/Killeroo/HttpPing/relea - Common Log Format (NCSA log format) ## Usage: - HttpPing.exe address [-d] [-t] [-ts] [-n count] [-i interval] [-r redirectCount] [-https] + HttpPing.exe address [-d] [-t] [-ts] [-h] [-n count] [-i interval] [-r redirectCount] [-https] ## Arguments: [-d] Detailed mode: shows server and cache info [-t] Infinite mode: Keep sending requests until stopped (Ctrl-C) [-n count] Send a specific number of requests [-ts] Include timestamp of when each request was sent + [-h] Only show the hostname in responses [-i interval] Interval between each request in milliseconds (default 30000) [-l] Use Common Log Format (https://en.wikipedia.org/wiki/Common_Log_Format) [-nc] No color