~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/monomac/samples/CFNetwork/AsyncTests.HttpClientTests/Addin/Server.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// AsyncTests.HttpClientTests.Addin.Server
 
3
//
 
4
// Authors:
 
5
//      Martin Baulig (martin.baulig@gmail.com)
 
6
//
 
7
// Copyright 2012 Xamarin Inc. (http://www.xamarin.com)
 
8
//
 
9
//
 
10
// Permission is hereby granted, free of charge, to any person obtaining
 
11
// a copy of this software and associated documentation files (the
 
12
// "Software"), to deal in the Software without restriction, including
 
13
// without limitation the rights to use, copy, modify, merge, publish,
 
14
// distribute, sublicense, and/or sell copies of the Software, and to
 
15
// permit persons to whom the Software is furnished to do so, subject to
 
16
// the following conditions:
 
17
// 
 
18
// The above copyright notice and this permission notice shall be
 
19
// included in all copies or substantial portions of the Software.
 
20
// 
 
21
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
22
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
23
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
24
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
25
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
26
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
27
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
28
//
 
29
 
 
30
using System;
 
31
using System.Linq;
 
32
using System.IO;
 
33
using System.Net;
 
34
using System.Net.Http;
 
35
using System.Diagnostics;
 
36
using System.Reflection;
 
37
using System.Collections.Generic;
 
38
using System.Threading;
 
39
using System.Threading.Tasks;
 
40
using NUnit.Framework;
 
41
 
 
42
namespace AsyncTests.HttpClientTests.Addin
 
