Merge pull request #2373 from akoeplinger/servicemodel-tcpreplychannel-race
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels.Http / HttpContextInfo.cs
1 //
2 // HttpContextInfo.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2010 Novell, Inc.  http://www.novell.com
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.Collections.Generic;
30 using System.Collections.Specialized;
31 using System.Globalization;
32 using System.IO;
33 using System.Net;
34 using System.Security.Principal;
35 using System.ServiceModel;
36 using System.Text;
37 using System.Threading;
38 using System.Web;
39
40 namespace System.ServiceModel.Channels.Http
41 {
42         // Context
43         
44         abstract class HttpContextInfo
45         {
46                 public abstract HttpRequestInfo Request { get; }
47                 public abstract HttpResponseInfo Response { get; }
48
49                 public abstract string User { get; }
50                 public abstract string Password { get; }
51                 public abstract void ReturnUnauthorized ();
52
53                 public void Abort ()
54                 {
55                         Response.Abort ();
56                         OnContextClosed ();
57                 }
58
59                 public void Close ()
60                 {
61                         Response.Close ();
62                         OnContextClosed ();
63                 }
64                 
65                 protected virtual void OnContextClosed ()
66                 {
67                 }
68         }
69
70         class HttpStandaloneContextInfo : HttpContextInfo
71         {
72                 public HttpStandaloneContextInfo (HttpListenerContext ctx)
73                 {
74                         this.ctx = ctx;
75                         request = new HttpStandaloneRequestInfo (ctx.Request);
76                         response = new HttpStandaloneResponseInfo (ctx.Response);
77                 }
78                 
79                 HttpListenerContext ctx;
80                 HttpStandaloneRequestInfo request;
81                 HttpStandaloneResponseInfo response;
82
83                 public HttpListenerContext Source {
84                         get { return ctx; }
85                 }
86
87                 public override HttpRequestInfo Request {
88                         get { return request; }
89                 }
90
91                 public override HttpResponseInfo Response {
92                         get { return response; }
93                 }
94
95                 public override string User {
96                         get { return ctx.User != null ? ((HttpListenerBasicIdentity) ctx.User.Identity).Name : null; }
97                 }
98
99                 public override string Password {
100                         get { return ctx.User != null ? ((HttpListenerBasicIdentity) ctx.User.Identity).Password : null; }
101                 }
102
103                 public override void ReturnUnauthorized ()
104                 {
105                         ctx.Response.StatusCode = 401;
106                 }
107         }
108
109         class AspNetHttpContextInfo : HttpContextInfo
110         {
111                 public AspNetHttpContextInfo (SvcHttpHandler handler, HttpContext ctx)
112                 {
113                         this.ctx = ctx;
114                         this.handler = handler;
115                         this.request = new AspNetHttpRequestInfo (ctx.Request);
116                         this.response = new AspNetHttpResponseInfo (ctx.Response);
117                 }
118                 
119                 HttpContext ctx;
120                 SvcHttpHandler handler;
121                 AspNetHttpRequestInfo request;
122                 AspNetHttpResponseInfo response;
123
124                 public HttpContext Source {
125                         get { return ctx; }
126                 }
127                 
128                 public override HttpRequestInfo Request {
129                         get { return request; }
130                 }
131
132                 public override HttpResponseInfo Response {
133                         get { return response; }
134                 }
135
136                 public override string User {
137                         get { return ctx.User != null ? ((GenericIdentity) ctx.User.Identity).Name : null; }
138                 }
139
140                 // FIXME: how to acquire this?
141                 public override string Password {
142                         get { return null; }
143                 }
144
145                 public override void ReturnUnauthorized ()
146                 {
147                         ctx.Response.StatusCode = 401;
148                 }
149
150                 protected override void OnContextClosed ()
151                 {
152                         handler.EndHttpRequest (ctx);
153                 }
154         }
155
156         // Request
157
158         abstract class HttpRequestInfo
159         {
160                 public abstract long ContentLength64 { get; }
161                 public abstract NameValueCollection QueryString { get; }
162                 public abstract NameValueCollection Headers { get; }
163                 public abstract Uri Url { get; }
164                 public abstract string ContentType { get; }
165                 public abstract string HttpMethod { get; }
166                 public abstract Stream InputStream { get; }
167                 public abstract string ClientIPAddress { get; }
168                 public abstract int ClientPort { get; }
169         }
170
171         class HttpStandaloneRequestInfo : HttpRequestInfo
172         {
173                 public HttpStandaloneRequestInfo (HttpListenerRequest request)
174                 {
175                         this.req = request;
176                 }
177                 
178                 HttpListenerRequest req;
179
180                 public override long ContentLength64 {
181                         get { return req.ContentLength64; }
182                 }
183                 public override NameValueCollection QueryString {
184                         get { return req.QueryString; }
185                 }
186                 public override NameValueCollection Headers {
187                         get { return req.Headers; }
188                 }
189                 public override Uri Url {
190                         get { return req.Url; }
191                 }
192                 public override string ContentType {
193                         get { return req.ContentType; }
194                 }
195                 public override string HttpMethod {
196                         get { return req.HttpMethod; }
197                 }
198                 public override Stream InputStream {
199                         get { return req.InputStream; }
200                 }
201                 public override string ClientIPAddress {
202                         get { return req.RemoteEndPoint.Address.ToString (); }
203                 }
204                 public override int ClientPort {
205                         get { return req.RemoteEndPoint.Port; }
206                 }
207         }
208
209         class AspNetHttpRequestInfo : HttpRequestInfo
210         {
211                 public AspNetHttpRequestInfo (HttpRequest request)
212                 {
213                         this.req = request;
214                 }
215                 
216                 HttpRequest req;
217
218                 public override long ContentLength64 {
219                         get { return req.ContentLength; }
220                 }
221                 public override NameValueCollection QueryString {
222                         get { return req.QueryString; }
223                 }
224                 public override NameValueCollection Headers {
225                         get { return req.Headers; }
226                 }
227                 public override Uri Url {
228                         get { return req.Url; }
229                 }
230                 public override string ContentType {
231                         get { return req.ContentType; }
232                 }
233                 public override string HttpMethod {
234                         get { return req.HttpMethod; }
235                 }
236                 public override Stream InputStream {
237                         get { return req.InputStream; }
238                 }
239                 public override string ClientIPAddress {
240                         get { return req.UserHostAddress; }
241                 }
242                 public override int ClientPort {
243                         get { return -1; } // cannot retrieve
244                 }
245         }
246         
247         // Response
248         
249         abstract class HttpResponseInfo
250         {
251                 public abstract string ContentType { get; set; }
252                 public abstract NameValueCollection Headers { get; }
253                 public abstract Stream OutputStream { get; }
254                 public abstract int StatusCode { get; set; }
255                 public abstract string StatusDescription { get; set; }
256                 public abstract void Abort ();
257                 public abstract void Close ();
258                 public abstract void SetLength (long value);
259                 
260                 public virtual bool SuppressContent { get; set; }
261         }
262
263         class HttpStandaloneResponseInfo : HttpResponseInfo
264         {
265                 public HttpStandaloneResponseInfo (HttpListenerResponse response)
266                 {
267                         this.res = response;
268                 }
269                 
270                 HttpListenerResponse res;
271
272                 public override string ContentType {
273                         get { return res.ContentType; }
274                         set { res.ContentType = value; }
275                 }
276                 public override NameValueCollection Headers {
277                         get { return res.Headers; }
278                 }
279                 public override int StatusCode {
280                         get { return res.StatusCode; }
281                         set { res.StatusCode = value; }
282                 }
283                 public override string StatusDescription {
284                         get { return res.StatusDescription; }
285                         set { res.StatusDescription = value; }
286                 }
287                 public override Stream OutputStream {
288                         get { return res.OutputStream; }
289                 }
290                 
291                 public override void Abort ()
292                 {
293                         res.Abort ();
294                 }
295                 
296                 public override void Close ()
297                 {
298                         res.Close ();
299                 }
300                 
301                 public override void SetLength (long value)
302                 {
303                         res.ContentLength64 = value;
304                 }
305         }
306
307         class AspNetHttpResponseInfo : HttpResponseInfo
308         {
309                 public AspNetHttpResponseInfo (HttpResponse response)
310                 {
311                         this.res = response;
312                 }
313                 
314                 HttpResponse res;
315                 
316                 public override bool SuppressContent {
317                         get { return res.SuppressContent; }
318                         set { res.SuppressContent = value; }
319                 }
320                 public override string ContentType {
321                         get { return res.ContentType; }
322                         set { res.ContentType = value; }
323                 }
324                 public override NameValueCollection Headers {
325                         get { return res.Headers; }
326                 }
327                 public override int StatusCode {
328                         get { return res.StatusCode; }
329                         set { res.StatusCode = value; }
330                 }
331                 
332                 public override string StatusDescription {
333                         get { return res.StatusDescription; }
334                         set { res.StatusDescription = value; }
335                 }
336                 public override Stream OutputStream {
337                         get { return res.OutputStream; }
338                 }
339                 
340                 public override void Abort ()
341                 {
342                         res.End ();
343                 }
344                 
345                 public override void Close ()
346                 {
347                         // We must not close the response here, as everything is taking place in the
348                         // HttpApplication's pipeline context and the output is sent to the client
349                         // _after_ we leave this method. Closing the response here will stop any
350                         // output from reaching the client.
351                 }
352                 
353                 public override void SetLength (long value)
354                 {
355                         res.AddHeader ("Content-Length", value.ToString (CultureInfo.InvariantCulture));
356                 }
357         }
358 }