using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net; using System.IO; using System.Threading; namespace TINetworkTest { /* These instructions tell me how to set up will as a proxy. This is required to help me * test this software. This should not be required or helpful for the end user. The end * user will have his own proxy. * * Testing the proxy from the command line: * curl --proxy will.trade-ideas.com:8080 --head http://www.trade-ideas.com/NetworkTest.php * I did this from the data center and from my laptop. At this time I was using IP numbers to * allow the proxy. This gave me the current date, and listed "will" in a "via" header when * I did this from my laptop. This gave me a "forbidden" error when I tried it from * bob-saget. So it worked perfectly. * * Opening the fire wall on will: * I don't have a firewall script on will. I can only guess that I filled out a quick form * when I was installing Fedora on will. I used the following line to add port 8080 to the * white list: * iptables --insert INPUT 6 --protocol tcp --destination-port webcache -m state --state NEW -j ACCEPT * I probably should have used * iptables --insert INPUT 6 -m state --state NEW --protocol tcp --destination-port webcache -j ACCEPT * to look more like the existing rules. So the second example is probably better but the * first one has the advantage of being testing! * Note that the rule numbers start at 1, not 0. Inserting at position 1 will put the new * rule at the top of the list. * * I tested the firewall with * telnet will 8080 * I tested the proxy settings (which were incomplete the first time) by typing this on will: * telnet localhost 8080 * This will tell you if the message is getting through, before you try anything fancier. * * To turn on a simple proxy on will I created the file /etc/httpd/conf.d/trade_ideas_proxy.conf * with the following contents: * # Use this to test the proxy settings in TI Pro. * Listen 8080 * * ProxyRequests On * ProxyVia On * DocumentRoot /var/www/alldocs/8080 * * Order Deny,Allow * Deny from all * Allow from 98.176.36.240 * * * Then I called * apachectl graceful * * Log files on will: * less /var/log/httpd/error_log * This showed some useful stuff. Espeically after receiving a 5xx error. * * WARNING: The security on this next sections sucks! It worked well enough for the test, * but do not leave it up and running! The ip based security worked better, but I'm far * from an expert here, so it's probably best to disable that, too, when you are done. * * Use this config file and restart apache to test a proxy with credentials. This will * require a username and password when you connect to port 8080. If you enter the wrong * password, or just skip the username and password, you will get an appropriate error. * WARNING: For some reason, this turns on proxying for all virtual hosts, but only * requires a username and password for port 8080. So using will.trade-ideas.com:80 with * no username and password will work. That doesn't hurt our test, but it is bad. */ public partial class Form1 : Form { public Form1() { InitializeComponent(); UpdateStartButton(); UpdatePortColor(); } private Tester TestInProgress; private void UpdateStartButton() { startTestButton.Enabled = (null == TestInProgress) && (tryDefaultProxyCheckBox.Checked || tryNoProxyCheckBox.Checked || tryCustomProxyCheckBox.Checked); abortTestButton.Enabled = null != TestInProgress; } private void hostNameTextBox_TextChanged(object sender, EventArgs e) { tryCustomProxyCheckBox.Checked = true; } private void portTextBox_TextChanged(object sender, EventArgs e) { tryCustomProxyCheckBox.Checked = true; UpdatePortColor(); } private void UpdatePortColor() { bool error = false; if (tryCustomProxyCheckBox.Checked) { int unused; error = !Int32.TryParse(portTextBox.Text, out unused); } portTextBox.BackColor = error ? Color.LightPink : SystemColors.Window; } private void userNameTextBox_TextChanged(object sender, EventArgs e) { tryCustomProxyCheckBox.Checked = true; } private void passwordTextBox_TextChanged(object sender, EventArgs e) { tryCustomProxyCheckBox.Checked = true; } private void tryDefaultProxyCheckBox_CheckedChanged(object sender, EventArgs e) { UpdateStartButton(); } private void tryNoProxyCheckBox_CheckedChanged(object sender, EventArgs e) { UpdateStartButton(); } private void tryCustomProxyCheckBox_CheckedChanged(object sender, EventArgs e) { UpdateStartButton(); UpdatePortColor(); } private void AddOutput(string line) { outputTextBox.AppendText(line + "\r\n"); } private void AddOutputWithDate(string line) { AddOutput(DateTime.Now.ToString() + ": " + line); } private void startTestButton_Click(object sender, EventArgs e) { TestInProgress = new Tester(this); UpdateStartButton(); TestInProgress.Start(); } private class Tester { private volatile bool _aborted; private volatile HttpWebRequest _request; public void Abort() { _aborted = true; if (null != _request) _request.Abort(); // Rules: // _request is initially null. // _request can change, but it can never change back to null. // After you set _request, you have to manually check for the _aborted flag. } private List Proxies = new List(); private List Urls = new List(); // Use this because it's not likely to fail. Remember that we are converting a block of bytes // to characters as soon as we receive the data. We might night have the entire message. We // might have a partial unicode character. private static readonly Encoding LATIN1 = Encoding.GetEncoding(28591); private class AbortException : Exception { } private void ThreadFunction() { try { foreach (Uri url in Urls) { AddOutput("Testing url: " + url); foreach (ProxyInfo proxy in Proxies) { AddOutputWithDate("Starting " + proxy.Describe(url)); DateTime start = DateTime.Now; _request = (HttpWebRequest)WebRequest.Create(url); _request.Proxy = proxy.Proxy; _request.Timeout = 5000; _request.ReadWriteTimeout = 15000; if (_aborted) throw new AbortException(); HttpWebResponse response = (HttpWebResponse)_request.GetResponse(); Stream responseStream = response.GetResponseStream(); byte[] buffer = new byte[2048]; while (true) { int bytesRead = responseStream.Read(buffer, 0, buffer.Length); if (_aborted) throw new AbortException(); if (bytesRead > 0) { string body = new String(LATIN1.GetChars(buffer, 0, bytesRead)); AddOutputWithDate(response.StatusCode + ": “" + body + '”'); } else break; } response.Close(); AddOutputWithDate("Status code: " + response.StatusCode); } } } catch (AbortException ex) { AddOutputWithDate("Aborted at user's request."); } catch (Exception ex) { AddOutputWithDate("Unexpected exception in test: " + ex); } _form.Invoke((MethodInvoker)Done); } private void AddOutputWithDate(string line) { _form.Invoke((MethodInvoker)delegate { _form.AddOutputWithDate(line); }); } private void AddOutput(string line) { _form.Invoke((MethodInvoker)delegate { _form.AddOutput(line); }); } private readonly Form1 _form; public Tester(Form1 form) { _form = form; } public void Start() { _form.tabControl1.SelectedTab = _form.outputTabPage; _form.AddOutputWithDate("Starting."); try { if (_form.tryDefaultProxyCheckBox.Checked) Proxies.Add(ProxyInfo.DEFAULT); if (_form.tryNoProxyCheckBox.Checked) Proxies.Add(ProxyInfo.NONE); if (_form.tryCustomProxyCheckBox.Checked) { try { Proxies.Add(ProxyInfo.GetCustom(_form.hostNameTextBox.Text, Int32.Parse(_form.portTextBox.Text), _form.userNameTextBox.Text, _form.passwordTextBox.Text)); } catch (Exception ex) { _form.AddOutputWithDate("Unexpected exception with custom proxy: " + ex.Message); } } Urls.Add(new Uri("http://www.trade-ideas.com/NetworkTest.php")); Urls.Add(new Uri("http://69.43.145.244/NetworkTest.php")); Urls.Add(new Uri("http://69.43.145.244/NetworkTest1.php")); if (_form.customUrlTextBox.Text != "") try { Urls.Add(new Uri(_form.customUrlTextBox.Text)); } catch (Exception ex) { _form.AddOutputWithDate("Unexpected exception with custom URL: " + ex.Message); } new Thread(ThreadFunction).Start(); } catch (Exception ex) { _form.AddOutputWithDate("Problem setting up test: " + ex); Done(); } } private void Done() { _form.AddOutputWithDate("Done."); // For simplicity we say that the new test can't start until this test ends. // In a production system we'd be more likely to start the operation immediately, // and ignore results producted by any old operations. System.Diagnostics.Debug.Assert(_form.TestInProgress == this); _form.TestInProgress = null; _form.UpdateStartButton(); } }; private class ProxyInfo { public IWebProxy Proxy { get; private set; } public string Name { get; private set; } private ProxyInfo(IWebProxy Proxy, string Name) { this.Proxy = Proxy; this.Name = Name; } public static ProxyInfo NONE { get { // GlobalProxySelection.GetEmptyWebProxy() return new ProxyInfo(null, "No Proxy"); } } public static ProxyInfo DEFAULT { get { return new ProxyInfo(WebRequest.DefaultWebProxy, "Default Proxy"); } } public static ProxyInfo GetCustom(string Host, int Port, string UserName, string Password) { IWebProxy proxy = new WebProxy(Host, Port); if ((UserName != "") || (Password != "")) { ICredentials Credentials = new NetworkCredential(UserName, Password); proxy.Credentials = Credentials; } return new ProxyInfo(proxy, "Custom Proxy"); } public string Describe(Uri url) { StringBuilder sb = new StringBuilder(); sb.Append(Name); if (null != Proxy) { Uri proxyUrl = Proxy.GetProxy(url); if (url != proxyUrl) { sb.Append(" ("); sb.Append(proxyUrl); sb.Append(')'); } } return sb.ToString(); } } private void abortTestButton_Click(object sender, EventArgs e) { if (null != TestInProgress) TestInProgress.Abort(); } } }