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