Created
June 2, 2014 17:27
-
-
Save esdrubal/d6447be5566371766a27 to your computer and use it in GitHub Desktop.
WebClient CancelAsync
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Copyright 2012 Xamarin Inc. (http://www.xamarin.com) | |
// | |
using System; | |
using System.Globalization; | |
using System.IO; | |
using System.Net; | |
using System.Net.Sockets; | |
using System.Text; | |
using System.Threading; | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var ret = UploadFileAsyncCancelEvent(); | |
Console.WriteLine((ret)? "It Works!" : "Bug!"); | |
} | |
public static bool UploadFileAsyncCancelEvent() | |
{ | |
return UploadAsyncTest((webClient, uri, cancelEvent) => | |
{ | |
string tempFile = Path.GetTempFileName(); | |
webClient.UploadFileCompleted += (sender, args) => | |
{ | |
if (args.Cancelled) | |
cancelEvent.Set(); | |
}; | |
webClient.UploadFileAsync(uri, "PUT", tempFile); | |
}); | |
} | |
public static bool UploadAsyncTest(Action<WebClient, Uri, EventWaitHandle> uploadAction) | |
{ | |
var ep = new IPEndPoint(IPAddress.Loopback, 8000); | |
string url = "http://" + IPAddress.Loopback + ":8000/test/"; | |
using (var responder = new SocketResponder(ep, EchoRequestHandler)) | |
{ | |
responder.Start(); | |
var webClient = new WebClient(); | |
var cancellationTokenSource = new CancellationTokenSource(); | |
cancellationTokenSource.Token.Register(webClient.CancelAsync); | |
var cancelEvent = new ManualResetEvent(false); | |
uploadAction.Invoke(webClient, new Uri(url), cancelEvent); | |
cancellationTokenSource.Cancel(); | |
return cancelEvent.WaitOne(1000); | |
} | |
} | |
/* | |
* HELPERS | |
*/ | |
static byte[] EchoRequestHandler(Socket socket) | |
{ | |
MemoryStream ms = new MemoryStream(); | |
byte[] buffer = new byte[4096]; | |
int bytesReceived = socket.Receive(buffer); | |
while (bytesReceived > 0) | |
{ | |
ms.Write(buffer, 0, bytesReceived); | |
// We don't check for Content-Length or anything else here, so we give the client a little time to write | |
// after sending the headers | |
Thread.Sleep(200); | |
if (socket.Available > 0) | |
{ | |
bytesReceived = socket.Receive(buffer); | |
} | |
else | |
{ | |
bytesReceived = 0; | |
} | |
} | |
ms.Flush(); | |
ms.Position = 0; | |
StringBuilder sb = new StringBuilder(); | |
string expect = null; | |
StreamReader sr = new StreamReader(ms, Encoding.UTF8); | |
string line = null; | |
byte state = 0; | |
while ((line = sr.ReadLine()) != null) | |
{ | |
if (state > 0) | |
{ | |
state = 2; | |
sb.Append(line); | |
sb.Append("\r\n"); | |
} if (line.Length == 0) | |
{ | |
state = 1; | |
} | |
else if (line.StartsWith("Expect:")) | |
{ | |
expect = line.Substring(8); | |
} | |
} | |
StringWriter sw = new StringWriter(); | |
if (expect == "100-continue" && state != 2) | |
{ | |
sw.WriteLine("HTTP/1.1 100 Continue"); | |
sw.WriteLine(); | |
sw.Flush(); | |
socket.Send(Encoding.UTF8.GetBytes(sw.ToString())); | |
// receive body | |
ms = new MemoryStream(); | |
buffer = new byte[4096]; | |
bytesReceived = socket.Receive(buffer); | |
while (bytesReceived > 0) | |
{ | |
ms.Write(buffer, 0, bytesReceived); | |
Thread.Sleep(200); | |
if (socket.Available > 0) | |
{ | |
bytesReceived = socket.Receive(buffer); | |
} | |
else | |
{ | |
bytesReceived = 0; | |
} | |
} | |
ms.Flush(); | |
ms.Position = 0; | |
sb = new StringBuilder(); | |
sr = new StreamReader(ms, Encoding.UTF8); | |
line = sr.ReadLine(); | |
while (line != null) | |
{ | |
sb.Append(line); | |
sb.Append("\r\n"); | |
line = sr.ReadLine(); | |
} | |
} | |
sw = new StringWriter(); | |
sw.WriteLine("HTTP/1.1 200 OK"); | |
sw.WriteLine("Content-Type: text/xml"); | |
sw.WriteLine("Content-Length: " + sb.Length.ToString(CultureInfo.InvariantCulture)); | |
sw.WriteLine(); | |
sw.Write(sb.ToString()); | |
sw.Flush(); | |
return Encoding.UTF8.GetBytes(sw.ToString()); | |
} | |
public delegate byte[] SocketRequestHandler(Socket socket); | |
public class SocketResponder : IDisposable | |
{ | |
private TcpListener tcpListener; | |
private readonly IPEndPoint _localEndPoint; | |
private Thread listenThread; | |
private SocketRequestHandler _requestHandler; | |
private bool _stopped = true; | |
private readonly object _syncRoot = new object(); | |
private const int SOCKET_CLOSED = 10004; | |
private const int SOCKET_INVALID_ARGS = 10022; | |
public SocketResponder(IPEndPoint localEP, SocketRequestHandler requestHandler) | |
{ | |
_localEndPoint = localEP; | |
_requestHandler = requestHandler; | |
} | |
public IPEndPoint LocalEndPoint | |
{ | |
get { return _localEndPoint; } | |
} | |
public void Dispose() | |
{ | |
Stop(); | |
} | |
public bool IsStopped | |
{ | |
get | |
{ | |
lock (_syncRoot) | |
{ | |
return _stopped; | |
} | |
} | |
} | |
public void Start() | |
{ | |
lock (_syncRoot) | |
{ | |
if (!_stopped) | |
return; | |
_stopped = false; | |
tcpListener = new TcpListener(LocalEndPoint); | |
tcpListener.Start(); | |
listenThread = new Thread(new ThreadStart(Listen)); | |
listenThread.Start(); | |
} | |
} | |
public void Stop() | |
{ | |
lock (_syncRoot) | |
{ | |
if (_stopped) | |
return; | |
_stopped = true; | |
if (tcpListener != null) | |
{ | |
tcpListener.Stop(); | |
tcpListener = null; | |
Thread.Sleep(50); | |
} | |
} | |
} | |
private void Listen() | |
{ | |
while (!_stopped) | |
{ | |
Socket socket = null; | |
try | |
{ | |
socket = tcpListener.AcceptSocket(); | |
socket.Send(_requestHandler(socket)); | |
try | |
{ | |
socket.Shutdown(SocketShutdown.Receive); | |
socket.Shutdown(SocketShutdown.Send); | |
} | |
catch | |
{ | |
} | |
} | |
catch (SocketException) | |
{ | |
} | |
finally | |
{ | |
Thread.Sleep(500); | |
if (socket != null) | |
socket.Close(); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment