2 // System.Web.HttpRequest.cs
6 // Miguel de Icaza (miguel@novell.com)
7 // Gonzalo Paniagua Javier (gonzalo@novell.com)
11 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Web.Util;
36 using System.Collections.Specialized;
37 using System.Security.Permissions;
40 namespace System.Web {
43 // Methods exposed through HttpContext.Server property
46 // CAS - no InheritanceDemand here as the class is sealed
47 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
48 public sealed class HttpServerUtility {
51 internal HttpServerUtility (HttpContext context)
53 this.context = context;
56 public void ClearError ()
58 context.ClearError ();
61 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
62 public object CreateObject (string progID)
64 throw new HttpException (500, "COM is not supported");
67 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
68 public object CreateObject (Type type)
70 throw new HttpException (500, "COM is not supported");
73 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
74 public object CreateObjectFromClsid (string clsid)
76 throw new HttpException (500, "COM is not supported");
79 public void Execute (string path)
81 Execute (path, null, true);
84 public void Execute (string path, TextWriter writer)
86 Execute (path, writer, true);
90 public void Execute (string path, bool preserveForm)
92 Execute (path, null, preserveForm);
101 void Execute (string path, TextWriter writer, bool preserveForm)
104 throw new ArgumentNullException ("path");
106 if (path.IndexOf (':') != -1)
107 throw new ArgumentException ("Invalid path.");
109 HttpRequest request = context.Request;
110 string oldQuery = request.QueryStringRaw;
111 int qmark = path.IndexOf ('?');
113 request.QueryStringRaw = path.Substring (qmark + 1);
114 path = path.Substring (0, qmark);
115 } else if (!preserveForm) {
116 request.QueryStringRaw = "";
119 HttpResponse response = context.Response;
120 WebROCollection oldForm = null;
122 oldForm = request.Form as WebROCollection;
123 request.SetForm (new WebROCollection ());
126 TextWriter output = writer;
128 output = response.Output;
130 string oldFilePath = request.FilePath;
131 request.SetCurrentExePath (UrlUtils.Combine (request.BaseVirtualDir, path));
132 IHttpHandler handler = context.ApplicationInstance.GetHandler (context);
133 request.SetCurrentExePath (oldFilePath);
136 // If the target handler is not Page, the transfer must not occur.
137 // InTransit == true means we're being called from Transfer
138 if (context.InTransit && !(handler is Page))
139 throw new HttpException ("Transfer is possible only to .aspx files");
142 TextWriter previous = null;
145 context.PushHandler (handler);
147 previous = response.SetTextWriter (output);
149 if (!(handler is IHttpAsyncHandler)) {
150 handler.ProcessRequest (context);
152 IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler) handler;
153 IAsyncResult ar = asyncHandler.BeginProcessRequest (context, null, null);
154 ar.AsyncWaitHandle.WaitOne ();
155 asyncHandler.EndProcessRequest (ar);
158 if (oldQuery != null && oldQuery != "" && oldQuery != request.QueryStringRaw) {
159 oldQuery = oldQuery.Substring (1); // Ignore initial '?'
160 request.QueryStringRaw = oldQuery; // which is added here.
162 response.SetTextWriter (previous);
164 request.SetForm (oldForm);
165 context.InTransit = false;
167 context.PopHandler ();
172 public Exception GetLastError ()
175 return HttpContext.Current.Error;
176 return context.Error;
179 public string HtmlDecode (string s)
181 return HttpUtility.HtmlDecode (s);
184 public void HtmlDecode (string s, TextWriter output)
186 HttpUtility.HtmlDecode (s, output);
189 public string HtmlEncode (string s)
191 return HttpUtility.HtmlEncode (s);
194 public void HtmlEncode (string s, TextWriter output)
196 HttpUtility.HtmlEncode (s, output);
199 public string MapPath (string path)
201 return context.Request.MapPath (path);
204 public void Transfer (string path)
206 // If it's a page and a postback, don't pass form data
208 bool preserveForm = true;
209 if (context.Handler is Page) {
210 Page page = (Page) context.Handler;
211 preserveForm = !page.IsPostBack;
215 throw new HttpException ("Transfer may only be called from within a Page instance");
218 Transfer (path, preserveForm);
221 public void Transfer (string path, bool preserveForm)
224 if (!(context.Handler is Page))
225 throw new HttpException ("Transfer may only be called from within a Page instance");
228 context.InTransit = true;
229 Execute (path, null, preserveForm);
230 context.Response.End ();
233 public void Transfer (IHttpHandler handler, bool preserveForm)
236 throw new ArgumentNullException ("handler");
237 if (!(handler is Page))
238 throw new HttpException ("Transfer may only be called from within a Page instance");
240 // TODO: see the MS doc and search for "enableViewStateMac": this method is not
241 // allowed for pages when preserveForm is true and the page IsCallback property
244 Execute (handler, null, preserveForm);
245 context.Response.End ();
248 public void Execute (IHttpHandler handler, TextWriter writer, bool preserveForm)
251 throw new ArgumentNullException ("handler");
253 // If the target handler is not Page, the transfer must not occur.
254 // InTransit == true means we're being called from Transfer
255 if (context.InTransit && !(handler is Page))
256 throw new HttpException ("Transfer is possible only to .aspx files");
258 HttpRequest request = context.Request;
259 string oldQuery = request.QueryStringRaw;
261 request.QueryStringRaw = "";
264 HttpResponse response = context.Response;
265 WebROCollection oldForm = null;
267 oldForm = request.Form as WebROCollection;
268 request.SetForm (new WebROCollection ());
271 TextWriter output = writer;
273 output = response.Output;
275 TextWriter previous = null;
277 previous = response.SetTextWriter (output);
278 if (!(handler is IHttpAsyncHandler)) {
279 handler.ProcessRequest (context);
281 IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler) handler;
282 IAsyncResult ar = asyncHandler.BeginProcessRequest (context, null, null);
283 ar.AsyncWaitHandle.WaitOne ();
284 asyncHandler.EndProcessRequest (ar);
287 if (oldQuery != null && oldQuery != "" && oldQuery != request.QueryStringRaw) {
288 oldQuery = oldQuery.Substring (1); // Ignore initial '?'
289 request.QueryStringRaw = oldQuery; // which is added here.
291 response.SetTextWriter (previous);
293 request.SetForm (oldForm);
297 public static byte[] UrlTokenDecode (string input)
300 throw new ArgumentNullException ("input");
301 if (input.Length < 1)
303 byte[] bytes = Encoding.ASCII.GetBytes (input);
304 int inputLength = input.Length - 1;
305 int equalsCount = (int)(((char)bytes[inputLength]) - 0x30);
306 char[] ret = new char[inputLength + equalsCount];
308 for (; i < inputLength; i++) {
309 switch ((char)bytes[i]) {
319 ret[i] = (char)bytes[i];
323 while (equalsCount > 0) {
328 return Convert.FromBase64CharArray (ret, 0, ret.Length);
331 public static string UrlTokenEncode (byte[] input)
334 throw new ArgumentNullException ("input");
335 if (input.Length < 1)
337 string base64 = Convert.ToBase64String (input);
339 if (base64 == null || (retlen = base64.Length) == 0)
342 // MS.NET implementation seems to process the base64
343 // string before returning. It replaces the chars:
348 // Then removes trailing ==, which may appear in the
349 // base64 string, and replaces them with a single digit
350 // that's the count of removed '=' characters (0 if none
352 int equalsCount = 0x30;
353 while (retlen > 0 && base64[retlen - 1] == '=') {
357 char[] chars = new char[retlen + 1];
358 chars[retlen] = (char)equalsCount;
359 for (int i = 0; i < retlen; i++) {
370 chars[i] = base64[i];
374 return new string (chars);
378 public string UrlDecode (string s)
380 return HttpUtility.UrlDecode (s);
383 public void UrlDecode (string s, TextWriter output)
386 output.Write (HttpUtility.UrlDecode (s));
389 public string UrlEncode (string s)
391 return HttpUtility.UrlEncode (s);
394 public void UrlEncode (string s, TextWriter output)
397 output.Write (HttpUtility.UrlEncode (s));
400 public string UrlPathEncode (string s)
405 int idx = s.IndexOf ("?");
408 s2 = s.Substring (0, idx-1);
409 s2 = HttpUtility.UrlEncode (s2) + s.Substring (idx);
411 s2 = HttpUtility.UrlEncode (s);
417 public string MachineName {
418 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
419 // Medium doesn't look heavy enough to replace this... reported as
420 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
421 [EnvironmentPermission (SecurityAction.Assert, Read = "COMPUTERNAME")]
422 get { return Environment.MachineName; }
425 public int ScriptTimeout {
426 get { return (int) context.ConfigTimeout.TotalSeconds; }
427 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
428 set { context.ConfigTimeout = new TimeSpan (0, 0, value); }