Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web / httpserverutility.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="httpserverutility.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 /*
8  * Server intrinsic used to match ASP's object model
9  *
10  * Copyright (c) 1999 Microsoft Corporation
11  */
12
13 // Don't entity encode high chars (160 to 256), to fix bugs VSWhidbey 85857/111927
14 // 
15 #define ENTITY_ENCODE_HIGH_ASCII_CHARS
16
17 namespace System.Web {
18     using System.Collections;
19     using System.Collections.Specialized;
20     using System.Globalization;
21     using System.IO;
22     using System.Security.Permissions;
23     using System.Text;
24     using System.Threading;
25     using System.Web.Configuration;
26     using System.Web.Hosting;
27     using System.Web.UI;
28     using System.Web.Util;
29
30     internal abstract class ErrorFormatterGenerator {
31         internal abstract ErrorFormatter GetErrorFormatter(Exception e);
32     }
33
34
35     /// <devdoc>
36     ///    <para>
37     ///       Provides several
38     ///       helper methods that can be used in the processing of Web requests.
39     ///    </para>
40     /// </devdoc>
41     public sealed class HttpServerUtility {
42         private HttpContext _context;
43         private HttpApplication _application;
44
45         private static IDictionary _cultureCache = Hashtable.Synchronized(new Hashtable());
46
47         internal HttpServerUtility(HttpContext context) {
48             _context = context;
49         }
50
51         internal HttpServerUtility(HttpApplication application) {
52             _application = application;
53         }
54
55         //
56         // Misc ASP compatibility methods
57         //
58
59
60         /// <devdoc>
61         ///    <para>
62         ///       Instantiates a COM object identified via a progid.
63         ///    </para>
64         /// </devdoc>
65         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
66         public object CreateObject(string progID) {
67             EnsureHasNotTransitionedToWebSocket();
68
69             Type type = null;
70             object obj = null;
71
72             try {
73 #if !FEATURE_PAL // FEATURE_PAL does not enable COM
74                 type = Type.GetTypeFromProgID(progID);
75 #else // !FEATURE_PAL
76                 throw new NotImplementedException("ROTORTODO");
77 #endif // !FEATURE_PAL
78             }
79             catch {
80             }
81
82             if (type == null) {
83                 throw new HttpException(SR.GetString(SR.Could_not_create_object_of_type, progID));
84             }
85
86             // Disallow Apartment components in non-compat mode
87             AspCompatApplicationStep.CheckThreadingModel(progID, type.GUID);
88
89             // Instantiate the object
90             obj = Activator.CreateInstance(type);
91
92             // For ASP compat: take care of OnPageStart/OnPageEnd
93             AspCompatApplicationStep.OnPageStart(obj);
94
95             return obj;
96         }
97
98
99         /// <devdoc>
100         ///    <para>
101         ///       Instantiates a COM object identified via a Type.
102         ///    </para>
103         /// </devdoc>
104         [SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
105         public object CreateObject(Type type) {
106             EnsureHasNotTransitionedToWebSocket();
107
108             // Disallow Apartment components in non-compat mode
109             AspCompatApplicationStep.CheckThreadingModel(type.FullName, type.GUID);
110
111             // Instantiate the object
112             Object obj = Activator.CreateInstance(type);
113
114             // For ASP compat: take care of OnPageStart/OnPageEnd
115             AspCompatApplicationStep.OnPageStart(obj);
116
117             return obj;
118         }
119
120
121
122         /// <devdoc>
123         ///    <para>
124         ///       Instantiates a COM object identified via a clsid.
125         ///    </para>
126         /// </devdoc>
127         [SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
128         public object CreateObjectFromClsid(string clsid) {
129             EnsureHasNotTransitionedToWebSocket();
130
131             Type type = null;
132             object obj = null;
133
134             // Create a Guid out of it
135             Guid guid = new Guid(clsid);
136
137             // Disallow Apartment components in non-compat mode
138             AspCompatApplicationStep.CheckThreadingModel(clsid, guid);
139
140             try {
141 #if !FEATURE_PAL // FEATURE_PAL does not enable COM
142                 type = Type.GetTypeFromCLSID(guid, null, true /*throwOnError*/);
143 #else // !FEATURE_PAL
144                 throw new NotImplementedException("ROTORTODO");
145 #endif // !FEATURE_PAL
146
147                 // Instantiate the object
148                 obj = Activator.CreateInstance(type);
149             }
150             catch {
151             }
152
153             if (obj == null) {
154                 throw new HttpException(
155                     SR.GetString(SR.Could_not_create_object_from_clsid, clsid));
156             }
157
158             // For ASP compat: take care of OnPageStart/OnPageEnd
159             AspCompatApplicationStep.OnPageStart(obj);
160
161             return obj;
162         }
163
164         // Internal static method that returns a read-only, non-user override accounted, CultureInfo object
165         internal static CultureInfo CreateReadOnlyCultureInfo(string name) {
166             if (!_cultureCache.Contains(name)) {
167                 // To be threadsafe, get the lock before creating
168                 lock (_cultureCache) {
169                     if (_cultureCache[name] == null) {
170                         _cultureCache[name] = CultureInfo.ReadOnly(new CultureInfo(name));
171                     }
172                 }
173             }
174             return (CultureInfo)_cultureCache[name];
175         }
176
177         // Internal static method that returns a read-only, non-user override accounted, culture specific CultureInfo object
178         internal static CultureInfo CreateReadOnlySpecificCultureInfo(string name) {
179             if(name.IndexOf('-') > 0) {
180                 return CreateReadOnlyCultureInfo(name);
181             }
182             CultureInfo ci = CultureInfo.CreateSpecificCulture(name);
183             if (!_cultureCache.Contains(ci.Name)) {
184                 //To be threadsafe, get the lock before creating
185                 lock (_cultureCache) {
186                     if (_cultureCache[ci.Name] == null) {
187                         _cultureCache[ci.Name] = CultureInfo.ReadOnly(ci);
188                     }
189                 }
190             }
191             return (CultureInfo)_cultureCache[ci.Name];
192         }
193
194         // Internal static method that returns a read-only, non-user override accounted, CultureInfo object
195         internal static CultureInfo CreateReadOnlyCultureInfo(int culture) {
196             if (!_cultureCache.Contains(culture)) {
197                 // To be threadsafe, get the lock before creating
198                 lock (_cultureCache) {
199                     if (_cultureCache[culture] == null) {
200                         _cultureCache[culture] = CultureInfo.ReadOnly(new CultureInfo(culture));
201                     }
202                 }
203             }
204             return (CultureInfo)_cultureCache[culture];
205         }
206
207         /// <devdoc>
208         ///    <para>
209         ///       Maps a virtual path to a physical path.
210         ///    </para>
211         /// </devdoc>
212         public string MapPath(string path) {
213             if (_context == null)
214                 throw new HttpException(SR.GetString(SR.Server_not_available));
215             // Disable hiding the request so that Server.MapPath works when called from
216             // Application_Start in integrated mode
217             bool unhideRequest = _context.HideRequestResponse;
218             string realPath;
219             try {
220                 if (unhideRequest) {
221                     _context.HideRequestResponse = false;
222                 }
223                 realPath = _context.Request.MapPath(path);
224             }
225             finally {
226                 if (unhideRequest) {
227                     _context.HideRequestResponse = true;
228                 }
229             }
230             return realPath;
231         }
232
233
234         /// <devdoc>
235         ///    <para>Returns the last recorded exception.</para>
236         /// </devdoc>
237         public Exception GetLastError() {
238             if (_context != null)
239                 return _context.Error;
240             else if (_application != null)
241                 return _application.LastError;
242             else
243                 return null;
244         }
245
246
247         /// <devdoc>
248         ///    <para>Clears the last error.</para>
249         /// </devdoc>
250         public void ClearError() {
251             if (_context != null)
252                 _context.ClearError();
253             else if (_application != null)
254                 _application.ClearError();
255         }
256
257         //
258         // Server.Transfer/Server.Execute -- child requests
259         //
260
261
262         /// <devdoc>
263         ///    <para>
264         ///       Executes a new request (using the specified URL path as the target). Unlike
265         ///       the Transfer method, execution of the original page continues after the executed
266         ///       page completes.
267         ///    </para>
268         /// </devdoc>
269         public void Execute(string path) {
270             Execute(path, null, true /*preserveForm*/);
271         }
272
273
274         /// <devdoc>
275         ///    <para>
276         ///       Executes a new request (using the specified URL path as the target). Unlike
277         ///       the Transfer method, execution of the original page continues after the executed
278         ///       page completes.
279         ///    </para>
280         /// </devdoc>
281         public void Execute(string path, TextWriter writer) {
282             Execute(path, writer, true /*preserveForm*/);
283         }
284
285
286         /// <devdoc>
287         ///    <para>
288         ///       Executes a new request (using the specified URL path as the target). Unlike
289         ///       the Transfer method, execution of the original page continues after the executed
290         ///       page completes.
291         ///       If preserveForm is false, the QueryString and Form collections are cleared.
292         ///    </para>
293         /// </devdoc>
294         public void Execute(string path, bool preserveForm) {
295             Execute(path, null, preserveForm);
296         }
297
298
299         /// <devdoc>
300         ///    <para>
301         ///       Executes a new request (using the specified URL path as the target). Unlike
302         ///       the Transfer method, execution of the original page continues after the executed
303         ///       page completes.
304         ///       If preserveForm is false, the QueryString and Form collections are cleared.
305         ///    </para>
306         /// </devdoc>
307         public void Execute(string path, TextWriter writer, bool preserveForm) {
308             EnsureHasNotTransitionedToWebSocket();
309
310             if (_context == null)
311                 throw new HttpException(SR.GetString(SR.Server_not_available));
312
313             if (path == null)
314                 throw new ArgumentNullException("path");
315
316             string queryStringOverride = null;
317             HttpRequest request = _context.Request;
318             HttpResponse response = _context.Response;
319
320             // Remove potential cookie-less session id (ASURT 100558)
321             path = response.RemoveAppPathModifier(path);
322
323             // Allow query string override
324             int iqs = path.IndexOf('?');
325             if (iqs >= 0) {
326                 queryStringOverride = path.Substring(iqs+1);
327                 path = path.Substring(0, iqs);
328             }
329
330             if (!UrlPath.IsValidVirtualPathWithoutProtocol(path)) {
331                 throw new ArgumentException(SR.GetString(SR.Invalid_path_for_child_request, path));
332             }
333
334             VirtualPath virtualPath = VirtualPath.Create(path);
335
336             // Find the handler for the path
337
338             IHttpHandler handler = null;
339
340             string physPath = request.MapPath(virtualPath);        // get physical path
341             VirtualPath filePath = request.FilePathObject.Combine(virtualPath);    // vpath
342
343             // Demand read access to the physical path of the target handler
344             InternalSecurityPermissions.FileReadAccess(physPath).Demand();
345
346             // We need to Assert since there typically is user code on the stack (VSWhidbey 270965)
347             if (HttpRuntime.IsLegacyCas) {
348                 InternalSecurityPermissions.Unrestricted.Assert();
349             }
350
351             try {
352                 // paths that ends with . are disallowed as they are used to get around
353                 // extension mappings and server source as static file
354                 if (StringUtil.StringEndsWith(virtualPath.VirtualPathString, '.'))
355                     throw new HttpException(404, String.Empty);
356
357                 bool useAppConfig = !filePath.IsWithinAppRoot;
358
359                 using (new DisposableHttpContextWrapper(_context)) {
360
361                     try {
362                         // We need to increase the depth when calling MapHttpHandler,
363                         // since PageHandlerFactory relies on it
364                         _context.ServerExecuteDepth++;
365                         
366                         if (_context.WorkerRequest is IIS7WorkerRequest) {
367                             handler = _context.ApplicationInstance.MapIntegratedHttpHandler(
368                                 _context,
369                                 request.RequestType,
370                                 filePath,
371                                 physPath,
372                                 useAppConfig,
373                                 true /*convertNativeStaticFileModule*/);
374                         }
375                         else {
376                             handler = _context.ApplicationInstance.MapHttpHandler(
377                                 _context,
378                                 request.RequestType,
379                                 filePath,
380                                 physPath,
381                                 useAppConfig);
382                         }
383                     }
384                     finally {
385                         _context.ServerExecuteDepth--;
386                     }
387                 }
388             }
389             catch (Exception e) {
390                 // 500 errors (compilation errors) get preserved
391                 if (e is HttpException) {
392                     int code = ((HttpException)e).GetHttpCode();
393
394                     if (code != 500 && code != 404) {
395                         e = null;
396                     }
397                 }
398
399                 throw new HttpException(SR.GetString(SR.Error_executing_child_request_for_path, path), e);
400             }
401
402             ExecuteInternal(handler, writer, preserveForm, true /*setPreviousPage*/,
403                 virtualPath, filePath, physPath, null, queryStringOverride);
404         }
405
406
407         public void Execute(IHttpHandler handler, TextWriter writer, bool preserveForm) {
408             if (_context == null)
409                 throw new HttpException(SR.GetString(SR.Server_not_available));
410
411             Execute(handler, writer, preserveForm, true /*setPreviousPage*/);
412         }
413
414         internal void Execute(IHttpHandler handler, TextWriter writer, bool preserveForm, bool setPreviousPage) {
415             HttpRequest request = _context.Request;
416             VirtualPath filePath = request.CurrentExecutionFilePathObject;
417             string physicalPath = request.MapPath(filePath);
418
419             ExecuteInternal(handler, writer, preserveForm, setPreviousPage,
420                 null, filePath, physicalPath, null, null);
421         }
422
423         private void ExecuteInternal(IHttpHandler handler, TextWriter writer, bool preserveForm, bool setPreviousPage,
424             VirtualPath path, VirtualPath filePath, string physPath, Exception error, string queryStringOverride) {
425
426             EnsureHasNotTransitionedToWebSocket();
427
428             if (handler == null)
429                 throw new ArgumentNullException("handler");
430
431             HttpRequest request = _context.Request;
432             HttpResponse response = _context.Response;
433             HttpApplication app = _context.ApplicationInstance;
434
435             HttpValueCollection savedForm = null;
436             VirtualPath savedCurrentExecutionFilePath = null;
437             string savedQueryString = null;
438             TextWriter savedOutputWriter = null;
439             AspNetSynchronizationContextBase savedSyncContext = null;
440
441             // Transaction wouldn't flow into ASPCOMPAT mode -- need to report an error
442             VerifyTransactionFlow(handler);
443
444             // create new trace context
445             _context.PushTraceContext();
446
447             // set the new handler as the current handler
448             _context.SetCurrentHandler(handler);
449
450             // because we call this synchrnously async operations must be disabled
451             bool originalSyncContextWasEnabled = _context.SyncContext.Enabled;
452             _context.SyncContext.Disable();
453
454             // Execute the handler
455             try {
456                 try {
457                     _context.ServerExecuteDepth++;
458
459                     savedCurrentExecutionFilePath = request.SwitchCurrentExecutionFilePath(filePath);
460
461                     if (!preserveForm) {
462                         savedForm = request.SwitchForm(new HttpValueCollection());
463
464                         // Clear out the query string, but honor overrides
465                         if (queryStringOverride == null)
466                             queryStringOverride = String.Empty;
467                     }
468
469                     // override query string if requested
470                     if (queryStringOverride != null) {
471                         savedQueryString = request.QueryStringText;
472                         request.QueryStringText = queryStringOverride;
473                     }
474
475                     // capture output if requested
476                     if (writer != null)
477                         savedOutputWriter = response.SwitchWriter(writer);
478
479                     Page targetPage = handler as Page;
480                     if (targetPage != null) {
481                         if (setPreviousPage) {
482                             // Set the previousPage of the new Page as the previous Page
483                             targetPage.SetPreviousPage(_context.PreviousHandler as Page);
484                         }
485
486                         Page sourcePage = _context.Handler as Page;
487
488 #pragma warning disable 0618    // To avoid deprecation warning
489                         // If the source page of the transfer has smart nav on,
490                         // always do as if the destination has it too (ASURT 97732)
491                         if (sourcePage != null && sourcePage.SmartNavigation)
492                             targetPage.SmartNavigation = true;
493 #pragma warning restore 0618
494
495                         // If the target page is async need to save/restore sync context
496                         if (targetPage is IHttpAsyncHandler) {
497                             savedSyncContext = _context.InstallNewAspNetSynchronizationContext();
498                         }
499                     }
500
501                     if ((handler is StaticFileHandler || handler is DefaultHttpHandler) &&
502                        !DefaultHttpHandler.IsClassicAspRequest(filePath.VirtualPathString)) {
503                         // cannot apply static files handler directly
504                         // -- it would dump the source of the current page
505                         // instead just dump the file content into response
506                         try {
507                             response.WriteFile(physPath);
508                         }
509                         catch {
510                             // hide the real error as it could be misleading
511                             // in case of mismapped requests like /foo.asmx/bar
512                             error = new HttpException(404, String.Empty);
513                         }
514                     }
515                     else if (!(handler is Page)) {
516                         // disallow anything but pages
517                         error = new HttpException(404, String.Empty);
518                     }
519                     else if (handler is IHttpAsyncHandler) {
520                         // Asynchronous handler
521
522                         // suspend cancellable period (don't abort this thread while
523                         // we wait for another to finish)
524                         bool isCancellable =  _context.IsInCancellablePeriod;
525                         if (isCancellable)
526                             _context.EndCancellablePeriod();
527
528                         try {
529                             IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)handler;
530
531                             if (!AppSettings.UseTaskFriendlySynchronizationContext) {
532                                 // Legacy code path: behavior ASP.NET <= 4.0
533
534                                 IAsyncResult ar = asyncHandler.BeginProcessRequest(_context, null, null);
535
536                                 // wait for completion
537                                 if (!ar.IsCompleted) {
538                                     // suspend app lock while waiting
539                                     bool needToRelock = false;
540
541                                     try {
542                                         try { }
543                                         finally {
544                                             _context.SyncContext.DisassociateFromCurrentThread();
545                                             needToRelock = true;
546                                         }
547
548                                         WaitHandle h = ar.AsyncWaitHandle;
549
550                                         if (h != null) {
551                                             h.WaitOne();
552                                         }
553                                         else {
554                                             while (!ar.IsCompleted)
555                                                 Thread.Sleep(1);
556                                         }
557                                     }
558                                     finally {
559                                         if (needToRelock) {
560                                             _context.SyncContext.AssociateWithCurrentThread();
561                                         }
562                                     }
563                                 }
564
565                                 // end the async operation (get error if any)
566
567                                 try {
568                                     asyncHandler.EndProcessRequest(ar);
569                                 }
570                                 catch (Exception e) {
571                                     error = e;
572                                 }
573                             }
574                             else {
575                                 // New code path: behavior ASP.NET >= 4.5
576                                 IAsyncResult ar;
577                                 bool blockedThread;
578
579                                 using (CountdownEvent countdownEvent = new CountdownEvent(1)) {
580                                     using (_context.SyncContext.AcquireThreadLock()) {
581                                         // Kick off the asynchronous operation
582                                         ar = asyncHandler.BeginProcessRequest(_context,
583                                            cb: _ => { countdownEvent.Signal(); },
584                                            extraData: null);
585                                     }
586
587                                     // The callback passed to BeginProcessRequest will signal the CountdownEvent.
588                                     // The Wait() method blocks until the callback executes; no-ops if the operation completed synchronously.
589                                     blockedThread = !countdownEvent.IsSet;
590                                     countdownEvent.Wait();
591                                 }
592
593                                 // end the async operation (get error if any)
594
595                                 try {
596                                     using (_context.SyncContext.AcquireThreadLock()) {
597                                         asyncHandler.EndProcessRequest(ar);
598                                     }
599
600                                     // If we blocked the thread, YSOD the request to display a diagnostic message.
601                                     if (blockedThread && !_context.SyncContext.AllowAsyncDuringSyncStages) {
602                                         throw new InvalidOperationException(SR.GetString(SR.Server_execute_blocked_on_async_handler));
603                                     }
604                                 }
605                                 catch (Exception e) {
606                                     error = e;
607                                 }
608                             }
609                         }
610                         finally {
611                             // resume cancelleable period
612                             if (isCancellable)
613                                 _context.BeginCancellablePeriod();
614                         }
615                     }
616                     else {
617                         // Synchronous handler
618
619                         using (new DisposableHttpContextWrapper(_context)) {
620                             try {
621                                 handler.ProcessRequest(_context);
622                             }
623                             catch (Exception e) {
624                                 error = e;
625                             }
626                         }
627                     }
628                 }
629                 finally {
630                     _context.ServerExecuteDepth--;
631
632                     // Restore the handlers;
633                     _context.RestoreCurrentHandler();
634
635                     // restore output writer
636                     if (savedOutputWriter != null)
637                         response.SwitchWriter(savedOutputWriter);
638
639                     // restore overriden query string
640                     if (queryStringOverride != null && savedQueryString != null)
641                         request.QueryStringText = savedQueryString;
642
643                     if (savedForm != null)
644                         request.SwitchForm(savedForm);
645
646                     request.SwitchCurrentExecutionFilePath(savedCurrentExecutionFilePath);
647
648                     if (savedSyncContext != null) {
649                         _context.RestoreSavedAspNetSynchronizationContext(savedSyncContext);
650                     }
651
652                     if (originalSyncContextWasEnabled) {
653                         _context.SyncContext.Enable();
654                     }
655
656                     // restore trace context
657                     _context.PopTraceContext();
658                 }
659             }
660             catch { // Protect against exception filters
661                 throw;
662             }
663
664             // Report any error
665             if (error != null) {
666                 // suppress errors with HTTP codes (for child requests they mislead more than help)
667                 if (error is HttpException && ((HttpException)error).GetHttpCode() != 500)
668                     error = null;
669
670                 if (path != null)
671                     throw new HttpException(SR.GetString(SR.Error_executing_child_request_for_path, path), error);
672
673                 throw new HttpException(SR.GetString(SR.Error_executing_child_request_for_handler, handler.GetType().ToString()), error);
674             }
675         }
676
677
678         /// <devdoc>
679         ///    <para>
680         ///       Terminates execution of the current page and begins execution of a new
681         ///       request using the supplied URL path.
682         ///       If preserveForm is false, the QueryString and Form collections are cleared.
683         ///    </para>
684         /// </devdoc>
685         public void Transfer(string path, bool preserveForm) {
686             Page page = _context.Handler as Page;
687             if ((page != null) && page.IsCallback) {
688                 throw new ApplicationException(SR.GetString(SR.Transfer_not_allowed_in_callback));
689             }
690             
691             // execute child request
692
693             Execute(path, null, preserveForm);
694
695             // suppress the remainder of the current one
696
697             _context.Response.End();
698         }
699
700
701         /// <devdoc>
702         ///    <para>
703         ///       Terminates execution of the current page and begins execution of a new
704         ///       request using the supplied URL path.
705         ///    </para>
706         /// </devdoc>
707         public void Transfer(string path) {
708             // Make sure the transfer is not treated as a postback, which could cause a stack
709             // overflow if the user doesn't expect it (VSWhidbey 181013).
710             // If the use *does* want it treated as a postback, they can call Transfer(path, true).
711             bool savedPreventPostback = _context.PreventPostback;
712             _context.PreventPostback = true;
713
714             Transfer(path, true /*preserveForm*/);
715
716             _context.PreventPostback = savedPreventPostback;
717         }
718
719
720         public void Transfer(IHttpHandler handler, bool preserveForm) {
721             Page page = handler as Page;
722             if ((page != null) && page.IsCallback) {
723                 throw new ApplicationException(SR.GetString(SR.Transfer_not_allowed_in_callback));
724             }
725             
726             Execute(handler, null, preserveForm);
727
728             // suppress the remainder of the current one
729
730             _context.Response.End();
731         }
732
733         public void TransferRequest(string path)
734         {
735             TransferRequest(path, false, null, null, preserveUser: true);
736         }
737
738         public void TransferRequest(string path, bool preserveForm)
739         {
740             TransferRequest(path, preserveForm, null, null, preserveUser: true);
741         }
742
743         public void TransferRequest(string path, bool preserveForm, string method, NameValueCollection headers) {
744             TransferRequest(path, preserveForm, method, headers, preserveUser: true);
745         }
746
747         public void TransferRequest(string path, bool preserveForm, string method, NameValueCollection headers, bool preserveUser) {
748             EnsureHasNotTransitionedToWebSocket();
749
750             if (!HttpRuntime.UseIntegratedPipeline) {
751                 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
752             }
753
754             if (_context == null) {
755                 throw new HttpException(SR.GetString(SR.Server_not_available));
756             }
757
758             if (path == null) {
759                 throw new ArgumentNullException("path");
760             }
761
762             IIS7WorkerRequest wr = _context.WorkerRequest as IIS7WorkerRequest;
763             HttpRequest request = _context.Request;
764             HttpResponse response = _context.Response;
765
766             if (wr == null) {
767                 throw new HttpException(SR.GetString(SR.Server_not_available));            
768             }
769                 
770             // Remove potential cookie-less session id (ASURT 100558)
771             path = response.RemoveAppPathModifier(path);
772
773             // Extract query string if specified
774             String qs = null;
775             int iqs = path.IndexOf('?');
776             if (iqs >= 0) {
777                 qs = (iqs < path.Length-1) ? path.Substring(iqs+1) : String.Empty;
778                 path = path.Substring(0, iqs);   
779             }
780
781             if (!UrlPath.IsValidVirtualPathWithoutProtocol(path)) {
782                 throw new ArgumentException(SR.GetString(SR.Invalid_path_for_child_request, path));
783             }
784
785             VirtualPath virtualPath = request.FilePathObject.Combine(VirtualPath.Create(path));
786
787             //  Schedule the child execution
788             wr.ScheduleExecuteUrl( virtualPath.VirtualPathString,
789                                    qs,
790                                    method,
791                                    preserveForm,
792                                    preserveForm ? request.EntityBody : null,
793                                    headers,
794                                    preserveUser);
795             
796             // force the completion of the current request so that the 
797             // child execution can be performed immediately after unwind
798             _context.ApplicationInstance.EnsureReleaseState();
799
800             // DevDiv Bugs 162750: IIS7 Integrated Mode:  TransferRequest performance issue
801             // Instead of calling Response.End we call HttpApplication.CompleteRequest()
802             _context.ApplicationInstance.CompleteRequest();
803         }
804
805         private void VerifyTransactionFlow(IHttpHandler handler) {
806             Page topPage = _context.Handler as Page;
807             Page childPage = handler as Page;
808
809             if (childPage != null && childPage.IsInAspCompatMode && // child page aspcompat
810                 topPage != null && !topPage.IsInAspCompatMode &&    // top page is not aspcompat
811                 Transactions.Utils.IsInTransaction) {               // we are in transaction
812
813                 throw new HttpException(SR.GetString(SR.Transacted_page_calls_aspcompat));
814             }
815         }
816
817         //
818         // Static method to execute a request outside of HttpContext and capture the response
819         //
820
821         internal static void ExecuteLocalRequestAndCaptureResponse(String path, TextWriter writer,
822                                                                 ErrorFormatterGenerator errorFormatterGenerator) {
823             HttpRequest request = new HttpRequest(
824                                           VirtualPath.CreateAbsolute(path),
825                                           String.Empty);
826
827             HttpResponse response = new HttpResponse(writer);
828
829             HttpContext context = new HttpContext(request, response);
830
831             HttpApplication app = HttpApplicationFactory.GetApplicationInstance(context) as HttpApplication;
832             context.ApplicationInstance = app;
833
834             try {
835                 context.Server.Execute(path);
836             }
837             catch (HttpException e) {
838                 if (errorFormatterGenerator != null) {
839                     context.Response.SetOverrideErrorFormatter(errorFormatterGenerator.GetErrorFormatter(e));
840                 }
841
842                 context.Response.ReportRuntimeError(e, false, true);
843             }
844             finally {
845                 if (app != null) {
846                     context.ApplicationInstance = null;
847                     HttpApplicationFactory.RecycleApplicationInstance(app);
848                 }
849             }
850         }
851
852         //
853         // Computer name
854         //
855
856         private static object _machineNameLock = new object();
857         private static string _machineName;
858         private const int _maxMachineNameLength = 256;
859
860
861         /// <devdoc>
862         ///    <para>
863         ///       Gets
864         ///       the server machine name.
865         ///    </para>
866         /// </devdoc>
867         public string MachineName {
868             [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
869             get {
870                 return GetMachineNameInternal();
871             }
872         }
873
874         internal static string GetMachineNameInternal()
875         {
876             if (_machineName != null)
877                 return _machineName;
878             lock (_machineNameLock)
879             {
880                 if (_machineName != null)
881                     return _machineName;
882
883                 StringBuilder   buf = new StringBuilder (_maxMachineNameLength);
884                 int             len = _maxMachineNameLength;
885
886                 if (UnsafeNativeMethods.GetComputerName (buf, ref len) == 0)
887                     throw new HttpException (SR.GetString(SR.Get_computer_name_failed));
888
889                 _machineName = buf.ToString();
890             }
891             return _machineName;
892         }
893
894         //
895         // Request Timeout
896         //
897
898
899         /// <devdoc>
900         ///    <para>
901         ///       Request timeout in seconds
902         ///    </para>
903         /// </devdoc>
904         public int ScriptTimeout {
905             get {
906                 if (_context != null) {
907                     return Convert.ToInt32(_context.Timeout.TotalSeconds);
908                 }
909                 else {
910                     return HttpRuntimeSection.DefaultExecutionTimeout;
911                 }
912             }
913
914             [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
915             set {
916                 if (_context == null)
917                     throw new HttpException(SR.GetString(SR.Server_not_available));
918                 if (value <= 0)
919                     throw new ArgumentOutOfRangeException("value");
920                 _context.Timeout = new TimeSpan(0, 0, value);
921             }
922         }
923
924         //
925         // Encoding / Decoding -- wrappers for HttpUtility
926         //
927
928
929         /// <devdoc>
930         ///    <para>
931         ///       HTML
932         ///       decodes a given string and
933         ///       returns the decoded string.
934         ///    </para>
935         /// </devdoc>
936         public string HtmlDecode(string s) {
937             return HttpUtility.HtmlDecode(s);
938         }
939
940
941         /// <devdoc>
942         ///    <para>
943         ///       HTML
944         ///       decode a string and send the result to a TextWriter output
945         ///       stream.
946         ///    </para>
947         /// </devdoc>
948         public void HtmlDecode(string s, TextWriter output) {
949             HttpUtility.HtmlDecode(s, output);
950         }
951
952
953         /// <devdoc>
954         ///    <para>
955         ///       HTML
956         ///       encodes a given string and
957         ///       returns the encoded string.
958         ///    </para>
959         /// </devdoc>
960         public string HtmlEncode(string s) {
961             return HttpUtility.HtmlEncode(s);
962         }
963
964
965         /// <devdoc>
966         ///    <para>
967         ///       HTML
968         ///       encodes
969         ///       a string and returns the output to a TextWriter stream of output.
970         ///    </para>
971         /// </devdoc>
972         public void HtmlEncode(string s, TextWriter output) {
973             HttpUtility.HtmlEncode(s, output);
974         }
975
976
977         /// <devdoc>
978         ///    <para>
979         ///       URL
980         ///       encodes a given
981         ///       string and returns the encoded string.
982         ///    </para>
983         /// </devdoc>
984         public string UrlEncode(string s) {
985             Encoding e = (_context != null) ? _context.Response.ContentEncoding : Encoding.UTF8;
986             return HttpUtility.UrlEncode(s, e);
987         }
988
989
990         /// <devdoc>
991         ///    <para>
992         ///       URL encodes a path portion of a URL string and returns the encoded string.
993         ///    </para>
994         /// </devdoc>
995         public string UrlPathEncode(string s) {
996             return HttpUtility.UrlPathEncode(s);
997         }
998
999
1000         /// <devdoc>
1001         ///    <para>
1002         ///       URL
1003         ///       encodes
1004         ///       a string and returns the output to a TextWriter output stream.
1005         ///    </para>
1006         /// </devdoc>
1007         public void UrlEncode(string s, TextWriter output) {
1008             if (s != null)
1009                 output.Write(UrlEncode(s));
1010         }
1011
1012
1013         /// <devdoc>
1014         ///    <para>
1015         ///       URL decodes a string and returns the output in a string.
1016         ///    </para>
1017         /// </devdoc>
1018         public string UrlDecode(string s) {
1019             Encoding e = (_context != null) ? _context.Request.ContentEncoding : Encoding.UTF8;
1020             return HttpUtility.UrlDecode(s, e);
1021         }
1022
1023
1024         /// <devdoc>
1025         ///    <para>
1026         ///       URL decodes a string and returns the output as a TextWriter output
1027         ///       stream.
1028         ///    </para>
1029         /// </devdoc>
1030         public void UrlDecode(string s, TextWriter output) {
1031             if (s != null)
1032                 output.Write(UrlDecode(s));
1033         }
1034
1035         /////////////////////////////////////////////////////////////////////////////
1036         /////////////////////////////////////////////////////////////////////////////
1037         /////////////////////////////////////////////////////////////////////////////
1038
1039         static public string UrlTokenEncode(byte [] input)
1040         {
1041             return HttpEncoder.Current.UrlTokenEncode(input);
1042         }
1043
1044         /////////////////////////////////////////////////////////////////////////////
1045         /////////////////////////////////////////////////////////////////////////////
1046         /////////////////////////////////////////////////////////////////////////////
1047
1048         static public byte [] UrlTokenDecode(string input) {
1049             return HttpEncoder.Current.UrlTokenDecode(input);
1050         }
1051
1052         // helper that throws an exception if we have transitioned the current request to a WebSocket request
1053         internal void EnsureHasNotTransitionedToWebSocket() {
1054             if (_context != null) {
1055                 _context.EnsureHasNotTransitionedToWebSocket();
1056             }
1057         }
1058     }
1059
1060
1061     /// <devdoc>
1062     /// </devdoc>
1063
1064     // VSWhidbey 473228 - removed link demand from HttpUtility for ClickOnce scenario
1065     public sealed class HttpUtility {
1066
1067         public HttpUtility () {}
1068                 
1069                 //////////////////////////////////////////////////////////////////////////
1070         //
1071         //  HTML Encoding / Decoding
1072         //
1073
1074
1075         /// <devdoc>
1076         ///    <para>
1077         ///       HTML decodes a string and returns the decoded string.
1078         ///    </para>
1079         /// </devdoc>
1080         public static string HtmlDecode(string s) {
1081             return HttpEncoder.Current.HtmlDecode(s);
1082         }
1083
1084
1085         /// <devdoc>
1086         ///    <para>
1087         ///       HTML decode a string and send the result to a TextWriter output stream.
1088         ///    </para>
1089         /// </devdoc>
1090         public static void HtmlDecode(string s, TextWriter output) {
1091             HttpEncoder.Current.HtmlDecode(s, output);
1092         }
1093
1094
1095         /// <devdoc>
1096         ///    <para>
1097         ///       HTML encodes a string and returns the encoded string.
1098         ///    </para>
1099         /// </devdoc>
1100         public static String HtmlEncode(String s) {
1101             return HttpEncoder.Current.HtmlEncode(s);
1102         }
1103
1104
1105         /// <devdoc>
1106         ///    <para>
1107         ///       HTML encodes an object's string representation and returns the encoded string.
1108         ///       If the object implements IHtmlString, don't encode it
1109         ///    </para>
1110         /// </devdoc>
1111         public static String HtmlEncode(object value) {
1112             if (value == null) {
1113                 // Return null to be consistent with HtmlEncode(string)
1114                 return null;
1115             }
1116
1117             var htmlString = value as IHtmlString;
1118             if (htmlString != null) {
1119                 return htmlString.ToHtmlString();
1120             }
1121
1122             return HtmlEncode(Convert.ToString(value, CultureInfo.CurrentCulture));
1123         }
1124
1125
1126         /// <devdoc>
1127         ///    <para>
1128         ///       HTML encodes a string and returns the output to a TextWriter stream of
1129         ///       output.
1130         ///    </para>
1131         /// </devdoc>
1132         public static void HtmlEncode(String s, TextWriter output) {
1133             HttpEncoder.Current.HtmlEncode(s, output);
1134         }
1135
1136
1137         /// <devdoc>
1138         ///    <para>
1139         ///       Encodes a string to make it a valid HTML attribute and returns the encoded string.
1140         ///    </para>
1141         /// </devdoc>
1142         public static String HtmlAttributeEncode(String s) {
1143             return HttpEncoder.Current.HtmlAttributeEncode(s);
1144         }
1145                 
1146
1147         /// <devdoc>
1148         ///    <para>
1149         ///       Encodes a string to make it a valid HTML attribute and returns the output
1150         ///       to a TextWriter stream of
1151         ///       output.
1152         ///    </para>
1153         /// </devdoc>
1154         public static void HtmlAttributeEncode(String s, TextWriter output) {
1155             HttpEncoder.Current.HtmlAttributeEncode(s, output);
1156         }
1157
1158         
1159         internal static string FormatPlainTextSpacesAsHtml(string s) {
1160             if (s == null) {
1161                 return null;
1162             }
1163
1164             StringBuilder builder = new StringBuilder();
1165             StringWriter writer = new StringWriter(builder);
1166
1167             int cb = s.Length;
1168
1169             for (int i = 0; i < cb; i++) {
1170                 char ch = s[i];
1171                 if(ch == ' ') {
1172                     writer.Write("&nbsp;");
1173                 }
1174                 else {
1175                     writer.Write(ch);
1176                 }
1177             }
1178             return builder.ToString();
1179         }
1180
1181         internal static String FormatPlainTextAsHtml(String s) {
1182             if (s == null)
1183                 return null;
1184
1185             StringBuilder builder = new StringBuilder();
1186             StringWriter writer = new StringWriter(builder);
1187
1188             FormatPlainTextAsHtml(s, writer);
1189
1190             return builder.ToString();
1191         }
1192
1193         internal static void FormatPlainTextAsHtml(String s, TextWriter output) {
1194             if (s == null)
1195                 return;
1196
1197             int cb = s.Length;
1198
1199             char prevCh = '\0';
1200
1201             for (int i=0; i<cb; i++) {
1202                 char ch = s[i];
1203                 switch (ch) {
1204                     case '<':
1205                         output.Write("&lt;");
1206                         break;
1207                     case '>':
1208                         output.Write("&gt;");
1209                         break;
1210                     case '"':
1211                         output.Write("&quot;");
1212                         break;
1213                     case '&':
1214                         output.Write("&amp;");
1215                         break;
1216                     case ' ':
1217                         if (prevCh == ' ')
1218                             output.Write("&nbsp;");
1219                         else
1220                             output.Write(ch);
1221                         break;
1222                     case '\r':
1223                         // Ignore \r, only handle \n
1224                         break;
1225                     case '\n':
1226                         output.Write("<br>");
1227                         break;
1228
1229                     // 
1230                     default:
1231 #if ENTITY_ENCODE_HIGH_ASCII_CHARS
1232                         // The seemingly arbitrary 160 comes from RFC
1233                         if (ch >= 160 && ch < 256) {
1234                             output.Write("&#");
1235                             output.Write(((int)ch).ToString(NumberFormatInfo.InvariantInfo));
1236                             output.Write(';');
1237                             break;
1238                         }
1239 #endif // ENTITY_ENCODE_HIGH_ASCII_CHARS
1240
1241                         output.Write(ch);
1242                         break;
1243                 }
1244
1245                 prevCh = ch;
1246             }
1247         }
1248
1249
1250         //////////////////////////////////////////////////////////////////////////
1251         //
1252         //  ASII encode - everything all non-7-bit to '?'
1253         //
1254
1255         /*internal static String AsciiEncode(String s) {
1256             if (s == null)
1257                 return null;
1258
1259             StringBuilder sb = new StringBuilder(s.Length);
1260
1261             for (int i = 0; i < s.Length; i++) {
1262                 char ch = s[i];
1263                 if (((ch & 0xff80) != 0) || (ch < ' ' && ch != '\r' && ch != '\n' && ch != '\t'))
1264                     ch = '?';
1265                 sb.Append(ch);
1266             }
1267
1268             return sb.ToString();
1269         }*/
1270
1271
1272         //
1273         //  Query string parsing support
1274         //
1275
1276         public static NameValueCollection ParseQueryString(string query) {
1277             return ParseQueryString(query, Encoding.UTF8);
1278         }
1279
1280         public static NameValueCollection ParseQueryString(string query, Encoding encoding) {
1281             if (query == null) {
1282                 throw new ArgumentNullException("query");
1283             }
1284
1285             if (encoding == null) {
1286                 throw new ArgumentNullException("encoding");
1287             }
1288
1289             if (query.Length > 0 && query[0] == '?') {
1290                 query = query.Substring(1);
1291             }
1292
1293             return new HttpValueCollection(query, false, true, encoding);
1294         }
1295
1296         //////////////////////////////////////////////////////////////////////////
1297         //
1298         //  URL decoding / encoding
1299         //
1300         //////////////////////////////////////////////////////////////////////////
1301
1302         //
1303         //  Public static methods
1304         //
1305
1306
1307         /// <devdoc>
1308         ///    <para>[To be supplied.]</para>
1309         /// </devdoc>
1310         public static string UrlEncode(string str) {
1311             if (str == null)
1312                 return null;
1313             return UrlEncode(str, Encoding.UTF8);
1314         }
1315
1316
1317         /// <devdoc>
1318         ///    <para>
1319         ///       URL encodes a path portion of a URL string and returns the encoded string.
1320         ///    </para>
1321         /// </devdoc>
1322         public static string UrlPathEncode(string str) {
1323             return HttpEncoder.Current.UrlPathEncode(str);
1324         }
1325
1326         internal static string AspCompatUrlEncode(string s) {
1327             s = UrlEncode(s);
1328             s = s.Replace("!", "%21");
1329             s = s.Replace("*", "%2A");
1330             s = s.Replace("(", "%28");
1331             s = s.Replace(")", "%29");
1332             s = s.Replace("-", "%2D");
1333             s = s.Replace(".", "%2E");
1334             s = s.Replace("_", "%5F");
1335             s = s.Replace("\\", "%5C");
1336             return s;
1337         }
1338
1339
1340         /// <devdoc>
1341         ///    <para>[To be supplied.]</para>
1342         /// </devdoc>
1343         public static string UrlEncode(string str, Encoding e) {
1344             if (str == null)
1345                 return null;
1346             return Encoding.ASCII.GetString(UrlEncodeToBytes(str, e));
1347         }
1348
1349         //  Helper to encode the non-ASCII url characters only
1350         internal static String UrlEncodeNonAscii(string str, Encoding e) {
1351             return HttpEncoder.Current.UrlEncodeNonAscii(str, e);
1352         }
1353
1354         /// <devdoc>
1355         ///    <para>[To be supplied.]</para>
1356         /// </devdoc>
1357         public static string UrlEncode(byte[] bytes) {
1358             if (bytes == null)
1359                 return null;
1360             return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes));
1361         }
1362
1363
1364         /// <devdoc>
1365         ///    <para>[To be supplied.]</para>
1366         /// </devdoc>
1367         public static string UrlEncode(byte[] bytes, int offset, int count) {
1368             if (bytes == null)
1369                 return null;
1370             return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count));
1371         }
1372
1373
1374         /// <devdoc>
1375         ///    <para>[To be supplied.]</para>
1376         /// </devdoc>
1377         public static byte[] UrlEncodeToBytes(string str) {
1378             if (str == null)
1379                 return null;
1380             return UrlEncodeToBytes(str, Encoding.UTF8);
1381         }
1382
1383
1384         /// <devdoc>
1385         ///    <para>[To be supplied.]</para>
1386         /// </devdoc>
1387         public static byte[] UrlEncodeToBytes(string str, Encoding e) {
1388             if (str == null)
1389                 return null;
1390             byte[] bytes = e.GetBytes(str);
1391             return HttpEncoder.Current.UrlEncode(bytes, 0, bytes.Length, false /* alwaysCreateNewReturnValue */);
1392         }
1393
1394
1395         /// <devdoc>
1396         ///    <para>[To be supplied.]</para>
1397         /// </devdoc>
1398         public static byte[] UrlEncodeToBytes(byte[] bytes) {
1399             if (bytes == null)
1400                 return null;
1401             return UrlEncodeToBytes(bytes, 0, bytes.Length);
1402         }
1403
1404
1405         /// <devdoc>
1406         ///    <para>[To be supplied.]</para>
1407         /// </devdoc>
1408         public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count) {
1409             return HttpEncoder.Current.UrlEncode(bytes, offset, count, true /* alwaysCreateNewReturnValue */);
1410         }
1411
1412
1413         /// <devdoc>
1414         ///    <para>[To be supplied.]</para>
1415         /// </devdoc>
1416         [Obsolete("This method produces non-standards-compliant output and has interoperability issues. The preferred alternative is UrlEncode(String).")]
1417         public static string UrlEncodeUnicode(string str) {
1418             return HttpEncoder.Current.UrlEncodeUnicode(str, false /* ignoreAscii */);
1419         }
1420
1421
1422         /// <devdoc>
1423         ///    <para>[To be supplied.]</para>
1424         /// </devdoc>
1425         [Obsolete("This method produces non-standards-compliant output and has interoperability issues. The preferred alternative is UrlEncodeToBytes(String).")]
1426         public static byte[] UrlEncodeUnicodeToBytes(string str) {
1427             if (str == null)
1428                 return null;
1429             return Encoding.ASCII.GetBytes(UrlEncodeUnicode(str));
1430         }
1431
1432
1433         /// <devdoc>
1434         ///    <para>[To be supplied.]</para>
1435         /// </devdoc>
1436         public static string UrlDecode(string str) {
1437             if (str == null)
1438                 return null;
1439             return UrlDecode(str, Encoding.UTF8);
1440         }
1441
1442
1443         /// <devdoc>
1444         ///    <para>[To be supplied.]</para>
1445         /// </devdoc>
1446         public static string UrlDecode(string str, Encoding e) {
1447             return HttpEncoder.Current.UrlDecode(str, e);
1448         }
1449
1450
1451         /// <devdoc>
1452         ///    <para>[To be supplied.]</para>
1453         /// </devdoc>
1454         public static string UrlDecode(byte[] bytes, Encoding e) {
1455             if (bytes == null)
1456                 return null;
1457             return UrlDecode(bytes, 0, bytes.Length, e);
1458         }
1459
1460
1461         /// <devdoc>
1462         ///    <para>[To be supplied.]</para>
1463         /// </devdoc>
1464         public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e) {
1465             return HttpEncoder.Current.UrlDecode(bytes, offset, count, e);
1466         }
1467
1468
1469         /// <devdoc>
1470         ///    <para>[To be supplied.]</para>
1471         /// </devdoc>
1472         public static byte[] UrlDecodeToBytes(string str) {
1473             if (str == null)
1474                 return null;
1475             return UrlDecodeToBytes(str, Encoding.UTF8);
1476         }
1477
1478
1479         /// <devdoc>
1480         ///    <para>[To be supplied.]</para>
1481         /// </devdoc>
1482         public static byte[] UrlDecodeToBytes(string str, Encoding e) {
1483             if (str == null)
1484                 return null;
1485             return UrlDecodeToBytes(e.GetBytes(str));
1486         }
1487
1488
1489         /// <devdoc>
1490         ///    <para>[To be supplied.]</para>
1491         /// </devdoc>
1492         public static byte[] UrlDecodeToBytes(byte[] bytes) {
1493             if (bytes == null)
1494                 return null;
1495             return UrlDecodeToBytes(bytes, 0, (bytes != null) ? bytes.Length : 0);
1496         }
1497
1498
1499         /// <devdoc>
1500         ///    <para>[To be supplied.]</para>
1501         /// </devdoc>
1502         public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count) {
1503             return HttpEncoder.Current.UrlDecode(bytes, offset, count);
1504         }
1505                 
1506
1507         //////////////////////////////////////////////////////////////////////////
1508         //
1509         //  Misc helpers
1510         //
1511         //////////////////////////////////////////////////////////////////////////
1512
1513         internal static String FormatHttpDateTime(DateTime dt) {
1514             if (dt < DateTime.MaxValue.AddDays(-1) && dt > DateTime.MinValue.AddDays(1))
1515                 dt = dt.ToUniversalTime();
1516             return dt.ToString("R", DateTimeFormatInfo.InvariantInfo);
1517         }
1518
1519         internal static String FormatHttpDateTimeUtc(DateTime dt) {
1520             return dt.ToString("R", DateTimeFormatInfo.InvariantInfo);
1521         }
1522
1523         internal static String FormatHttpCookieDateTime(DateTime dt) {
1524             if (dt < DateTime.MaxValue.AddDays(-1) && dt > DateTime.MinValue.AddDays(1))
1525                 dt = dt.ToUniversalTime();
1526             return dt.ToString("ddd, dd-MMM-yyyy HH':'mm':'ss 'GMT'", DateTimeFormatInfo.InvariantInfo);
1527         }
1528
1529         //
1530         // JavaScriptStringEncode
1531         //
1532
1533         public static String JavaScriptStringEncode(string value) {
1534             return JavaScriptStringEncode(value, false);
1535         }
1536
1537         public static String JavaScriptStringEncode(string value, bool addDoubleQuotes) {
1538             string encoded = HttpEncoder.Current.JavaScriptStringEncode(value);
1539             return (addDoubleQuotes) ? "\"" + encoded + "\"" : encoded;
1540         }
1541
1542         /// <summary>
1543         /// Attempts to parse a co-ordinate as a double precision floating point value. 
1544         /// This essentially does a Double.TryParse while disallowing specific floating point constructs such as the exponent.
1545         /// </summary>
1546         internal static bool TryParseCoordinates(string value, out double doubleValue) {
1547             var flags = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite | NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
1548             return Double.TryParse(value, flags, CultureInfo.InvariantCulture, out doubleValue);
1549         }
1550     }
1551 }