2007-05-16 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web / HttpServerUtility.cs
1 //
2 // System.Web.HttpRequest.cs 
3 //
4 // 
5 // Author:
6 //      Miguel de Icaza (miguel@novell.com)
7 //      Gonzalo Paniagua Javier (gonzalo@novell.com)
8 //
9
10 //
11 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
12 //
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:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
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.
31 //
32
33 using System.IO;
34 using System.Web.UI;
35 using System.Web.Util;
36 using System.Collections.Specialized;
37 using System.Security.Permissions;
38 using System.Text;
39
40 namespace System.Web {
41
42         //
43         // Methods exposed through HttpContext.Server property
44         //
45         
46         // CAS - no InheritanceDemand here as the class is sealed
47         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
48         public sealed class HttpServerUtility {
49                 HttpContext context;
50                 
51                 internal HttpServerUtility (HttpContext context)
52                 {
53                         this.context = context;
54                 }
55
56                 public void ClearError ()
57                 {
58                         context.ClearError ();
59                 }
60
61                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
62                 public object CreateObject (string progID)
63                 {
64                         throw new HttpException (500, "COM is not supported");
65                 }
66
67                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
68                 public object CreateObject (Type type)
69                 {
70                         throw new HttpException (500, "COM is not supported");
71                 }
72
73                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
74                 public object CreateObjectFromClsid (string clsid)
75                 {
76                         throw new HttpException (500, "COM is not supported");
77                 }
78
79                 public void Execute (string path)
80                 {
81                         Execute (path, null, true);
82                 }
83
84                 public void Execute (string path, TextWriter writer)
85                 {
86                         Execute (path, writer, true);
87                 }
88
89 #if NET_2_0
90                 public void Execute (string path, bool preserveForm)
91                 {
92                         Execute (path, null, preserveForm);
93                 }
94 #endif
95                 
96 #if NET_2_0
97                 public
98 #else
99                 internal
100 #endif
101                 void Execute (string path, TextWriter writer, bool preserveForm)
102                 {
103                         if (path == null)
104                                 throw new ArgumentNullException ("path");
105
106                         if (path.IndexOf (':') != -1)
107                                 throw new ArgumentException ("Invalid path.");
108
109                         HttpRequest request = context.Request;
110                         string oldQuery = request.QueryStringRaw;
111                         int qmark = path.IndexOf ('?');
112                         if (qmark != -1) {
113                                 request.QueryStringRaw = path.Substring (qmark + 1);
114                                 path = path.Substring (0, qmark);
115                         } else if (!preserveForm) {
116                                 request.QueryStringRaw = "";
117                         }
118
119                         HttpResponse response = context.Response;
120                         WebROCollection oldForm = null;
121                         if (!preserveForm) {
122                                 oldForm = request.Form as WebROCollection;
123                                 request.SetForm (new WebROCollection ());
124                         }
125
126                         TextWriter output = writer;
127                         if (output == null)
128                                 output = response.Output;
129
130                         string oldFilePath = request.FilePath;
131                         request.SetCurrentExePath (UrlUtils.Combine (request.BaseVirtualDir, path));
132                         IHttpHandler handler = context.ApplicationInstance.GetHandler (context);
133                         TextWriter previous = null;
134                         try {
135 #if NET_2_0
136                                 context.PushHandler (handler);
137 #endif
138                                 previous = response.SetTextWriter (output);
139                                 if (!(handler is IHttpAsyncHandler)) {
140                                         handler.ProcessRequest (context);
141                                 } else {
142                                         IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler) handler;
143                                         IAsyncResult ar = asyncHandler.BeginProcessRequest (context, null, null);
144                                         ar.AsyncWaitHandle.WaitOne ();
145                                         asyncHandler.EndProcessRequest (ar);
146                                 }
147                         } finally {
148                                 request.SetCurrentExePath (oldFilePath);
149                                 if (oldQuery != null && oldQuery != "" && oldQuery != request.QueryStringRaw) {
150                                         oldQuery = oldQuery.Substring (1); // Ignore initial '?'
151                                         request.QueryStringRaw = oldQuery; // which is added here.
152                                 }
153                                 response.SetTextWriter (previous);
154                                 if (!preserveForm)
155                                         request.SetForm (oldForm);
156 #if NET_2_0
157                                 context.PopHandler ();
158 #endif
159                         }
160                 }
161
162                 public Exception GetLastError ()
163                 {
164                         if (context == null)
165                                 return HttpContext.Current.Error;
166                         return context.Error;
167                 }
168
169                 public string HtmlDecode (string s)
170                 {
171                         return HttpUtility.HtmlDecode (s);
172                 }
173
174                 public void HtmlDecode (string s, TextWriter output)
175                 {
176                         HttpUtility.HtmlDecode (s, output);
177                 }
178
179                 public string HtmlEncode (string s)
180                 {
181                         return HttpUtility.HtmlEncode (s);
182                 }
183
184                 public void HtmlEncode (string s, TextWriter output)
185                 {
186                         HttpUtility.HtmlEncode (s, output);
187                 }
188
189                 public string MapPath (string path)
190                 {
191                         return context.Request.MapPath (path);
192                 }
193
194                 public void Transfer (string path)
195                 {
196                         // If it's a page and a postback, don't pass form data
197                         // See bug #65613.
198                         bool preserveForm = true;
199                         if (context.Handler is Page) {
200                                 Page page = (Page) context.Handler;
201                                 preserveForm = !page.IsPostBack;
202                         }
203
204                         Transfer (path, preserveForm);
205                 }
206
207                 public void Transfer (string path, bool preserveForm)
208                 {
209                         Execute (path, null, preserveForm);
210                         context.Response.End ();
211                 }
212 #if NET_2_0
213                 [MonoTODO ("Not implemented")]
214                 public void Transfer (IHttpHandler handler, bool preserveForm)
215                 {
216                         if (handler == null)
217                                 throw new ArgumentNullException ("handler");
218
219                         // TODO: see the MS doc and search for "enableViewStateMac": this method is not
220                         // allowed for pages when preserveForm is true and the page IsCallback property
221                         // is true.
222
223                         Execute (handler, null, preserveForm);
224                         context.Response.End ();
225                 }
226
227                 public void Execute (IHttpHandler handler, TextWriter writer, bool preserveForm)
228                 {
229                         if (handler == null)
230                                 throw new ArgumentNullException ("handler");
231
232                         HttpRequest request = context.Request;
233                         string oldQuery = request.QueryStringRaw;
234                         if (!preserveForm) {
235                                 request.QueryStringRaw = "";
236                         }
237
238                         HttpResponse response = context.Response;
239                         WebROCollection oldForm = null;
240                         if (!preserveForm) {
241                                 oldForm = request.Form as WebROCollection;
242                                 request.SetForm (new WebROCollection ());
243                         }
244
245                         TextWriter output = writer;
246                         if (output == null)
247                                 output = response.Output;
248
249                         TextWriter previous = null;
250                         try {
251                                 previous = response.SetTextWriter (output);
252                                 if (!(handler is IHttpAsyncHandler)) {
253                                         handler.ProcessRequest (context);
254                                 } else {
255                                         IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler) handler;
256                                         IAsyncResult ar = asyncHandler.BeginProcessRequest (context, null, null);
257                                         ar.AsyncWaitHandle.WaitOne ();
258                                         asyncHandler.EndProcessRequest (ar);
259                                 }
260                         } finally {
261                                 if (oldQuery != null && oldQuery != "" && oldQuery != request.QueryStringRaw) {
262                                         oldQuery = oldQuery.Substring (1); // Ignore initial '?'
263                                         request.QueryStringRaw = oldQuery; // which is added here.
264                                 }
265                                 response.SetTextWriter (previous);
266                                 if (!preserveForm)
267                                         request.SetForm (oldForm);
268                         }
269                 }
270
271                 public static byte[] UrlTokenDecode (string input)
272                 {
273                         if (input == null)
274                                 throw new ArgumentNullException ("input");
275                         if (input.Length < 1)
276                                 return new byte[0];
277                         byte[] bytes = Encoding.ASCII.GetBytes (input);
278                         int inputLength = input.Length - 1;
279                         int equalsCount = (int)(((char)bytes[inputLength]) - 0x30);
280                         char[] ret = new char[inputLength + equalsCount];
281                         int i = 0;
282                         for (; i < inputLength; i++) {
283                                 switch ((char)bytes[i]) {
284                                         case '-':
285                                                 ret[i] = '+';
286                                                 break;
287
288                                         case '_':
289                                                 ret[i] = '/';
290                                                 break;
291
292                                         default:
293                                                 ret[i] = (char)bytes[i];
294                                                 break;
295                                 }
296                         }
297                         while (equalsCount > 0) {
298                                 ret[i++] = '=';
299                                 equalsCount--;
300                         }
301                         
302                         return Convert.FromBase64CharArray (ret, 0, ret.Length);
303                 }
304
305                 public static string UrlTokenEncode (byte[] input)
306                 {
307                         if (input == null)
308                                 throw new ArgumentNullException ("input");
309                         if (input.Length < 1)
310                                 return String.Empty;
311                         string base64 = Convert.ToBase64String (input);
312                         int retlen;
313                         if (base64 == null || (retlen = base64.Length) == 0)
314                                 return String.Empty;
315
316                         // MS.NET implementation seems to process the base64
317                         // string before returning. It replaces the chars:
318                         //
319                         //  + with -
320                         //  / with _
321                         //
322                         // Then removes trailing ==, which may appear in the
323                         // base64 string, and replaces them with a single digit
324                         // that's the count of removed '=' characters (0 if none
325                         // were removed)
326                         int equalsCount = 0x30;
327                         while (retlen > 0 && base64[retlen - 1] == '=') {
328                                 equalsCount++;
329                                 retlen--;
330                         }
331                         char[] chars = new char[retlen + 1];
332                         chars[retlen] = (char)equalsCount;
333                         for (int i = 0; i < retlen; i++) {
334                                 switch (base64[i]) {
335                                         case '+':
336                                                 chars[i] = '-';
337                                                 break;
338
339                                         case '/':
340                                                 chars[i] = '_';
341                                                 break;
342                                         
343                                         default:
344                                                 chars[i] = base64[i];
345                                                 break;
346                                 }
347                         }
348                         return new string (chars);
349                 }
350 #endif
351
352                 public string UrlDecode (string s)
353                 {
354                         return HttpUtility.UrlDecode (s);
355                 }
356
357                 public void UrlDecode (string s, TextWriter output)
358                 {
359                         if (s != null)
360                                 output.Write (HttpUtility.UrlDecode (s));
361                 }
362
363                 public string UrlEncode (string s)
364                 {
365                         return HttpUtility.UrlEncode (s);
366                 }
367
368                 public void UrlEncode (string s, TextWriter output)
369                 {
370                         if (s != null)
371                                 output.Write (HttpUtility.UrlEncode (s));
372                 }
373
374                 public string UrlPathEncode (string s)
375                 {
376                         if (s == null)
377                                 return null;
378
379                         int idx = s.IndexOf ("?");
380                         string s2 = null;
381                         if (idx != -1) {
382                                 s2 = s.Substring (0, idx-1);
383                                 s2 = HttpUtility.UrlEncode (s2) + s.Substring (idx);
384                         } else {
385                                 s2 = HttpUtility.UrlEncode (s);
386                         }
387
388                         return s2;
389                 }
390
391                 public string MachineName {
392                         [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
393                         // Medium doesn't look heavy enough to replace this... reported as
394                         [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
395                         [EnvironmentPermission (SecurityAction.Assert, Read = "COMPUTERNAME")]
396                         get { return Environment.MachineName; }
397                 }
398
399                 public int ScriptTimeout {
400                         get { return (int) context.ConfigTimeout.TotalSeconds; }
401                         [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
402                         set { context.ConfigTimeout = new TimeSpan (0, 0, value); }
403                 }
404         }
405 }