Skip to content

Instantly share code, notes, and snippets.

@ToJans
Last active December 14, 2015 11:58
Show Gist options
  • Save ToJans/5082560 to your computer and use it in GitHub Desktop.
Save ToJans/5082560 to your computer and use it in GitHub Desktop.
Who can tell me why fiddler https proxying gives a timeout and http does not.....
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
using System;
using System.Net;
using System.Net.Security;
namespace NetVCR.Specs
{
[TestClass]
public class Verify_basic_proxy_functionality
{
WebClient WC;
Proxy SUT;
Uri uri;
const string faked_url = "http://proxy/ping";
const string faked_response_body = "pong";
const string missing_url = "http://proxy/pang";
const string replay_http_url = "http://httpbin.org/ip";
const string replay_https_url = "https://httpbin.org/ip";
const string word_occuring_in_replay_response = "origin";
[TestInitialize]
public void Init()
{
SUT = new Proxy();
SUT.FakeResponse(Url: faked_url, ResponseBody: faked_response_body);
uri = SUT.Startup(9100, IsRecording: false);
WC = new WebClient(){ Proxy = new WebProxy(uri) };
}
[TestMethod]
public void Faked_url_should_return_faked_response()
{
WC.DownloadString(faked_url).ShouldBe(faked_response_body);
}
[TestMethod]
[ExpectedException(typeof(WebException))]
public void Missing_url_should_return_error()
{
WC.DownloadString(missing_url);
}
[TestMethod]
public void Http_reverse_proxy_should_work()
{
SUT.IsRecording = true;
var initial_result = WC.DownloadString(replay_http_url);
initial_result.ShouldContain(word_occuring_in_replay_response);
SUT.IsRecording = false;
var result = WC.DownloadString(replay_http_url);
result.ShouldBe(initial_result);
}
[TestMethod]
public void Https_recording_should_use_the_Fiddler_cert_as_root()
{
string expected_certificate_Issuer = "CN=DO_NOT_TRUST_FiddlerRoot, O=DO_NOT_TRUST, OU=Created by http://www.fiddler2.com";
string expected_certificate_Subject = "CN=httpbin.org, O=DO_NOT_TRUST, OU=Created by http://www.fiddler2.com";
string certificate_issuer = null;
string certificate_subject = null;
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslerrors) => {
certificate_issuer = certificate.Issuer;
certificate_subject = certificate.Subject;
return sslerrors == SslPolicyErrors.None;
};
SUT.IsRecording = true;
var initial_result = WC.DownloadString(replay_https_url);
certificate_issuer.ShouldBe(expected_certificate_Issuer);
certificate_subject.ShouldBe(expected_certificate_Subject);
}
[TestMethod]
public void Https_reverse_proxy_should_work()
{
SUT.IsRecording = true;
var initial_result = WC.DownloadString(replay_https_url);
initial_result.ShouldContain(word_occuring_in_replay_response);
SUT.IsRecording = false;
var result = WC.DownloadString(replay_https_url);
result.ShouldBe(initial_result);
}
[TestCleanup]
public void Done()
{
SUT.Shutdown();
}
}
}
using Fiddler;
using NetVCR.FiddlerSession;
using System;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;
namespace NetVCR
{
public class Proxy : IDisposable
{
ISessionRepository _Repo;
SessionFilter _RequestFilter;
SessionField _MatchingRequestFields;
public bool IsRecording { get; set; }
private Uri _proxyUri;
string fnamecertificate = "FiddlerRoot.cer";
private bool StartupFailed = false;
object Lock = new object();
public Proxy(SessionFilter Filter = null, SessionField MatchingRequestFields = SessionField.FullUrl, ISessionRepository Repo = null)
{
this._RequestFilter = Filter ?? SessionFilter.AllowAll;
this._MatchingRequestFields = MatchingRequestFields;
this._Repo = Repo ?? new SessionRepository();
}
public void FakeResponse(Action<Fiddler.Session> oSessionAction = null,
string Url = "http://bogus.com", string Method = "GET", string RequestBody = "",
int ResponseCode = 200, string ResponseBody = null, string ResponseHeaders = null)
{
var oSession = BuildSession(Method, Url, RequestBody);
oSession.utilCreateResponseAndBypassServer();
oSession.responseCode = ResponseCode;
if (RequestBody != null) oSession.utilSetRequestBody(RequestBody);
if (ResponseHeaders != null) oSession.oResponse.headers.AssignFromString(ResponseHeaders);
if (ResponseBody != null) oSession.utilSetResponseBody(ResponseBody);
if (Url != null) oSession.fullUrl = Url;
if (oSessionAction != null) oSessionAction(oSession);
InsertSessionInternal(oSession);
}
void InsertSessionInternal(Fiddler.Session oSession)
{
var hashcode = oSession.GetHashCodeForRequest(_MatchingRequestFields);
if (!_Repo.ContainsKey(hashcode))
_Repo.Add(hashcode, oSession.ResponseToByteArray());
}
public Uri Startup(int port, bool? IsRecording = null)
{
StartupFailed = false;
if (Fiddler.FiddlerApplication.IsStarted())
{
Fiddler.FiddlerApplication.Shutdown();
}
while (Fiddler.FiddlerApplication.isClosing)
System.Threading.Thread.Sleep(100);
if (!IsRecording.HasValue)
this.IsRecording = _Repo.HasItems == false;
this.IsRecording = IsRecording.Value;
if (this.IsRecording)
_Repo.Truncate();
Fiddler.FiddlerApplication.OnNotification += delegate(object sender, NotificationEventArgs oNEA)
{
Console.WriteLine("** NotifyUser: " + oNEA.NotifyString);
if (oNEA.NotifyString.Contains("System.Net.Sockets.SocketException (0x80004005)"))
{
lock (this)
{
this.StartupFailed = true;
}
}
};
Fiddler.FiddlerApplication.Log.OnLogString += delegate(object sender, LogEventArgs oLEA)
{
Console.WriteLine("** LogString: " + oLEA.LogString);
};
Fiddler.FiddlerApplication.Startup(port, FiddlerCoreStartupFlags.DecryptSSL | FiddlerCoreStartupFlags.ChainToUpstreamGateway);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
while (Fiddler.FiddlerApplication.IsStarted() == false && this.StartupFailed == false)
System.Threading.Thread.Sleep(100);
if (this.StartupFailed)
{
throw new Exception("Unable to start service; probably the network address " + _proxyUri + " is in use");
}
var b = new UriBuilder("http://localhost");
b.Port = port;
this._proxyUri = b.Uri;
if (!File.Exists(fnamecertificate))
{
b.Path = fnamecertificate;
new WebClient().DownloadFile(b.Uri, fnamecertificate);
}
FiddlerApplication.oDefaultClientCertificate = X509Certificate.CreateFromCertFile(fnamecertificate);
Fiddler.FiddlerApplication.BeforeRequest += new Fiddler.SessionStateHandler(FiddlerApplication_BeforeRequest);
Fiddler.FiddlerApplication.AfterSessionComplete += new Fiddler.SessionStateHandler(FiddlerApplication_AfterSessionComplete);
return _proxyUri;
}
void FiddlerApplication_AfterSessionComplete(Fiddler.Session oSession)
{
if (oSession.oRequest.headers.HTTPMethod == "CONNECT") return;
lock (Lock)
{
if (oSession.url.StartsWith(_proxyUri.ToString())) return;
if (IsRecording)
{
InsertSessionInternal(oSession);
//Console.WriteLine(Encoding.UTF8.GetString(oSession.ResponseBody.Take(1024).ToArray()));
}
}
}
void FiddlerApplication_BeforeRequest(Fiddler.Session oSession)
{
if (oSession.oRequest.headers.HTTPMethod == "CONNECT")
{
return;
}
lock (Lock)
{
oSession.bBufferResponse = true;
oSession.utilDecodeRequest();
if (oSession.url.StartsWith(_proxyUri.ToString())) return;
if (_RequestFilter.Allows(oSession) && !IsRecording)
{
var requestHashcode = oSession.GetHashCodeForRequest(_MatchingRequestFields);
byte[] responseBytes = null;
oSession.utilCreateResponseAndBypassServer();
if (_Repo.TryGetValue(requestHashcode, out responseBytes))
{
oSession.ResponseFromByteArray(responseBytes);
}
else
{
//oSession.SetDefaultResponseHeaders();
oSession.responseCode = 500;
oSession.utilSetResponseBody("The requested URI " + oSession.GetValue(SessionField.FullUrl) + " has not been recorded by the proxy and cannot be replayed");
}
}
}
}
public void Shutdown()
{
Fiddler.FiddlerApplication.Shutdown();
Fiddler.FiddlerApplication.BeforeRequest -= new Fiddler.SessionStateHandler(FiddlerApplication_BeforeRequest);
Fiddler.FiddlerApplication.AfterSessionComplete -= new Fiddler.SessionStateHandler(FiddlerApplication_AfterSessionComplete);
//System.Threading.Thread.Sleep(750);
}
public static Fiddler.Session BuildSession(string RequestVerb, string Url, string Body)
{
var headers = new Fiddler.HTTPRequestHeaders
{
HTTPMethod = RequestVerb,
RequestPath = Url
};
var body = System.Text.Encoding.ASCII.GetBytes(Body);
return new Fiddler.Session(headers, body);
}
public void Dispose()
{
Shutdown();
}
}
}
@ToJans
Copy link
Author

ToJans commented Mar 4, 2013

So it works on the https get but fails on the https replay

@ToJans
Copy link
Author

ToJans commented Mar 6, 2013

https now works as well !!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment