2009-10-06 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels / SvcHttpHandler.cs
1 //
2 // SvcHttpHandler.cs
3 //
4 // Author:
5 //      Ankit Jain  <jankit@novell.com>
6 //      Atsushi Enomoto <atsushi@ximian.com>
7 //
8 // Copyright (C) 2006,2009 Novell, Inc.  http://www.novell.com
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 using System;
30 using System.Collections.Generic;
31 using System.Linq;
32 using System.Web;
33 using System.Threading;
34
35 using System.ServiceModel;
36 using System.ServiceModel.Activation;
37 using System.ServiceModel.Configuration;
38 using System.ServiceModel.Description;
39
40 namespace System.ServiceModel.Channels {
41
42         internal class SvcHttpHandler : IHttpHandler
43         {
44                 Type type;
45                 Type factory_type;
46                 string path;
47                 Uri request_url;
48                 ServiceHostBase host;
49                 Queue<HttpContext> pending = new Queue<HttpContext> ();
50                 int close_state;
51
52                 AutoResetEvent process_request_wait = new AutoResetEvent (false);
53                 AutoResetEvent listening = new AutoResetEvent (false);
54
55                 public SvcHttpHandler (Type type, Type factoryType, string path)
56                 {
57                         this.type = type;
58                         this.factory_type = factoryType;
59                         this.path = path;
60                 }
61
62                 public bool IsReusable 
63                 {
64                         get { return true; }
65                 }
66
67                 public ServiceHostBase Host {
68                         get { return host; }
69                 }
70
71                 public HttpContext WaitForRequest (TimeSpan timeout)
72                 {
73                         if (close_state > 0)
74                                 return null;
75                         DateTime start = DateTime.Now;
76
77                         if (close_state > 0)
78                                 return null;
79                         if (pending.Count == 0) {
80                                 if (!process_request_wait.WaitOne (timeout - (DateTime.Now - start), false) || close_state > 0)
81                                         return null;
82                         }
83                         HttpContext ctx;
84                         lock (pending) {
85                                 if (pending.Count == 0)
86                                         return null;
87                                 ctx = pending.Dequeue ();
88                         }
89                         if (ctx.AllErrors != null && ctx.AllErrors.Length > 0)
90                                 return WaitForRequest (timeout - (DateTime.Now - start));
91                         return ctx;
92                 }
93
94                 public void ProcessRequest (HttpContext context)
95                 {
96                         request_url = context.Request.Url;
97                         EnsureServiceHost ();
98                         pending.Enqueue (context);
99                         process_request_wait.Set ();
100
101                         if (close_state == 0)
102                                 listening.WaitOne ();
103                 }
104
105                 public void EndRequest (HttpContext context)
106                 {
107                         listening.Set ();
108                 }
109
110                 // called from SvcHttpHandlerFactory's remove callback (i.e.
111                 // unloading asp.net). It closes ServiceHost, then the host
112                 // in turn closes the listener and the channels it opened.
113                 // The channel listener calls CloseServiceChannel() to stop
114                 // accepting further requests on its shutdown.
115                 public void Close ()
116                 {
117                         host.Close ();
118                         host = null;
119                 }
120
121                 // called from AspNetChannelListener.Close() or .Abort().
122                 public void CloseServiceChannel ()
123                 {
124                         if (close_state > 0)
125                                 return;
126                         close_state = 1;
127                         process_request_wait.Set ();
128                         listening.Set ();
129                         close_state = 2;
130                 }
131
132                 void EnsureServiceHost ()
133                 {
134                         if (host != null)
135                                 return;
136
137                         //ServiceHost for this not created yet
138                         var baseUri = new Uri (HttpContext.Current.Request.Url.GetLeftPart (UriPartial.Path));
139                         if (factory_type != null) {
140                                 host = ((ServiceHostFactory) Activator.CreateInstance (factory_type)).CreateServiceHost (type, new Uri [] {baseUri});
141                         }
142                         else
143                                 host = new ServiceHost (type, baseUri);
144                         host.Extensions.Add (new VirtualPathExtension (baseUri.AbsolutePath));
145
146                         host.Open ();
147                 }
148         }
149 }