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