43
{
 
44
        using Framework;
 
45
 
 
46
        public class Server
 
47
        {
 
48
                static Server instance;
 
49
                HttpListener listener;
 
50
                Dictionary<string, RequestHandler> handlerByName;
 
51
                Dictionary<MethodInfo, RequestHandler> handlerByMethod;
 
52
                TaskCompletionSource<object> startTcs;
 
53
                TaskCompletionSource<object> stopTcs;
 
54
                Dictionary<int, Exception> exceptions;
 
55
                Assembly assembly;
 
56
                string prefix;
 
57
                bool running;
 
58
                Thread thread;
 
59
                Random random;
 
60
 
 
61
                Server (Assembly assembly, string prefix)
 
62
                {
 
63
                        this.assembly = assembly;
 
64
                        this.prefix = prefix;
 
65
 
 
66
                        random = new Random ();
 
67
                        exceptions = new Dictionary<int, Exception> ();
 
68
 
 
69
                        handlerByName = new Dictionary<string, RequestHandler> ();
 
70
                        handlerByMethod = new Dictionary<MethodInfo, RequestHandler> ();
 
71
 
 
72
                        startTcs = new TaskCompletionSource<object> ();
 
73
                        stopTcs = new TaskCompletionSource<object> ();
 
74
 
 
75
                        listener = new HttpListener ();
 
76
                        listener.Prefixes.Add (prefix);
 
77
 
 
78
                        listener.AuthenticationSchemeSelectorDelegate = SelectAuthentication;
 
79
 
 
80
                        running = true;
 
81
                        thread = new Thread (() => ServerMain ());
 
82
                        thread.Start ();
 
83
                }
 
84
 
 
85
                AuthenticationSchemes SelectAuthentication (HttpListenerRequest request)
 
86
                {
 
87
                        var path = request.Url.AbsolutePath.Substring (1);
 
88
                        if (!handlerByName.ContainsKey (path))
 
89
                                return AuthenticationSchemes.Anonymous;
 
90
 
 
91
                        var handler = handlerByName [path];
 
92
                        return handler.Attribute.Authentication;
 
93
                }
 
94
 
 
95
                internal static void Log (string message, params object[] args)
 
96
                {
 
97
                        Debug.WriteLine (string.Format (message, args), "Server");
 
98
                }
 
99
 
 
100
                void ServerMain ()
 
101
                {
 
102
                        try {
 
103
                                Register ();
 
104
                                listener.Start ();
 
105
                        } catch (Exception ex) {
 
106
                                startTcs.SetException (ex);
 
107
                                return;
 
108
                        }
 
109
 
 
110
                        startTcs.SetResult (null);
 
111
 
 
112
                        while (running) {
 
113
                                try {
 
114
                                        Run ().Wait ();
 
115
                                } catch (Exception ex) {
 
116
                                        if (!running)
 
117
                                                break;
 
118
                                        Log ("SERVER EXCEPTION: {0} {1}", running, ex);
 
119
                                        throw;
 
120
                                }
 
121
                        }
 
122
                        Log ("Server exiting.");
 
123
                        stopTcs.SetResult (null);
 
124
                }
 
125
 
 
126
                Task Shutdown ()
 
127
                {
 
128
                        running = false;
 
129
                        listener.Stop ();
 
130
                        listener.Close ();
 
131
 
 
132
                        return stopTcs.Task;
 
133
                }
 
134
 
 
135
                public static Uri URI {
 
136
                        get { return new Uri (instance.prefix); }
 
137
                }
 
138
 
 
139
                public static string Host {
 
140
                        get {
 
141
                                var uri = URI;
 
142
                                if (uri.Port != 0)
 
143
                                        return string.Format ("{0}:{1}", uri.Host, uri.Port);
 
144
                                else
 
145
                                        return uri.Host;
 
146
                        }
 
147
                }
 
148
 
 
149
                public static bool IsLocal {
 
150
                        get { return URI.IsLoopback; }
 
151
                }
 
152
 
 
153
                public static bool IsRunning {
 
154
                        get { return instance != null; }
 
155
                }
 
156
 
 
157
                public static async Task Start (Assembly assembly, string prefix)
 
158
                {
 
159
                        if (instance != null)
 
160
                                return;
 
161
                        instance = new Server (assembly, prefix);
 
162
                        await instance.startTcs.Task;
 
163
                        Log ("Started server: {0}", prefix);
 
164
                }
 
165
 
 
166
                public static async Task Stop ()
 
167
                {
 
168
                        if (instance != null) {
 
169
                                await instance.Shutdown ();
 
170
                                instance = null;
 
171
                        }
 
172
                }
 
173
 
 
174
                void Register ()
 
175
                {
 
176
                        foreach (var type in assembly.GetTypes ()) {
 
177
                                CheckType (type);
 
178
                        }
 
179
                }
 
180
 
 
181
                void CheckType (Type type)
 
182
                {
 
183
                        var attr = type.GetCustomAttribute<AsyncTestFixtureAttribute> ();
 
184
                        if (attr == null)
 
185
                                return;
 
186
 
 
187
                        var bf = BindingFlags.Public | BindingFlags.Static;
 
188
                        foreach (var method in type.GetMethods (bf)) {
 
189
                                var mattr = method.GetCustomAttribute<RequestHandlerAttribute> ();
 
190
                                if (mattr == null)
 
191
                                        continue;
 
192
 
 
193
                                if (CheckMethod (method, mattr))
 
194
                                        continue;
 
195
                                Log ("ERROR: Invalid method: {0}.{1}", type.FullName, method.Name);
 
196
                        }
 
197
 
 
198
                        foreach (var nested in type.GetNestedTypes ()) {
 
199
                                CheckType (nested);
 
200
                        }
 
201
                }
 
202
 
 
203
                bool CheckMethod (MethodInfo method, RequestHandlerAttribute attr)
 
204
                {
 
205
                        if ((method.ReturnType != typeof (void)) &&
 
206
                            !method.ReturnType.Equals (typeof (Task)))
 
207
                                return false;
 
208
 
 
209
                        var pinfo = method.GetParameters ();
 
210
                        if (pinfo.Length != 1)
 
211
                                return false;
 
212
 
 
213
                        if (!pinfo [0].ParameterType.Equals (typeof(ServerContext)))
 
214
                                return false;
 
215
 
 
216
                        var handler = new RequestHandler (method, attr);
 
217
                        handlerByName.Add (handler.Name, handler);
 
218
                        handlerByMethod.Add (method, handler);
 
219
                        return true;
 
220
                }
 
221
 
 
222
                class RequestHandler
 
223
                {
 
224
                        public RequestHandlerAttribute Attribute {
 
225
                                get;
 
226
                                private set;
 
227
                        }
 
228
 
 
229
                        public bool IsAsync {
 
230
                                get;
 
231
                                private set;
 
232
                        }
 
233
 
 
234
                        public RequestHandlerDelegate Handler {
 
235
                                get;
 
236
                                private set;
 
237
                        }
 
238
 
 
239
                        public AsyncRequestHandlerDelegate AsyncHandler {
 
240
                                get;
 
241
                                private set;
 
242
                        }
 
243
 
 
244
                        public MethodInfo Method {
 
245
                                get {
 
246
                                        return IsAsync ? AsyncHandler.Method : Handler.Method;
 
247
                                }
 
248
                        }
 
249
 
 
250
                        public string Name {
 
251
                                get;
 
252
                                private set;
 
253
                        }
 
254
 
 
255
                        public RequestHandler (MethodInfo method, RequestHandlerAttribute attr)
 
256
                        {
 
257
                                Attribute = attr;
 
258
                                if (method.ReturnType == typeof (void)) {
 
259
                                        Handler = (RequestHandlerDelegate)Delegate.CreateDelegate (
 
260
                                                typeof (RequestHandlerDelegate), method);
 
261
                                } else {
 
262
                                        IsAsync = true;
 
263
                                        AsyncHandler = (AsyncRequestHandlerDelegate)Delegate.CreateDelegate (
 
264
                                                typeof (AsyncRequestHandlerDelegate), method);
 
265
                                }
 
266
 
 
267
                                Name = method.DeclaringType.FullName.Replace ('.', '/') + '/' + method.Name;
 
268
                        }
 
269
 
 
270
                        public override string ToString ()
 
271
                        {
 
272
                                return string.Format ("[RequestHandler: {0}]", Name);
 
273
                        }
 
274
                }
 
275
 
 
276
                async Task Run ()
 
277
                {
 
278
                        var context = await listener.GetContextAsync ();
 
279
                        var url = context.Request.Url;
 
280
 
 
281
                        var path = url.AbsolutePath.Substring (1);
 
282
                        if (path == string.Empty) {
 
283
                                PrintIndex (context);
 
284
                                context.Response.Close ();
 
285
                                return;
 
286
                        } else if (path.Equals ("favicon.ico")) {
 
287
                                context.Response.StatusCode = 404;
 
288
                                context.Response.Close ();
 
289
                                return;
 
290
                        }
 
291
 
 
292
                        if (!handlerByName.ContainsKey (path)) {
 
293
                                Log ("Unknown URL: {0}", path);
 
294
                                Error (context.Response, "Invalid URL: '{0}'", path);
 
295
                                return;
 
296
                        }
 
297
 
 
298
                        var handler = handlerByName [path];
 
299
 
 
300
                        var sctx = new ServerContext (context);
 
301
                        if (handler.IsAsync)
 
302
                                ServerContext.Register (sctx);
 
303
                        try {
 
304
                                await sctx.Invoke (handler.Name, handler.Method);
 
305
                        } catch (Exception ex) {
 
306
                                if (!sctx.SetException (ex))
 
307
                                        Exception (context.Response, ex);
 
308
                        } finally {
 
309
                                try {
 
310
                                        context.Response.Close ();
 
311
                                } catch {
 
312
                                        ;
 
313
                                }
 
314
                        }
 
315
                }
 
316
 
 
317
                int CreateExceptionId ()
 
318
                {
 
319
                        int id;
 
320
                        do {
 
321
                                id = random.Next ();
 
322
                        } while (exceptions.ContainsKey (id));
 
323
                        return id;
 
324
                }
 
325
 
 
326
                static readonly string ExceptionHeaderName = typeof (Server).FullName + ".Exception";
 
327
 
 
328
                void Exception (HttpListenerResponse response, Exception exception)
 
329
                {
 
330
                        var id = CreateExceptionId ();
 
331
                        exceptions [id] = exception;
 
332
                        response.AddHeader (ExceptionHeaderName, id.ToString ());
 
333
                        if (exception == null)
 
334
                                return;
 
335
                        response.StatusCode = 500;
 
336
                        using (var writer = new StreamWriter (response.OutputStream)) {
 
337
                                writer.WriteLine (string.Format ("EXCEPTION: {0}", exception));
 
338
                        }
 
339
                        response.Close ();
 
340
                }
 
341
 
 
342
                public static Exception GetException (HttpResponseMessage response)
 
343
                {
 
344
                        var exception = ServerContext.GetException (response);
 
345
                        if (exception != null)
 
346
                                return exception;
 
347
 
 
348
                        if (!response.Headers.Contains (ExceptionHeaderName))
 
349
                                return null;
 
350
                        try {
 
351
                                var value = response.Headers.GetValues (ExceptionHeaderName).First ();
 
352
                                var id = int.Parse (value);
 
353
                                return instance.exceptions [id];
 
354
                        } catch {
 
355
                                return null;
 
356
                        }
 
357
                }
 
358
 
 
359
                public static void CheckException (HttpResponseMessage response)
 
360
                {
 
361
                        var exc = GetException (response);
 
362
                        if (exc != null)
 
363
                                throw exc;
 
364
                }
 
365
 
 
366
                void Error (HttpListenerResponse response, string format, params object[] args)
 
367
                {
 
368
                        response.StatusCode = 500;
 
369
                        using (var writer = new StreamWriter (response.OutputStream)) {
 
370
                                writer.WriteLine (format, args);
 
371
                        }
 
372
                        response.Close ();
 
373
                }
 
374
 
 
375
                public static Uri GetUri (RequestHandlerDelegate dlg)
 
376
                {
 
377
                        var handler = instance.handlerByMethod [dlg.Method];
 
378
                        if (handler == null)
 
379
                                throw new InvalidOperationException ();
 
380
 
 
381
                        return GetUri (handler);
 
382
                }
 
383
 
 
384
                public static Uri GetAsyncUri (AsyncRequestHandlerDelegate dlg)
 
385
                {
 
386
                        var handler = instance.handlerByMethod [dlg.Method];
 
387
                        if (handler == null)
 
388
                                throw new InvalidOperationException ();
 
389
 
 
390
                        return GetUri (handler);
 
391
                }
 
392
 
 
393
                static Uri GetUri (RequestHandler handler)
 
394
                {
 
395
                        return new Uri (new Uri (instance.prefix), handler.Name);
 
396
                }
 
397
 
 
398
                void PrintIndex (HttpListenerContext context)
 
399
                {
 
400
                        context.Response.StatusCode = 200;
 
401
                        using (var writer = new StreamWriter (context.Response.OutputStream)) {
 
402
                                writer.WriteLine ("<html><head><title>Test Server</title><head><body>");
 
403
                                writer.WriteLine ("<p>Registered tests:");
 
404
                                writer.WriteLine ("<p><ul>");
 
405
                                foreach (var handler in handlerByName.Keys) {
 
406
                                        var uri = new Uri (new Uri (prefix), handler);
 
407
                                        writer.WriteLine ("<li><a href=\"{0}\">{1}</a>",
 
408
                                                          uri.AbsoluteUri, handler);
 
409
                                }
 
410
                                writer.WriteLine ("</ul>");
 
411
                                writer.WriteLine ("</body></html>");
 
412
                        }
 
413
                }
 
414
        }
 
415
}