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; }
ReturnUnauthorized()51 		public abstract void ReturnUnauthorized ();
52 
Abort()53 		public void Abort ()
54 		{
55 			Response.Abort ();
56 			OnContextClosed ();
57 		}
58 
Close()59 		public void Close ()
60 		{
61 			Response.Close ();
62 			OnContextClosed ();
63 		}
64 
OnContextClosed()65 		protected virtual void OnContextClosed ()
66 		{
67 		}
68 	}
69 
70 	class HttpStandaloneContextInfo : HttpContextInfo
71 	{
HttpStandaloneContextInfo(HttpListenerContext ctx)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 
ReturnUnauthorized()103 		public override void ReturnUnauthorized ()
104 		{
105 			ctx.Response.StatusCode = 401;
106 		}
107 	}
108 
109 	class AspNetHttpContextInfo : HttpContextInfo
110 	{
AspNetHttpContextInfo(SvcHttpHandler handler, HttpContext ctx)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 
ReturnUnauthorized()145 		public override void ReturnUnauthorized ()
146 		{
147 			ctx.Response.StatusCode = 401;
148 		}
149 
OnContextClosed()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 	{
HttpStandaloneRequestInfo(HttpListenerRequest request)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 	{
AspNetHttpRequestInfo(HttpRequest request)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; }
Abort()256 		public abstract void Abort ();
Close()257 		public abstract void Close ();
SetLength(long value)258 		public abstract void SetLength (long value);
259 
260 		public virtual bool SuppressContent { get; set; }
261 	}
262 
263 	class HttpStandaloneResponseInfo : HttpResponseInfo
264 	{
HttpStandaloneResponseInfo(HttpListenerResponse response)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 
Abort()291 		public override void Abort ()
292 		{
293 			res.Abort ();
294 		}
295 
Close()296 		public override void Close ()
297 		{
298 			res.Close ();
299 		}
300 
SetLength(long value)301 		public override void SetLength (long value)
302 		{
303 			res.ContentLength64 = value;
304 		}
305 	}
306 
307 	class AspNetHttpResponseInfo : HttpResponseInfo
308 	{
AspNetHttpResponseInfo(HttpResponse response)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 
Abort()340 		public override void Abort ()
341 		{
342 			res.End ();
343 		}
344 
Close()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 
SetLength(long value)353 		public override void SetLength (long value)
354 		{
355 			res.AddHeader ("Content-Length", value.ToString (CultureInfo.InvariantCulture));
356 		}
357 	}
358 }
359