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