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