1 //------------------------------------------------------------------------------
2 // <copyright file="httpserverutility.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
8 * Server intrinsic used to match ASP's object model
10 * Copyright (c) 1999 Microsoft Corporation
13 // Don't entity encode high chars (160 to 256), to fix bugs VSWhidbey 85857/111927
15 #define ENTITY_ENCODE_HIGH_ASCII_CHARS
17 namespace System.Web {
18 using System.Collections;
19 using System.Collections.Specialized;
20 using System.Globalization;
22 using System.Security.Permissions;
24 using System.Threading;
25 using System.Web.Configuration;
26 using System.Web.Hosting;
28 using System.Web.Util;
30 internal abstract class ErrorFormatterGenerator {
31 internal abstract ErrorFormatter GetErrorFormatter(Exception e);
38 /// helper methods that can be used in the processing of Web requests.
41 public sealed class HttpServerUtility {
42 private HttpContext _context;
43 private HttpApplication _application;
45 private static IDictionary _cultureCache = Hashtable.Synchronized(new Hashtable());
47 internal HttpServerUtility(HttpContext context) {
51 internal HttpServerUtility(HttpApplication application) {
52 _application = application;
56 // Misc ASP compatibility methods
62 /// Instantiates a COM object identified via a progid.
65 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
66 public object CreateObject(string progID) {
67 EnsureHasNotTransitionedToWebSocket();
73 #if !FEATURE_PAL // FEATURE_PAL does not enable COM
74 type = Type.GetTypeFromProgID(progID);
76 throw new NotImplementedException("ROTORTODO");
77 #endif // !FEATURE_PAL
83 throw new HttpException(SR.GetString(SR.Could_not_create_object_of_type, progID));
86 // Disallow Apartment components in non-compat mode
87 AspCompatApplicationStep.CheckThreadingModel(progID, type.GUID);
89 // Instantiate the object
90 obj = Activator.CreateInstance(type);
92 // For ASP compat: take care of OnPageStart/OnPageEnd
93 AspCompatApplicationStep.OnPageStart(obj);
101 /// Instantiates a COM object identified via a Type.
104 [SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
105 public object CreateObject(Type type) {
106 EnsureHasNotTransitionedToWebSocket();
108 // Disallow Apartment components in non-compat mode
109 AspCompatApplicationStep.CheckThreadingModel(type.FullName, type.GUID);
111 // Instantiate the object
112 Object obj = Activator.CreateInstance(type);
114 // For ASP compat: take care of OnPageStart/OnPageEnd
115 AspCompatApplicationStep.OnPageStart(obj);
124 /// Instantiates a COM object identified via a clsid.
127 [SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
128 public object CreateObjectFromClsid(string clsid) {
129 EnsureHasNotTransitionedToWebSocket();
134 // Create a Guid out of it
135 Guid guid = new Guid(clsid);
137 // Disallow Apartment components in non-compat mode
138 AspCompatApplicationStep.CheckThreadingModel(clsid, guid);
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
147 // Instantiate the object
148 obj = Activator.CreateInstance(type);
154 throw new HttpException(
155 SR.GetString(SR.Could_not_create_object_from_clsid, clsid));
158 // For ASP compat: take care of OnPageStart/OnPageEnd
159 AspCompatApplicationStep.OnPageStart(obj);
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));
174 return (CultureInfo)_cultureCache[name];
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);
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);
191 return (CultureInfo)_cultureCache[ci.Name];
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));
204 return (CultureInfo)_cultureCache[culture];
209 /// Maps a virtual path to a physical path.
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;
221 _context.HideRequestResponse = false;
223 realPath = _context.Request.MapPath(path);
227 _context.HideRequestResponse = true;
235 /// <para>Returns the last recorded exception.</para>
237 public Exception GetLastError() {
238 if (_context != null)
239 return _context.Error;
240 else if (_application != null)
241 return _application.LastError;
248 /// <para>Clears the last error.</para>
250 public void ClearError() {
251 if (_context != null)
252 _context.ClearError();
253 else if (_application != null)
254 _application.ClearError();
258 // Server.Transfer/Server.Execute -- child requests
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
269 public void Execute(string path) {
270 Execute(path, null, true /*preserveForm*/);
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
281 public void Execute(string path, TextWriter writer) {
282 Execute(path, writer, true /*preserveForm*/);
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
291 /// If preserveForm is false, the QueryString and Form collections are cleared.
294 public void Execute(string path, bool preserveForm) {
295 Execute(path, null, preserveForm);
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
304 /// If preserveForm is false, the QueryString and Form collections are cleared.
307 public void Execute(string path, TextWriter writer, bool preserveForm) {
308 EnsureHasNotTransitionedToWebSocket();
310 if (_context == null)
311 throw new HttpException(SR.GetString(SR.Server_not_available));
314 throw new ArgumentNullException("path");
316 string queryStringOverride = null;
317 HttpRequest request = _context.Request;
318 HttpResponse response = _context.Response;
320 // Remove potential cookie-less session id (ASURT 100558)
321 path = response.RemoveAppPathModifier(path);
323 // Allow query string override
324 int iqs = path.IndexOf('?');
326 queryStringOverride = path.Substring(iqs+1);
327 path = path.Substring(0, iqs);
330 if (!UrlPath.IsValidVirtualPathWithoutProtocol(path)) {
331 throw new ArgumentException(SR.GetString(SR.Invalid_path_for_child_request, path));
334 VirtualPath virtualPath = VirtualPath.Create(path);
336 // Find the handler for the path
338 IHttpHandler handler = null;
340 string physPath = request.MapPath(virtualPath); // get physical path
341 VirtualPath filePath = request.FilePathObject.Combine(virtualPath); // vpath
343 // Demand read access to the physical path of the target handler
344 InternalSecurityPermissions.FileReadAccess(physPath).Demand();
346 // We need to Assert since there typically is user code on the stack (VSWhidbey 270965)
347 if (HttpRuntime.IsLegacyCas) {
348 InternalSecurityPermissions.Unrestricted.Assert();
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);
357 bool useAppConfig = !filePath.IsWithinAppRoot;
359 using (new DisposableHttpContextWrapper(_context)) {
362 // We need to increase the depth when calling MapHttpHandler,
363 // since PageHandlerFactory relies on it
364 _context.ServerExecuteDepth++;
366 if (_context.WorkerRequest is IIS7WorkerRequest) {
367 handler = _context.ApplicationInstance.MapIntegratedHttpHandler(
373 true /*convertNativeStaticFileModule*/);
376 handler = _context.ApplicationInstance.MapHttpHandler(
385 _context.ServerExecuteDepth--;
389 catch (Exception e) {
390 // 500 errors (compilation errors) get preserved
391 if (e is HttpException) {
392 int code = ((HttpException)e).GetHttpCode();
394 if (code != 500 && code != 404) {
399 throw new HttpException(SR.GetString(SR.Error_executing_child_request_for_path, path), e);
402 ExecuteInternal(handler, writer, preserveForm, true /*setPreviousPage*/,
403 virtualPath, filePath, physPath, null, queryStringOverride);
407 public void Execute(IHttpHandler handler, TextWriter writer, bool preserveForm) {
408 if (_context == null)
409 throw new HttpException(SR.GetString(SR.Server_not_available));
411 Execute(handler, writer, preserveForm, true /*setPreviousPage*/);
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);
419 ExecuteInternal(handler, writer, preserveForm, setPreviousPage,
420 null, filePath, physicalPath, null, null);
423 private void ExecuteInternal(IHttpHandler handler, TextWriter writer, bool preserveForm, bool setPreviousPage,
424 VirtualPath path, VirtualPath filePath, string physPath, Exception error, string queryStringOverride) {
426 EnsureHasNotTransitionedToWebSocket();
429 throw new ArgumentNullException("handler");
431 HttpRequest request = _context.Request;
432 HttpResponse response = _context.Response;
433 HttpApplication app = _context.ApplicationInstance;
435 HttpValueCollection savedForm = null;
436 VirtualPath savedCurrentExecutionFilePath = null;
437 string savedQueryString = null;
438 TextWriter savedOutputWriter = null;
439 AspNetSynchronizationContextBase savedSyncContext = null;
441 // Transaction wouldn't flow into ASPCOMPAT mode -- need to report an error
442 VerifyTransactionFlow(handler);
444 // create new trace context
445 _context.PushTraceContext();
447 // set the new handler as the current handler
448 _context.SetCurrentHandler(handler);
450 // because we call this synchrnously async operations must be disabled
451 bool originalSyncContextWasEnabled = _context.SyncContext.Enabled;
452 _context.SyncContext.Disable();
454 // Execute the handler
457 _context.ServerExecuteDepth++;
459 savedCurrentExecutionFilePath = request.SwitchCurrentExecutionFilePath(filePath);
462 savedForm = request.SwitchForm(new HttpValueCollection());
464 // Clear out the query string, but honor overrides
465 if (queryStringOverride == null)
466 queryStringOverride = String.Empty;
469 // override query string if requested
470 if (queryStringOverride != null) {
471 savedQueryString = request.QueryStringText;
472 request.QueryStringText = queryStringOverride;
475 // capture output if requested
477 savedOutputWriter = response.SwitchWriter(writer);
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);
486 Page sourcePage = _context.Handler as Page;
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
495 // If the target page is async need to save/restore sync context
496 if (targetPage is IHttpAsyncHandler) {
497 savedSyncContext = _context.InstallNewAspNetSynchronizationContext();
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
507 response.WriteFile(physPath);
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);
515 else if (!(handler is Page)) {
516 // disallow anything but pages
517 error = new HttpException(404, String.Empty);
519 else if (handler is IHttpAsyncHandler) {
520 // Asynchronous handler
522 // suspend cancellable period (don't abort this thread while
523 // we wait for another to finish)
524 bool isCancellable = _context.IsInCancellablePeriod;
526 _context.EndCancellablePeriod();
529 IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)handler;
531 if (!AppSettings.UseTaskFriendlySynchronizationContext) {
532 // Legacy code path: behavior ASP.NET <= 4.0
534 IAsyncResult ar = asyncHandler.BeginProcessRequest(_context, null, null);
536 // wait for completion
537 if (!ar.IsCompleted) {
538 // suspend app lock while waiting
539 bool needToRelock = false;
544 _context.SyncContext.DisassociateFromCurrentThread();
548 WaitHandle h = ar.AsyncWaitHandle;
554 while (!ar.IsCompleted)
560 _context.SyncContext.AssociateWithCurrentThread();
565 // end the async operation (get error if any)
568 asyncHandler.EndProcessRequest(ar);
570 catch (Exception e) {
575 // New code path: behavior ASP.NET >= 4.5
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(); },
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();
593 // end the async operation (get error if any)
596 using (_context.SyncContext.AcquireThreadLock()) {
597 asyncHandler.EndProcessRequest(ar);
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));
605 catch (Exception e) {
611 // resume cancelleable period
613 _context.BeginCancellablePeriod();
617 // Synchronous handler
619 using (new DisposableHttpContextWrapper(_context)) {
621 handler.ProcessRequest(_context);
623 catch (Exception e) {
630 _context.ServerExecuteDepth--;
632 // Restore the handlers;
633 _context.RestoreCurrentHandler();
635 // restore output writer
636 if (savedOutputWriter != null)
637 response.SwitchWriter(savedOutputWriter);
639 // restore overriden query string
640 if (queryStringOverride != null && savedQueryString != null)
641 request.QueryStringText = savedQueryString;
643 if (savedForm != null)
644 request.SwitchForm(savedForm);
646 request.SwitchCurrentExecutionFilePath(savedCurrentExecutionFilePath);
648 if (savedSyncContext != null) {
649 _context.RestoreSavedAspNetSynchronizationContext(savedSyncContext);
652 if (originalSyncContextWasEnabled) {
653 _context.SyncContext.Enable();
656 // restore trace context
657 _context.PopTraceContext();
660 catch { // Protect against exception filters
666 // suppress errors with HTTP codes (for child requests they mislead more than help)
667 if (error is HttpException && ((HttpException)error).GetHttpCode() != 500)
671 throw new HttpException(SR.GetString(SR.Error_executing_child_request_for_path, path), error);
673 throw new HttpException(SR.GetString(SR.Error_executing_child_request_for_handler, handler.GetType().ToString()), error);
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.
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));
691 // execute child request
693 Execute(path, null, preserveForm);
695 // suppress the remainder of the current one
697 _context.Response.End();
703 /// Terminates execution of the current page and begins execution of a new
704 /// request using the supplied URL path.
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;
714 Transfer(path, true /*preserveForm*/);
716 _context.PreventPostback = savedPreventPostback;
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));
726 Execute(handler, null, preserveForm);
728 // suppress the remainder of the current one
730 _context.Response.End();
733 public void TransferRequest(string path)
735 TransferRequest(path, false, null, null, preserveUser: true);
738 public void TransferRequest(string path, bool preserveForm)
740 TransferRequest(path, preserveForm, null, null, preserveUser: true);
743 public void TransferRequest(string path, bool preserveForm, string method, NameValueCollection headers) {
744 TransferRequest(path, preserveForm, method, headers, preserveUser: true);
747 public void TransferRequest(string path, bool preserveForm, string method, NameValueCollection headers, bool preserveUser) {
748 EnsureHasNotTransitionedToWebSocket();
750 if (!HttpRuntime.UseIntegratedPipeline) {
751 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
754 if (_context == null) {
755 throw new HttpException(SR.GetString(SR.Server_not_available));
759 throw new ArgumentNullException("path");
762 IIS7WorkerRequest wr = _context.WorkerRequest as IIS7WorkerRequest;
763 HttpRequest request = _context.Request;
764 HttpResponse response = _context.Response;
767 throw new HttpException(SR.GetString(SR.Server_not_available));
770 // Remove potential cookie-less session id (ASURT 100558)
771 path = response.RemoveAppPathModifier(path);
773 // Extract query string if specified
775 int iqs = path.IndexOf('?');
777 qs = (iqs < path.Length-1) ? path.Substring(iqs+1) : String.Empty;
778 path = path.Substring(0, iqs);
781 if (!UrlPath.IsValidVirtualPathWithoutProtocol(path)) {
782 throw new ArgumentException(SR.GetString(SR.Invalid_path_for_child_request, path));
785 VirtualPath virtualPath = request.FilePathObject.Combine(VirtualPath.Create(path));
787 // Schedule the child execution
788 wr.ScheduleExecuteUrl( virtualPath.VirtualPathString,
792 preserveForm ? request.EntityBody : null,
796 // force the completion of the current request so that the
797 // child execution can be performed immediately after unwind
798 _context.ApplicationInstance.EnsureReleaseState();
800 // DevDiv Bugs 162750: IIS7 Integrated Mode: TransferRequest performance issue
801 // Instead of calling Response.End we call HttpApplication.CompleteRequest()
802 _context.ApplicationInstance.CompleteRequest();
805 private void VerifyTransactionFlow(IHttpHandler handler) {
806 Page topPage = _context.Handler as Page;
807 Page childPage = handler as Page;
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
813 throw new HttpException(SR.GetString(SR.Transacted_page_calls_aspcompat));
818 // Static method to execute a request outside of HttpContext and capture the response
821 internal static void ExecuteLocalRequestAndCaptureResponse(String path, TextWriter writer,
822 ErrorFormatterGenerator errorFormatterGenerator) {
823 HttpRequest request = new HttpRequest(
824 VirtualPath.CreateAbsolute(path),
827 HttpResponse response = new HttpResponse(writer);
829 HttpContext context = new HttpContext(request, response);
831 HttpApplication app = HttpApplicationFactory.GetApplicationInstance(context) as HttpApplication;
832 context.ApplicationInstance = app;
835 context.Server.Execute(path);
837 catch (HttpException e) {
838 if (errorFormatterGenerator != null) {
839 context.Response.SetOverrideErrorFormatter(errorFormatterGenerator.GetErrorFormatter(e));
842 context.Response.ReportRuntimeError(e, false, true);
846 context.ApplicationInstance = null;
847 HttpApplicationFactory.RecycleApplicationInstance(app);
856 private static object _machineNameLock = new object();
857 private static string _machineName;
858 private const int _maxMachineNameLength = 256;
864 /// the server machine name.
867 public string MachineName {
868 [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
870 return GetMachineNameInternal();
874 internal static string GetMachineNameInternal()
876 if (_machineName != null)
878 lock (_machineNameLock)
880 if (_machineName != null)
883 StringBuilder buf = new StringBuilder (_maxMachineNameLength);
884 int len = _maxMachineNameLength;
886 if (UnsafeNativeMethods.GetComputerName (buf, ref len) == 0)
887 throw new HttpException (SR.GetString(SR.Get_computer_name_failed));
889 _machineName = buf.ToString();
901 /// Request timeout in seconds
904 public int ScriptTimeout {
906 if (_context != null) {
907 return Convert.ToInt32(_context.Timeout.TotalSeconds);
910 return HttpRuntimeSection.DefaultExecutionTimeout;
914 [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
916 if (_context == null)
917 throw new HttpException(SR.GetString(SR.Server_not_available));
919 throw new ArgumentOutOfRangeException("value");
920 _context.Timeout = new TimeSpan(0, 0, value);
925 // Encoding / Decoding -- wrappers for HttpUtility
932 /// decodes a given string and
933 /// returns the decoded string.
936 public string HtmlDecode(string s) {
937 return HttpUtility.HtmlDecode(s);
944 /// decode a string and send the result to a TextWriter output
948 public void HtmlDecode(string s, TextWriter output) {
949 HttpUtility.HtmlDecode(s, output);
956 /// encodes a given string and
957 /// returns the encoded string.
960 public string HtmlEncode(string s) {
961 return HttpUtility.HtmlEncode(s);
969 /// a string and returns the output to a TextWriter stream of output.
972 public void HtmlEncode(string s, TextWriter output) {
973 HttpUtility.HtmlEncode(s, output);
981 /// string and returns the encoded string.
984 public string UrlEncode(string s) {
985 Encoding e = (_context != null) ? _context.Response.ContentEncoding : Encoding.UTF8;
986 return HttpUtility.UrlEncode(s, e);
992 /// URL encodes a path portion of a URL string and returns the encoded string.
995 public string UrlPathEncode(string s) {
996 return HttpUtility.UrlPathEncode(s);
1004 /// a string and returns the output to a TextWriter output stream.
1007 public void UrlEncode(string s, TextWriter output) {
1009 output.Write(UrlEncode(s));
1015 /// URL decodes a string and returns the output in a string.
1018 public string UrlDecode(string s) {
1019 Encoding e = (_context != null) ? _context.Request.ContentEncoding : Encoding.UTF8;
1020 return HttpUtility.UrlDecode(s, e);
1026 /// URL decodes a string and returns the output as a TextWriter output
1030 public void UrlDecode(string s, TextWriter output) {
1032 output.Write(UrlDecode(s));
1035 /////////////////////////////////////////////////////////////////////////////
1036 /////////////////////////////////////////////////////////////////////////////
1037 /////////////////////////////////////////////////////////////////////////////
1039 static public string UrlTokenEncode(byte [] input)
1041 return HttpEncoder.Current.UrlTokenEncode(input);
1044 /////////////////////////////////////////////////////////////////////////////
1045 /////////////////////////////////////////////////////////////////////////////
1046 /////////////////////////////////////////////////////////////////////////////
1048 static public byte [] UrlTokenDecode(string input) {
1049 return HttpEncoder.Current.UrlTokenDecode(input);
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();
1064 // VSWhidbey 473228 - removed link demand from HttpUtility for ClickOnce scenario
1065 public sealed class HttpUtility {
1067 public HttpUtility () {}
1069 //////////////////////////////////////////////////////////////////////////
1071 // HTML Encoding / Decoding
1077 /// HTML decodes a string and returns the decoded string.
1080 public static string HtmlDecode(string s) {
1081 return HttpEncoder.Current.HtmlDecode(s);
1087 /// HTML decode a string and send the result to a TextWriter output stream.
1090 public static void HtmlDecode(string s, TextWriter output) {
1091 HttpEncoder.Current.HtmlDecode(s, output);
1097 /// HTML encodes a string and returns the encoded string.
1100 public static String HtmlEncode(String s) {
1101 return HttpEncoder.Current.HtmlEncode(s);
1107 /// HTML encodes an object's string representation and returns the encoded string.
1108 /// If the object implements IHtmlString, don't encode it
1111 public static String HtmlEncode(object value) {
1112 if (value == null) {
1113 // Return null to be consistent with HtmlEncode(string)
1117 var htmlString = value as IHtmlString;
1118 if (htmlString != null) {
1119 return htmlString.ToHtmlString();
1122 return HtmlEncode(Convert.ToString(value, CultureInfo.CurrentCulture));
1128 /// HTML encodes a string and returns the output to a TextWriter stream of
1132 public static void HtmlEncode(String s, TextWriter output) {
1133 HttpEncoder.Current.HtmlEncode(s, output);
1139 /// Encodes a string to make it a valid HTML attribute and returns the encoded string.
1142 public static String HtmlAttributeEncode(String s) {
1143 return HttpEncoder.Current.HtmlAttributeEncode(s);
1149 /// Encodes a string to make it a valid HTML attribute and returns the output
1150 /// to a TextWriter stream of
1154 public static void HtmlAttributeEncode(String s, TextWriter output) {
1155 HttpEncoder.Current.HtmlAttributeEncode(s, output);
1159 internal static string FormatPlainTextSpacesAsHtml(string s) {
1164 StringBuilder builder = new StringBuilder();
1165 StringWriter writer = new StringWriter(builder);
1169 for (int i = 0; i < cb; i++) {
1172 writer.Write(" ");
1178 return builder.ToString();
1181 internal static String FormatPlainTextAsHtml(String s) {
1185 StringBuilder builder = new StringBuilder();
1186 StringWriter writer = new StringWriter(builder);
1188 FormatPlainTextAsHtml(s, writer);
1190 return builder.ToString();
1193 internal static void FormatPlainTextAsHtml(String s, TextWriter output) {
1201 for (int i=0; i<cb; i++) {
1205 output.Write("<");
1208 output.Write(">");
1211 output.Write(""");
1214 output.Write("&");
1218 output.Write(" ");
1223 // Ignore \r, only handle \n
1226 output.Write("<br>");
1231 #if ENTITY_ENCODE_HIGH_ASCII_CHARS
1232 // The seemingly arbitrary 160 comes from RFC
1233 if (ch >= 160 && ch < 256) {
1235 output.Write(((int)ch).ToString(NumberFormatInfo.InvariantInfo));
1239 #endif // ENTITY_ENCODE_HIGH_ASCII_CHARS
1250 //////////////////////////////////////////////////////////////////////////
1252 // ASII encode - everything all non-7-bit to '?'
1255 /*internal static String AsciiEncode(String s) {
1259 StringBuilder sb = new StringBuilder(s.Length);
1261 for (int i = 0; i < s.Length; i++) {
1263 if (((ch & 0xff80) != 0) || (ch < ' ' && ch != '\r' && ch != '\n' && ch != '\t'))
1268 return sb.ToString();
1273 // Query string parsing support
1276 public static NameValueCollection ParseQueryString(string query) {
1277 return ParseQueryString(query, Encoding.UTF8);
1280 public static NameValueCollection ParseQueryString(string query, Encoding encoding) {
1281 if (query == null) {
1282 throw new ArgumentNullException("query");
1285 if (encoding == null) {
1286 throw new ArgumentNullException("encoding");
1289 if (query.Length > 0 && query[0] == '?') {
1290 query = query.Substring(1);
1293 return new HttpValueCollection(query, false, true, encoding);
1296 //////////////////////////////////////////////////////////////////////////
1298 // URL decoding / encoding
1300 //////////////////////////////////////////////////////////////////////////
1303 // Public static methods
1308 /// <para>[To be supplied.]</para>
1310 public static string UrlEncode(string str) {
1313 return UrlEncode(str, Encoding.UTF8);
1319 /// URL encodes a path portion of a URL string and returns the encoded string.
1322 public static string UrlPathEncode(string str) {
1323 return HttpEncoder.Current.UrlPathEncode(str);
1326 internal static string AspCompatUrlEncode(string 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");
1341 /// <para>[To be supplied.]</para>
1343 public static string UrlEncode(string str, Encoding e) {
1346 return Encoding.ASCII.GetString(UrlEncodeToBytes(str, e));
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);
1355 /// <para>[To be supplied.]</para>
1357 public static string UrlEncode(byte[] bytes) {
1360 return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes));
1365 /// <para>[To be supplied.]</para>
1367 public static string UrlEncode(byte[] bytes, int offset, int count) {
1370 return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count));
1375 /// <para>[To be supplied.]</para>
1377 public static byte[] UrlEncodeToBytes(string str) {
1380 return UrlEncodeToBytes(str, Encoding.UTF8);
1385 /// <para>[To be supplied.]</para>
1387 public static byte[] UrlEncodeToBytes(string str, Encoding e) {
1390 byte[] bytes = e.GetBytes(str);
1391 return HttpEncoder.Current.UrlEncode(bytes, 0, bytes.Length, false /* alwaysCreateNewReturnValue */);
1396 /// <para>[To be supplied.]</para>
1398 public static byte[] UrlEncodeToBytes(byte[] bytes) {
1401 return UrlEncodeToBytes(bytes, 0, bytes.Length);
1406 /// <para>[To be supplied.]</para>
1408 public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count) {
1409 return HttpEncoder.Current.UrlEncode(bytes, offset, count, true /* alwaysCreateNewReturnValue */);
1414 /// <para>[To be supplied.]</para>
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 */);
1423 /// <para>[To be supplied.]</para>
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) {
1429 return Encoding.ASCII.GetBytes(UrlEncodeUnicode(str));
1434 /// <para>[To be supplied.]</para>
1436 public static string UrlDecode(string str) {
1439 return UrlDecode(str, Encoding.UTF8);
1444 /// <para>[To be supplied.]</para>
1446 public static string UrlDecode(string str, Encoding e) {
1447 return HttpEncoder.Current.UrlDecode(str, e);
1452 /// <para>[To be supplied.]</para>
1454 public static string UrlDecode(byte[] bytes, Encoding e) {
1457 return UrlDecode(bytes, 0, bytes.Length, e);
1462 /// <para>[To be supplied.]</para>
1464 public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e) {
1465 return HttpEncoder.Current.UrlDecode(bytes, offset, count, e);
1470 /// <para>[To be supplied.]</para>
1472 public static byte[] UrlDecodeToBytes(string str) {
1475 return UrlDecodeToBytes(str, Encoding.UTF8);
1480 /// <para>[To be supplied.]</para>
1482 public static byte[] UrlDecodeToBytes(string str, Encoding e) {
1485 return UrlDecodeToBytes(e.GetBytes(str));
1490 /// <para>[To be supplied.]</para>
1492 public static byte[] UrlDecodeToBytes(byte[] bytes) {
1495 return UrlDecodeToBytes(bytes, 0, (bytes != null) ? bytes.Length : 0);
1500 /// <para>[To be supplied.]</para>
1502 public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count) {
1503 return HttpEncoder.Current.UrlDecode(bytes, offset, count);
1507 //////////////////////////////////////////////////////////////////////////
1511 //////////////////////////////////////////////////////////////////////////
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);
1519 internal static String FormatHttpDateTimeUtc(DateTime dt) {
1520 return dt.ToString("R", DateTimeFormatInfo.InvariantInfo);
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);
1530 // JavaScriptStringEncode
1533 public static String JavaScriptStringEncode(string value) {
1534 return JavaScriptStringEncode(value, false);
1537 public static String JavaScriptStringEncode(string value, bool addDoubleQuotes) {
1538 string encoded = HttpEncoder.Current.JavaScriptStringEncode(value);
1539 return (addDoubleQuotes) ? "\"" + encoded + "\"" : encoded;
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.
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);