wasSharpNET – Blame information for rev 28
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
9 | office | 1 | /////////////////////////////////////////////////////////////////////////// |
2 | // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
||
3 | // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
||
4 | // rights of fair usage, the disclaimer and warranty conditions. // |
||
5 | /////////////////////////////////////////////////////////////////////////// |
||
6 | |||
7 | using System; |
||
8 | using System.Collections.Generic; |
||
9 | using System.Net; |
||
10 | using System.Threading; |
||
11 | |||
12 | namespace wasSharpNET.Network.HTTP |
||
13 | { |
||
15 | office | 14 | public abstract class HTTPServer : IDisposable |
9 | office | 15 | { |
27 | office | 16 | private readonly ManualResetEventSlim listenStop = new ManualResetEventSlim(false); |
28 | office | 17 | private readonly ManualResetEventSlim stopListen = new ManualResetEventSlim(false); |
27 | office | 18 | |
9 | office | 19 | private int activeRequests; |
11 | office | 20 | |
20 | office | 21 | private HttpListener HTTPListener; |
11 | office | 22 | |
9 | office | 23 | private int processedRequests; |
24 | |||
19 | office | 25 | public AuthenticationSchemes AuthenticationSchemes { get; set; } = |
26 | AuthenticationSchemes.None; |
||
9 | office | 27 | |
19 | office | 28 | public bool IsRunning => HTTPListener != null && HTTPListener.IsListening; |
9 | office | 29 | |
27 | office | 30 | public void Dispose() |
31 | { |
||
32 | stopListen.Set(); |
||
33 | } |
||
20 | office | 34 | |
35 | public bool Start(List<string> prefixes) |
||
10 | office | 36 | { |
20 | office | 37 | HTTPListener = new HttpListener |
19 | office | 38 | { |
39 | AuthenticationSchemes = AuthenticationSchemes |
||
40 | }; |
||
9 | office | 41 | |
10 | office | 42 | // Add all prefixes. |
16 | office | 43 | HTTPListener.Prefixes.Clear(); |
10 | office | 44 | foreach (var prefix in prefixes) |
45 | HTTPListener.Prefixes.Add(prefix); |
||
46 | |||
9 | office | 47 | // Do not bomb if the client disconnects. |
48 | HTTPListener.IgnoreWriteExceptions = true; |
||
49 | HTTPListener.Start(); |
||
20 | office | 50 | return ThreadPool.QueueUserWorkItem(Listen, new HTTPServerCallbackState(HTTPListener)); |
9 | office | 51 | } |
52 | |||
22 | office | 53 | public bool Stop(int timeout) |
9 | office | 54 | { |
20 | office | 55 | stopListen.Set(); |
22 | office | 56 | return listenStop.Wait(timeout); |
9 | office | 57 | } |
58 | |||
59 | private void Listen(object state) |
||
60 | { |
||
27 | office | 61 | var callbackState = (HTTPServerCallbackState) state; |
9 | office | 62 | |
63 | while (callbackState.Listener.IsListening) |
||
64 | { |
||
22 | office | 65 | callbackState.Listener?.BeginGetContext(ContextCallback, callbackState); |
20 | office | 66 | |
27 | office | 67 | if (WaitHandle.WaitAny(new[] {callbackState.ContextRetrieved, stopListen.WaitHandle}) != 1) |
20 | office | 68 | continue; |
69 | |||
22 | office | 70 | try |
71 | { |
||
72 | callbackState.Listener.Stop(); |
||
73 | callbackState.Listener.Close(); |
||
74 | } |
||
75 | finally |
||
76 | { |
||
77 | listenStop.Set(); |
||
78 | } |
||
20 | office | 79 | break; |
9 | office | 80 | } |
81 | } |
||
82 | |||
83 | public abstract void ProcessHTTPContext(HttpListenerContext context); |
||
84 | |||
85 | private void ContextCallback(IAsyncResult ar) |
||
86 | { |
||
27 | office | 87 | var callbackState = (HTTPServerCallbackState) ar.AsyncState; |
20 | office | 88 | HttpListenerContext httpContext; |
9 | office | 89 | |
90 | Interlocked.Increment(ref processedRequests); |
||
91 | Interlocked.Increment(ref activeRequests); |
||
92 | |||
93 | try |
||
94 | { |
||
95 | httpContext = callbackState.Listener.EndGetContext(ar); |
||
96 | } |
||
97 | catch (Exception) |
||
98 | { |
||
99 | Interlocked.Decrement(ref activeRequests); |
||
100 | return; |
||
101 | } |
||
102 | finally |
||
103 | { |
||
104 | callbackState.ContextRetrieved.Set(); |
||
105 | } |
||
106 | |||
107 | try |
||
108 | { |
||
109 | ProcessHTTPContext(httpContext); |
||
110 | } |
||
111 | finally |
||
112 | { |
||
113 | Interlocked.Decrement(ref activeRequests); |
||
114 | } |
||
115 | } |
||
116 | |||
117 | private class HTTPServerCallbackState |
||
118 | { |
||
119 | public HTTPServerCallbackState(HttpListener listener) |
||
120 | { |
||
121 | if (listener == null) |
||
20 | office | 122 | throw new ArgumentNullException(nameof(listener)); |
9 | office | 123 | Listener = listener; |
124 | ContextRetrieved = new AutoResetEvent(false); |
||
125 | } |
||
126 | |||
127 | public HttpListener Listener { get; } |
||
128 | |||
129 | public AutoResetEvent ContextRetrieved { get; } |
||
130 | } |
||
131 | } |
||
27 | office | 132 | } |