536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
1552 lines
55 KiB
C#
1552 lines
55 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="httpserverutility.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Server intrinsic used to match ASP's object model
|
|
*
|
|
* Copyright (c) 1999 Microsoft Corporation
|
|
*/
|
|
|
|
// Don't entity encode high chars (160 to 256), to fix bugs VSWhidbey 85857/111927
|
|
//
|
|
#define ENTITY_ENCODE_HIGH_ASCII_CHARS
|
|
|
|
namespace System.Web {
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Security.Permissions;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Web.Configuration;
|
|
using System.Web.Hosting;
|
|
using System.Web.UI;
|
|
using System.Web.Util;
|
|
|
|
internal abstract class ErrorFormatterGenerator {
|
|
internal abstract ErrorFormatter GetErrorFormatter(Exception e);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Provides several
|
|
/// helper methods that can be used in the processing of Web requests.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public sealed class HttpServerUtility {
|
|
private HttpContext _context;
|
|
private HttpApplication _application;
|
|
|
|
private static IDictionary _cultureCache = Hashtable.Synchronized(new Hashtable());
|
|
|
|
internal HttpServerUtility(HttpContext context) {
|
|
_context = context;
|
|
}
|
|
|
|
internal HttpServerUtility(HttpApplication application) {
|
|
_application = application;
|
|
}
|
|
|
|
//
|
|
// Misc ASP compatibility methods
|
|
//
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Instantiates a COM object identified via a progid.
|
|
/// </para>
|
|
/// </devdoc>
|
|
[SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
|
|
public object CreateObject(string progID) {
|
|
EnsureHasNotTransitionedToWebSocket();
|
|
|
|
Type type = null;
|
|
object obj = null;
|
|
|
|
try {
|
|
#if !FEATURE_PAL // FEATURE_PAL does not enable COM
|
|
type = Type.GetTypeFromProgID(progID);
|
|
#else // !FEATURE_PAL
|
|
throw new NotImplementedException("ROTORTODO");
|
|
#endif // !FEATURE_PAL
|
|
}
|
|
catch {
|
|
}
|
|
|
|
if (type == null) {
|
|
throw new HttpException(SR.GetString(SR.Could_not_create_object_of_type, progID));
|
|
}
|
|
|
|
// Disallow Apartment components in non-compat mode
|
|
AspCompatApplicationStep.CheckThreadingModel(progID, type.GUID);
|
|
|
|
// Instantiate the object
|
|
obj = Activator.CreateInstance(type);
|
|
|
|
// For ASP compat: take care of OnPageStart/OnPageEnd
|
|
AspCompatApplicationStep.OnPageStart(obj);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Instantiates a COM object identified via a Type.
|
|
/// </para>
|
|
/// </devdoc>
|
|
[SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
|
|
public object CreateObject(Type type) {
|
|
EnsureHasNotTransitionedToWebSocket();
|
|
|
|
// Disallow Apartment components in non-compat mode
|
|
AspCompatApplicationStep.CheckThreadingModel(type.FullName, type.GUID);
|
|
|
|
// Instantiate the object
|
|
Object obj = Activator.CreateInstance(type);
|
|
|
|
// For ASP compat: take care of OnPageStart/OnPageEnd
|
|
AspCompatApplicationStep.OnPageStart(obj);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Instantiates a COM object identified via a clsid.
|
|
/// </para>
|
|
/// </devdoc>
|
|
[SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
|
|
public object CreateObjectFromClsid(string clsid) {
|
|
EnsureHasNotTransitionedToWebSocket();
|
|
|
|
Type type = null;
|
|
object obj = null;
|
|
|
|
// Create a Guid out of it
|
|
Guid guid = new Guid(clsid);
|
|
|
|
// Disallow Apartment components in non-compat mode
|
|
AspCompatApplicationStep.CheckThreadingModel(clsid, guid);
|
|
|
|
try {
|
|
#if !FEATURE_PAL // FEATURE_PAL does not enable COM
|
|
type = Type.GetTypeFromCLSID(guid, null, true /*throwOnError*/);
|
|
#else // !FEATURE_PAL
|
|
throw new NotImplementedException("ROTORTODO");
|
|
#endif // !FEATURE_PAL
|
|
|
|
// Instantiate the object
|
|
obj = Activator.CreateInstance(type);
|
|
}
|
|
catch {
|
|
}
|
|
|
|
if (obj == null) {
|
|
throw new HttpException(
|
|
SR.GetString(SR.Could_not_create_object_from_clsid, clsid));
|
|
}
|
|
|
|
// For ASP compat: take care of OnPageStart/OnPageEnd
|
|
AspCompatApplicationStep.OnPageStart(obj);
|
|
|
|
return obj;
|
|
}
|
|
|
|
// Internal static method that returns a read-only, non-user override accounted, CultureInfo object
|
|
internal static CultureInfo CreateReadOnlyCultureInfo(string name) {
|
|
if (!_cultureCache.Contains(name)) {
|
|
// To be threadsafe, get the lock before creating
|
|
lock (_cultureCache) {
|
|
if (_cultureCache[name] == null) {
|
|
_cultureCache[name] = CultureInfo.ReadOnly(new CultureInfo(name));
|
|
}
|
|
}
|
|
}
|
|
return (CultureInfo)_cultureCache[name];
|
|
}
|
|
|
|
// Internal static method that returns a read-only, non-user override accounted, culture specific CultureInfo object
|
|
internal static CultureInfo CreateReadOnlySpecificCultureInfo(string name) {
|
|
if(name.IndexOf('-') > 0) {
|
|
return CreateReadOnlyCultureInfo(name);
|
|
}
|
|
CultureInfo ci = CultureInfo.CreateSpecificCulture(name);
|
|
if (!_cultureCache.Contains(ci.Name)) {
|
|
//To be threadsafe, get the lock before creating
|
|
lock (_cultureCache) {
|
|
if (_cultureCache[ci.Name] == null) {
|
|
_cultureCache[ci.Name] = CultureInfo.ReadOnly(ci);
|
|
}
|
|
}
|
|
}
|
|
return (CultureInfo)_cultureCache[ci.Name];
|
|
}
|
|
|
|
// Internal static method that returns a read-only, non-user override accounted, CultureInfo object
|
|
internal static CultureInfo CreateReadOnlyCultureInfo(int culture) {
|
|
if (!_cultureCache.Contains(culture)) {
|
|
// To be threadsafe, get the lock before creating
|
|
lock (_cultureCache) {
|
|
if (_cultureCache[culture] == null) {
|
|
_cultureCache[culture] = CultureInfo.ReadOnly(new CultureInfo(culture));
|
|
}
|
|
}
|
|
}
|
|
return (CultureInfo)_cultureCache[culture];
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Maps a virtual path to a physical path.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public string MapPath(string path) {
|
|
if (_context == null)
|
|
throw new HttpException(SR.GetString(SR.Server_not_available));
|
|
// Disable hiding the request so that Server.MapPath works when called from
|
|
// Application_Start in integrated mode
|
|
bool unhideRequest = _context.HideRequestResponse;
|
|
string realPath;
|
|
try {
|
|
if (unhideRequest) {
|
|
_context.HideRequestResponse = false;
|
|
}
|
|
realPath = _context.Request.MapPath(path);
|
|
}
|
|
finally {
|
|
if (unhideRequest) {
|
|
_context.HideRequestResponse = true;
|
|
}
|
|
}
|
|
return realPath;
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Returns the last recorded exception.</para>
|
|
/// </devdoc>
|
|
public Exception GetLastError() {
|
|
if (_context != null)
|
|
return _context.Error;
|
|
else if (_application != null)
|
|
return _application.LastError;
|
|
else
|
|
return null;
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Clears the last error.</para>
|
|
/// </devdoc>
|
|
public void ClearError() {
|
|
if (_context != null)
|
|
_context.ClearError();
|
|
else if (_application != null)
|
|
_application.ClearError();
|
|
}
|
|
|
|
//
|
|
// Server.Transfer/Server.Execute -- child requests
|
|
//
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Executes a new request (using the specified URL path as the target). Unlike
|
|
/// the Transfer method, execution of the original page continues after the executed
|
|
/// page completes.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void Execute(string path) {
|
|
Execute(path, null, true /*preserveForm*/);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Executes a new request (using the specified URL path as the target). Unlike
|
|
/// the Transfer method, execution of the original page continues after the executed
|
|
/// page completes.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void Execute(string path, TextWriter writer) {
|
|
Execute(path, writer, true /*preserveForm*/);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Executes a new request (using the specified URL path as the target). Unlike
|
|
/// the Transfer method, execution of the original page continues after the executed
|
|
/// page completes.
|
|
/// If preserveForm is false, the QueryString and Form collections are cleared.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void Execute(string path, bool preserveForm) {
|
|
Execute(path, null, preserveForm);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Executes a new request (using the specified URL path as the target). Unlike
|
|
/// the Transfer method, execution of the original page continues after the executed
|
|
/// page completes.
|
|
/// If preserveForm is false, the QueryString and Form collections are cleared.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void Execute(string path, TextWriter writer, bool preserveForm) {
|
|
EnsureHasNotTransitionedToWebSocket();
|
|
|
|
if (_context == null)
|
|
throw new HttpException(SR.GetString(SR.Server_not_available));
|
|
|
|
if (path == null)
|
|
throw new ArgumentNullException("path");
|
|
|
|
string queryStringOverride = null;
|
|
HttpRequest request = _context.Request;
|
|
HttpResponse response = _context.Response;
|
|
|
|
// Remove potential cookie-less session id (ASURT 100558)
|
|
path = response.RemoveAppPathModifier(path);
|
|
|
|
// Allow query string override
|
|
int iqs = path.IndexOf('?');
|
|
if (iqs >= 0) {
|
|
queryStringOverride = path.Substring(iqs+1);
|
|
path = path.Substring(0, iqs);
|
|
}
|
|
|
|
if (!UrlPath.IsValidVirtualPathWithoutProtocol(path)) {
|
|
throw new ArgumentException(SR.GetString(SR.Invalid_path_for_child_request, path));
|
|
}
|
|
|
|
VirtualPath virtualPath = VirtualPath.Create(path);
|
|
|
|
// Find the handler for the path
|
|
|
|
IHttpHandler handler = null;
|
|
|
|
string physPath = request.MapPath(virtualPath); // get physical path
|
|
VirtualPath filePath = request.FilePathObject.Combine(virtualPath); // vpath
|
|
|
|
// Demand read access to the physical path of the target handler
|
|
InternalSecurityPermissions.FileReadAccess(physPath).Demand();
|
|
|
|
// We need to Assert since there typically is user code on the stack (VSWhidbey 270965)
|
|
if (HttpRuntime.IsLegacyCas) {
|
|
InternalSecurityPermissions.Unrestricted.Assert();
|
|
}
|
|
|
|
try {
|
|
// paths that ends with . are disallowed as they are used to get around
|
|
// extension mappings and server source as static file
|
|
if (StringUtil.StringEndsWith(virtualPath.VirtualPathString, '.'))
|
|
throw new HttpException(404, String.Empty);
|
|
|
|
bool useAppConfig = !filePath.IsWithinAppRoot;
|
|
|
|
using (new DisposableHttpContextWrapper(_context)) {
|
|
|
|
try {
|
|
// We need to increase the depth when calling MapHttpHandler,
|
|
// since PageHandlerFactory relies on it
|
|
_context.ServerExecuteDepth++;
|
|
|
|
if (_context.WorkerRequest is IIS7WorkerRequest) {
|
|
handler = _context.ApplicationInstance.MapIntegratedHttpHandler(
|
|
_context,
|
|
request.RequestType,
|
|
filePath,
|
|
physPath,
|
|
useAppConfig,
|
|
true /*convertNativeStaticFileModule*/);
|
|
}
|
|
else {
|
|
handler = _context.ApplicationInstance.MapHttpHandler(
|
|
_context,
|
|
request.RequestType,
|
|
filePath,
|
|
physPath,
|
|
useAppConfig);
|
|
}
|
|
}
|
|
finally {
|
|
_context.ServerExecuteDepth--;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
// 500 errors (compilation errors) get preserved
|
|
if (e is HttpException) {
|
|
int code = ((HttpException)e).GetHttpCode();
|
|
|
|
if (code != 500 && code != 404) {
|
|
e = null;
|
|
}
|
|
}
|
|
|
|
throw new HttpException(SR.GetString(SR.Error_executing_child_request_for_path, path), e);
|
|
}
|
|
|
|
ExecuteInternal(handler, writer, preserveForm, true /*setPreviousPage*/,
|
|
virtualPath, filePath, physPath, null, queryStringOverride);
|
|
}
|
|
|
|
|
|
public void Execute(IHttpHandler handler, TextWriter writer, bool preserveForm) {
|
|
if (_context == null)
|
|
throw new HttpException(SR.GetString(SR.Server_not_available));
|
|
|
|
Execute(handler, writer, preserveForm, true /*setPreviousPage*/);
|
|
}
|
|
|
|
internal void Execute(IHttpHandler handler, TextWriter writer, bool preserveForm, bool setPreviousPage) {
|
|
HttpRequest request = _context.Request;
|
|
VirtualPath filePath = request.CurrentExecutionFilePathObject;
|
|
string physicalPath = request.MapPath(filePath);
|
|
|
|
ExecuteInternal(handler, writer, preserveForm, setPreviousPage,
|
|
null, filePath, physicalPath, null, null);
|
|
}
|
|
|
|
private void ExecuteInternal(IHttpHandler handler, TextWriter writer, bool preserveForm, bool setPreviousPage,
|
|
VirtualPath path, VirtualPath filePath, string physPath, Exception error, string queryStringOverride) {
|
|
|
|
EnsureHasNotTransitionedToWebSocket();
|
|
|
|
if (handler == null)
|
|
throw new ArgumentNullException("handler");
|
|
|
|
HttpRequest request = _context.Request;
|
|
HttpResponse response = _context.Response;
|
|
HttpApplication app = _context.ApplicationInstance;
|
|
|
|
HttpValueCollection savedForm = null;
|
|
VirtualPath savedCurrentExecutionFilePath = null;
|
|
string savedQueryString = null;
|
|
TextWriter savedOutputWriter = null;
|
|
AspNetSynchronizationContextBase savedSyncContext = null;
|
|
|
|
// Transaction wouldn't flow into ASPCOMPAT mode -- need to report an error
|
|
VerifyTransactionFlow(handler);
|
|
|
|
// create new trace context
|
|
_context.PushTraceContext();
|
|
|
|
// set the new handler as the current handler
|
|
_context.SetCurrentHandler(handler);
|
|
|
|
// because we call this synchrnously async operations must be disabled
|
|
bool originalSyncContextWasEnabled = _context.SyncContext.Enabled;
|
|
_context.SyncContext.Disable();
|
|
|
|
// Execute the handler
|
|
try {
|
|
try {
|
|
_context.ServerExecuteDepth++;
|
|
|
|
savedCurrentExecutionFilePath = request.SwitchCurrentExecutionFilePath(filePath);
|
|
|
|
if (!preserveForm) {
|
|
savedForm = request.SwitchForm(new HttpValueCollection());
|
|
|
|
// Clear out the query string, but honor overrides
|
|
if (queryStringOverride == null)
|
|
queryStringOverride = String.Empty;
|
|
}
|
|
|
|
// override query string if requested
|
|
if (queryStringOverride != null) {
|
|
savedQueryString = request.QueryStringText;
|
|
request.QueryStringText = queryStringOverride;
|
|
}
|
|
|
|
// capture output if requested
|
|
if (writer != null)
|
|
savedOutputWriter = response.SwitchWriter(writer);
|
|
|
|
Page targetPage = handler as Page;
|
|
if (targetPage != null) {
|
|
if (setPreviousPage) {
|
|
// Set the previousPage of the new Page as the previous Page
|
|
targetPage.SetPreviousPage(_context.PreviousHandler as Page);
|
|
}
|
|
|
|
Page sourcePage = _context.Handler as Page;
|
|
|
|
#pragma warning disable 0618 // To avoid deprecation warning
|
|
// If the source page of the transfer has smart nav on,
|
|
// always do as if the destination has it too (ASURT 97732)
|
|
if (sourcePage != null && sourcePage.SmartNavigation)
|
|
targetPage.SmartNavigation = true;
|
|
#pragma warning restore 0618
|
|
|
|
// If the target page is async need to save/restore sync context
|
|
if (targetPage is IHttpAsyncHandler) {
|
|
savedSyncContext = _context.InstallNewAspNetSynchronizationContext();
|
|
}
|
|
}
|
|
|
|
if ((handler is StaticFileHandler || handler is DefaultHttpHandler) &&
|
|
!DefaultHttpHandler.IsClassicAspRequest(filePath.VirtualPathString)) {
|
|
// cannot apply static files handler directly
|
|
// -- it would dump the source of the current page
|
|
// instead just dump the file content into response
|
|
try {
|
|
response.WriteFile(physPath);
|
|
}
|
|
catch {
|
|
// hide the real error as it could be misleading
|
|
// in case of mismapped requests like /foo.asmx/bar
|
|
error = new HttpException(404, String.Empty);
|
|
}
|
|
}
|
|
else if (!(handler is Page)) {
|
|
// disallow anything but pages
|
|
error = new HttpException(404, String.Empty);
|
|
}
|
|
else if (handler is IHttpAsyncHandler) {
|
|
// Asynchronous handler
|
|
|
|
// suspend cancellable period (don't abort this thread while
|
|
// we wait for another to finish)
|
|
bool isCancellable = _context.IsInCancellablePeriod;
|
|
if (isCancellable)
|
|
_context.EndCancellablePeriod();
|
|
|
|
try {
|
|
IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)handler;
|
|
|
|
if (!AppSettings.UseTaskFriendlySynchronizationContext) {
|
|
// Legacy code path: behavior ASP.NET <= 4.0
|
|
|
|
IAsyncResult ar = asyncHandler.BeginProcessRequest(_context, null, null);
|
|
|
|
// wait for completion
|
|
if (!ar.IsCompleted) {
|
|
// suspend app lock while waiting
|
|
bool needToRelock = false;
|
|
|
|
try {
|
|
try { }
|
|
finally {
|
|
_context.SyncContext.DisassociateFromCurrentThread();
|
|
needToRelock = true;
|
|
}
|
|
|
|
WaitHandle h = ar.AsyncWaitHandle;
|
|
|
|
if (h != null) {
|
|
h.WaitOne();
|
|
}
|
|
else {
|
|
while (!ar.IsCompleted)
|
|
Thread.Sleep(1);
|
|
}
|
|
}
|
|
finally {
|
|
if (needToRelock) {
|
|
_context.SyncContext.AssociateWithCurrentThread();
|
|
}
|
|
}
|
|
}
|
|
|
|
// end the async operation (get error if any)
|
|
|
|
try {
|
|
asyncHandler.EndProcessRequest(ar);
|
|
}
|
|
catch (Exception e) {
|
|
error = e;
|
|
}
|
|
}
|
|
else {
|
|
// New code path: behavior ASP.NET >= 4.5
|
|
IAsyncResult ar;
|
|
bool blockedThread;
|
|
|
|
using (CountdownEvent countdownEvent = new CountdownEvent(1)) {
|
|
using (_context.SyncContext.AcquireThreadLock()) {
|
|
// Kick off the asynchronous operation
|
|
ar = asyncHandler.BeginProcessRequest(_context,
|
|
cb: _ => { countdownEvent.Signal(); },
|
|
extraData: null);
|
|
}
|
|
|
|
// The callback passed to BeginProcessRequest will signal the CountdownEvent.
|
|
// The Wait() method blocks until the callback executes; no-ops if the operation completed synchronously.
|
|
blockedThread = !countdownEvent.IsSet;
|
|
countdownEvent.Wait();
|
|
}
|
|
|
|
// end the async operation (get error if any)
|
|
|
|
try {
|
|
using (_context.SyncContext.AcquireThreadLock()) {
|
|
asyncHandler.EndProcessRequest(ar);
|
|
}
|
|
|
|
// If we blocked the thread, YSOD the request to display a diagnostic message.
|
|
if (blockedThread && !_context.SyncContext.AllowAsyncDuringSyncStages) {
|
|
throw new InvalidOperationException(SR.GetString(SR.Server_execute_blocked_on_async_handler));
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
error = e;
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
// resume cancelleable period
|
|
if (isCancellable)
|
|
_context.BeginCancellablePeriod();
|
|
}
|
|
}
|
|
else {
|
|
// Synchronous handler
|
|
|
|
using (new DisposableHttpContextWrapper(_context)) {
|
|
try {
|
|
handler.ProcessRequest(_context);
|
|
}
|
|
catch (Exception e) {
|
|
error = e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
_context.ServerExecuteDepth--;
|
|
|
|
// Restore the handlers;
|
|
_context.RestoreCurrentHandler();
|
|
|
|
// restore output writer
|
|
if (savedOutputWriter != null)
|
|
response.SwitchWriter(savedOutputWriter);
|
|
|
|
// restore overriden query string
|
|
if (queryStringOverride != null && savedQueryString != null)
|
|
request.QueryStringText = savedQueryString;
|
|
|
|
if (savedForm != null)
|
|
request.SwitchForm(savedForm);
|
|
|
|
request.SwitchCurrentExecutionFilePath(savedCurrentExecutionFilePath);
|
|
|
|
if (savedSyncContext != null) {
|
|
_context.RestoreSavedAspNetSynchronizationContext(savedSyncContext);
|
|
}
|
|
|
|
if (originalSyncContextWasEnabled) {
|
|
_context.SyncContext.Enable();
|
|
}
|
|
|
|
// restore trace context
|
|
_context.PopTraceContext();
|
|
}
|
|
}
|
|
catch { // Protect against exception filters
|
|
throw;
|
|
}
|
|
|
|
// Report any error
|
|
if (error != null) {
|
|
// suppress errors with HTTP codes (for child requests they mislead more than help)
|
|
if (error is HttpException && ((HttpException)error).GetHttpCode() != 500)
|
|
error = null;
|
|
|
|
if (path != null)
|
|
throw new HttpException(SR.GetString(SR.Error_executing_child_request_for_path, path), error);
|
|
|
|
throw new HttpException(SR.GetString(SR.Error_executing_child_request_for_handler, handler.GetType().ToString()), error);
|
|
}
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Terminates execution of the current page and begins execution of a new
|
|
/// request using the supplied URL path.
|
|
/// If preserveForm is false, the QueryString and Form collections are cleared.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void Transfer(string path, bool preserveForm) {
|
|
Page page = _context.Handler as Page;
|
|
if ((page != null) && page.IsCallback) {
|
|
throw new ApplicationException(SR.GetString(SR.Transfer_not_allowed_in_callback));
|
|
}
|
|
|
|
// execute child request
|
|
|
|
Execute(path, null, preserveForm);
|
|
|
|
// suppress the remainder of the current one
|
|
|
|
_context.Response.End();
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Terminates execution of the current page and begins execution of a new
|
|
/// request using the supplied URL path.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void Transfer(string path) {
|
|
// Make sure the transfer is not treated as a postback, which could cause a stack
|
|
// overflow if the user doesn't expect it (VSWhidbey 181013).
|
|
// If the use *does* want it treated as a postback, they can call Transfer(path, true).
|
|
bool savedPreventPostback = _context.PreventPostback;
|
|
_context.PreventPostback = true;
|
|
|
|
Transfer(path, true /*preserveForm*/);
|
|
|
|
_context.PreventPostback = savedPreventPostback;
|
|
}
|
|
|
|
|
|
public void Transfer(IHttpHandler handler, bool preserveForm) {
|
|
Page page = handler as Page;
|
|
if ((page != null) && page.IsCallback) {
|
|
throw new ApplicationException(SR.GetString(SR.Transfer_not_allowed_in_callback));
|
|
}
|
|
|
|
Execute(handler, null, preserveForm);
|
|
|
|
// suppress the remainder of the current one
|
|
|
|
_context.Response.End();
|
|
}
|
|
|
|
public void TransferRequest(string path)
|
|
{
|
|
TransferRequest(path, false, null, null, preserveUser: true);
|
|
}
|
|
|
|
public void TransferRequest(string path, bool preserveForm)
|
|
{
|
|
TransferRequest(path, preserveForm, null, null, preserveUser: true);
|
|
}
|
|
|
|
public void TransferRequest(string path, bool preserveForm, string method, NameValueCollection headers) {
|
|
TransferRequest(path, preserveForm, method, headers, preserveUser: true);
|
|
}
|
|
|
|
public void TransferRequest(string path, bool preserveForm, string method, NameValueCollection headers, bool preserveUser) {
|
|
EnsureHasNotTransitionedToWebSocket();
|
|
|
|
if (!HttpRuntime.UseIntegratedPipeline) {
|
|
throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
|
|
}
|
|
|
|
if (_context == null) {
|
|
throw new HttpException(SR.GetString(SR.Server_not_available));
|
|
}
|
|
|
|
if (path == null) {
|
|
throw new ArgumentNullException("path");
|
|
}
|
|
|
|
IIS7WorkerRequest wr = _context.WorkerRequest as IIS7WorkerRequest;
|
|
HttpRequest request = _context.Request;
|
|
HttpResponse response = _context.Response;
|
|
|
|
if (wr == null) {
|
|
throw new HttpException(SR.GetString(SR.Server_not_available));
|
|
}
|
|
|
|
// Remove potential cookie-less session id (ASURT 100558)
|
|
path = response.RemoveAppPathModifier(path);
|
|
|
|
// Extract query string if specified
|
|
String qs = null;
|
|
int iqs = path.IndexOf('?');
|
|
if (iqs >= 0) {
|
|
qs = (iqs < path.Length-1) ? path.Substring(iqs+1) : String.Empty;
|
|
path = path.Substring(0, iqs);
|
|
}
|
|
|
|
if (!UrlPath.IsValidVirtualPathWithoutProtocol(path)) {
|
|
throw new ArgumentException(SR.GetString(SR.Invalid_path_for_child_request, path));
|
|
}
|
|
|
|
VirtualPath virtualPath = request.FilePathObject.Combine(VirtualPath.Create(path));
|
|
|
|
// Schedule the child execution
|
|
wr.ScheduleExecuteUrl( virtualPath.VirtualPathString,
|
|
qs,
|
|
method,
|
|
preserveForm,
|
|
preserveForm ? request.EntityBody : null,
|
|
headers,
|
|
preserveUser);
|
|
|
|
// force the completion of the current request so that the
|
|
// child execution can be performed immediately after unwind
|
|
_context.ApplicationInstance.EnsureReleaseState();
|
|
|
|
// DevDiv Bugs 162750: IIS7 Integrated Mode: TransferRequest performance issue
|
|
// Instead of calling Response.End we call HttpApplication.CompleteRequest()
|
|
_context.ApplicationInstance.CompleteRequest();
|
|
}
|
|
|
|
private void VerifyTransactionFlow(IHttpHandler handler) {
|
|
Page topPage = _context.Handler as Page;
|
|
Page childPage = handler as Page;
|
|
|
|
if (childPage != null && childPage.IsInAspCompatMode && // child page aspcompat
|
|
topPage != null && !topPage.IsInAspCompatMode && // top page is not aspcompat
|
|
Transactions.Utils.IsInTransaction) { // we are in transaction
|
|
|
|
throw new HttpException(SR.GetString(SR.Transacted_page_calls_aspcompat));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Static method to execute a request outside of HttpContext and capture the response
|
|
//
|
|
|
|
internal static void ExecuteLocalRequestAndCaptureResponse(String path, TextWriter writer,
|
|
ErrorFormatterGenerator errorFormatterGenerator) {
|
|
HttpRequest request = new HttpRequest(
|
|
VirtualPath.CreateAbsolute(path),
|
|
String.Empty);
|
|
|
|
HttpResponse response = new HttpResponse(writer);
|
|
|
|
HttpContext context = new HttpContext(request, response);
|
|
|
|
HttpApplication app = HttpApplicationFactory.GetApplicationInstance(context) as HttpApplication;
|
|
context.ApplicationInstance = app;
|
|
|
|
try {
|
|
context.Server.Execute(path);
|
|
}
|
|
catch (HttpException e) {
|
|
if (errorFormatterGenerator != null) {
|
|
context.Response.SetOverrideErrorFormatter(errorFormatterGenerator.GetErrorFormatter(e));
|
|
}
|
|
|
|
context.Response.ReportRuntimeError(e, false, true);
|
|
}
|
|
finally {
|
|
if (app != null) {
|
|
context.ApplicationInstance = null;
|
|
HttpApplicationFactory.RecycleApplicationInstance(app);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Computer name
|
|
//
|
|
|
|
private static object _machineNameLock = new object();
|
|
private static string _machineName;
|
|
private const int _maxMachineNameLength = 256;
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Gets
|
|
/// the server machine name.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public string MachineName {
|
|
[AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
|
|
get {
|
|
return GetMachineNameInternal();
|
|
}
|
|
}
|
|
|
|
internal static string GetMachineNameInternal()
|
|
{
|
|
if (_machineName != null)
|
|
return _machineName;
|
|
lock (_machineNameLock)
|
|
{
|
|
if (_machineName != null)
|
|
return _machineName;
|
|
|
|
StringBuilder buf = new StringBuilder (_maxMachineNameLength);
|
|
int len = _maxMachineNameLength;
|
|
|
|
if (UnsafeNativeMethods.GetComputerName (buf, ref len) == 0)
|
|
throw new HttpException (SR.GetString(SR.Get_computer_name_failed));
|
|
|
|
_machineName = buf.ToString();
|
|
}
|
|
return _machineName;
|
|
}
|
|
|
|
//
|
|
// Request Timeout
|
|
//
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Request timeout in seconds
|
|
/// </para>
|
|
/// </devdoc>
|
|
public int ScriptTimeout {
|
|
get {
|
|
if (_context != null) {
|
|
return Convert.ToInt32(_context.Timeout.TotalSeconds);
|
|
}
|
|
else {
|
|
return HttpRuntimeSection.DefaultExecutionTimeout;
|
|
}
|
|
}
|
|
|
|
[AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
|
|
set {
|
|
if (_context == null)
|
|
throw new HttpException(SR.GetString(SR.Server_not_available));
|
|
if (value <= 0)
|
|
throw new ArgumentOutOfRangeException("value");
|
|
_context.Timeout = new TimeSpan(0, 0, value);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Encoding / Decoding -- wrappers for HttpUtility
|
|
//
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// HTML
|
|
/// decodes a given string and
|
|
/// returns the decoded string.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public string HtmlDecode(string s) {
|
|
return HttpUtility.HtmlDecode(s);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// HTML
|
|
/// decode a string and send the result to a TextWriter output
|
|
/// stream.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void HtmlDecode(string s, TextWriter output) {
|
|
HttpUtility.HtmlDecode(s, output);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// HTML
|
|
/// encodes a given string and
|
|
/// returns the encoded string.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public string HtmlEncode(string s) {
|
|
return HttpUtility.HtmlEncode(s);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// HTML
|
|
/// encodes
|
|
/// a string and returns the output to a TextWriter stream of output.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void HtmlEncode(string s, TextWriter output) {
|
|
HttpUtility.HtmlEncode(s, output);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// URL
|
|
/// encodes a given
|
|
/// string and returns the encoded string.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public string UrlEncode(string s) {
|
|
Encoding e = (_context != null) ? _context.Response.ContentEncoding : Encoding.UTF8;
|
|
return HttpUtility.UrlEncode(s, e);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// URL encodes a path portion of a URL string and returns the encoded string.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public string UrlPathEncode(string s) {
|
|
return HttpUtility.UrlPathEncode(s);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// URL
|
|
/// encodes
|
|
/// a string and returns the output to a TextWriter output stream.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void UrlEncode(string s, TextWriter output) {
|
|
if (s != null)
|
|
output.Write(UrlEncode(s));
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// URL decodes a string and returns the output in a string.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public string UrlDecode(string s) {
|
|
Encoding e = (_context != null) ? _context.Request.ContentEncoding : Encoding.UTF8;
|
|
return HttpUtility.UrlDecode(s, e);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// URL decodes a string and returns the output as a TextWriter output
|
|
/// stream.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void UrlDecode(string s, TextWriter output) {
|
|
if (s != null)
|
|
output.Write(UrlDecode(s));
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
static public string UrlTokenEncode(byte [] input)
|
|
{
|
|
return HttpEncoder.Current.UrlTokenEncode(input);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
static public byte [] UrlTokenDecode(string input) {
|
|
return HttpEncoder.Current.UrlTokenDecode(input);
|
|
}
|
|
|
|
// helper that throws an exception if we have transitioned the current request to a WebSocket request
|
|
internal void EnsureHasNotTransitionedToWebSocket() {
|
|
if (_context != null) {
|
|
_context.EnsureHasNotTransitionedToWebSocket();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
|
|
// VSWhidbey 473228 - removed link demand from HttpUtility for ClickOnce scenario
|
|
public sealed class HttpUtility {
|
|
|
|
public HttpUtility () {}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HTML Encoding / Decoding
|
|
//
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// HTML decodes a string and returns the decoded string.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public static string HtmlDecode(string s) {
|
|
return HttpEncoder.Current.HtmlDecode(s);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// HTML decode a string and send the result to a TextWriter output stream.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public static void HtmlDecode(string s, TextWriter output) {
|
|
HttpEncoder.Current.HtmlDecode(s, output);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// HTML encodes a string and returns the encoded string.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public static String HtmlEncode(String s) {
|
|
return HttpEncoder.Current.HtmlEncode(s);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// HTML encodes an object's string representation and returns the encoded string.
|
|
/// If the object implements IHtmlString, don't encode it
|
|
/// </para>
|
|
/// </devdoc>
|
|
public static String HtmlEncode(object value) {
|
|
if (value == null) {
|
|
// Return null to be consistent with HtmlEncode(string)
|
|
return null;
|
|
}
|
|
|
|
var htmlString = value as IHtmlString;
|
|
if (htmlString != null) {
|
|
return htmlString.ToHtmlString();
|
|
}
|
|
|
|
return HtmlEncode(Convert.ToString(value, CultureInfo.CurrentCulture));
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// HTML encodes a string and returns the output to a TextWriter stream of
|
|
/// output.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public static void HtmlEncode(String s, TextWriter output) {
|
|
HttpEncoder.Current.HtmlEncode(s, output);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Encodes a string to make it a valid HTML attribute and returns the encoded string.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public static String HtmlAttributeEncode(String s) {
|
|
return HttpEncoder.Current.HtmlAttributeEncode(s);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Encodes a string to make it a valid HTML attribute and returns the output
|
|
/// to a TextWriter stream of
|
|
/// output.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public static void HtmlAttributeEncode(String s, TextWriter output) {
|
|
HttpEncoder.Current.HtmlAttributeEncode(s, output);
|
|
}
|
|
|
|
|
|
internal static string FormatPlainTextSpacesAsHtml(string s) {
|
|
if (s == null) {
|
|
return null;
|
|
}
|
|
|
|
StringBuilder builder = new StringBuilder();
|
|
StringWriter writer = new StringWriter(builder);
|
|
|
|
int cb = s.Length;
|
|
|
|
for (int i = 0; i < cb; i++) {
|
|
char ch = s[i];
|
|
if(ch == ' ') {
|
|
writer.Write(" ");
|
|
}
|
|
else {
|
|
writer.Write(ch);
|
|
}
|
|
}
|
|
return builder.ToString();
|
|
}
|
|
|
|
internal static String FormatPlainTextAsHtml(String s) {
|
|
if (s == null)
|
|
return null;
|
|
|
|
StringBuilder builder = new StringBuilder();
|
|
StringWriter writer = new StringWriter(builder);
|
|
|
|
FormatPlainTextAsHtml(s, writer);
|
|
|
|
return builder.ToString();
|
|
}
|
|
|
|
internal static void FormatPlainTextAsHtml(String s, TextWriter output) {
|
|
if (s == null)
|
|
return;
|
|
|
|
int cb = s.Length;
|
|
|
|
char prevCh = '\0';
|
|
|
|
for (int i=0; i<cb; i++) {
|
|
char ch = s[i];
|
|
switch (ch) {
|
|
case '<':
|
|
output.Write("<");
|
|
break;
|
|
case '>':
|
|
output.Write(">");
|
|
break;
|
|
case '"':
|
|
output.Write(""");
|
|
break;
|
|
case '&':
|
|
output.Write("&");
|
|
break;
|
|
case ' ':
|
|
if (prevCh == ' ')
|
|
output.Write(" ");
|
|
else
|
|
output.Write(ch);
|
|
break;
|
|
case '\r':
|
|
// Ignore \r, only handle \n
|
|
break;
|
|
case '\n':
|
|
output.Write("<br>");
|
|
break;
|
|
|
|
//
|
|
default:
|
|
#if ENTITY_ENCODE_HIGH_ASCII_CHARS
|
|
// The seemingly arbitrary 160 comes from RFC
|
|
if (ch >= 160 && ch < 256) {
|
|
output.Write("&#");
|
|
output.Write(((int)ch).ToString(NumberFormatInfo.InvariantInfo));
|
|
output.Write(';');
|
|
break;
|
|
}
|
|
#endif // ENTITY_ENCODE_HIGH_ASCII_CHARS
|
|
|
|
output.Write(ch);
|
|
break;
|
|
}
|
|
|
|
prevCh = ch;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ASII encode - everything all non-7-bit to '?'
|
|
//
|
|
|
|
/*internal static String AsciiEncode(String s) {
|
|
if (s == null)
|
|
return null;
|
|
|
|
StringBuilder sb = new StringBuilder(s.Length);
|
|
|
|
for (int i = 0; i < s.Length; i++) {
|
|
char ch = s[i];
|
|
if (((ch & 0xff80) != 0) || (ch < ' ' && ch != '\r' && ch != '\n' && ch != '\t'))
|
|
ch = '?';
|
|
sb.Append(ch);
|
|
}
|
|
|
|
return sb.ToString();
|
|
}*/
|
|
|
|
|
|
//
|
|
// Query string parsing support
|
|
//
|
|
|
|
public static NameValueCollection ParseQueryString(string query) {
|
|
return ParseQueryString(query, Encoding.UTF8);
|
|
}
|
|
|
|
public static NameValueCollection ParseQueryString(string query, Encoding encoding) {
|
|
if (query == null) {
|
|
throw new ArgumentNullException("query");
|
|
}
|
|
|
|
if (encoding == null) {
|
|
throw new ArgumentNullException("encoding");
|
|
}
|
|
|
|
if (query.Length > 0 && query[0] == '?') {
|
|
query = query.Substring(1);
|
|
}
|
|
|
|
return new HttpValueCollection(query, false, true, encoding);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// URL decoding / encoding
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Public static methods
|
|
//
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static string UrlEncode(string str) {
|
|
if (str == null)
|
|
return null;
|
|
return UrlEncode(str, Encoding.UTF8);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// URL encodes a path portion of a URL string and returns the encoded string.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public static string UrlPathEncode(string str) {
|
|
return HttpEncoder.Current.UrlPathEncode(str);
|
|
}
|
|
|
|
internal static string AspCompatUrlEncode(string s) {
|
|
s = UrlEncode(s);
|
|
s = s.Replace("!", "%21");
|
|
s = s.Replace("*", "%2A");
|
|
s = s.Replace("(", "%28");
|
|
s = s.Replace(")", "%29");
|
|
s = s.Replace("-", "%2D");
|
|
s = s.Replace(".", "%2E");
|
|
s = s.Replace("_", "%5F");
|
|
s = s.Replace("\\", "%5C");
|
|
return s;
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static string UrlEncode(string str, Encoding e) {
|
|
if (str == null)
|
|
return null;
|
|
return Encoding.ASCII.GetString(UrlEncodeToBytes(str, e));
|
|
}
|
|
|
|
// Helper to encode the non-ASCII url characters only
|
|
internal static String UrlEncodeNonAscii(string str, Encoding e) {
|
|
return HttpEncoder.Current.UrlEncodeNonAscii(str, e);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static string UrlEncode(byte[] bytes) {
|
|
if (bytes == null)
|
|
return null;
|
|
return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes));
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static string UrlEncode(byte[] bytes, int offset, int count) {
|
|
if (bytes == null)
|
|
return null;
|
|
return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count));
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static byte[] UrlEncodeToBytes(string str) {
|
|
if (str == null)
|
|
return null;
|
|
return UrlEncodeToBytes(str, Encoding.UTF8);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static byte[] UrlEncodeToBytes(string str, Encoding e) {
|
|
if (str == null)
|
|
return null;
|
|
byte[] bytes = e.GetBytes(str);
|
|
return HttpEncoder.Current.UrlEncode(bytes, 0, bytes.Length, false /* alwaysCreateNewReturnValue */);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static byte[] UrlEncodeToBytes(byte[] bytes) {
|
|
if (bytes == null)
|
|
return null;
|
|
return UrlEncodeToBytes(bytes, 0, bytes.Length);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count) {
|
|
return HttpEncoder.Current.UrlEncode(bytes, offset, count, true /* alwaysCreateNewReturnValue */);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
[Obsolete("This method produces non-standards-compliant output and has interoperability issues. The preferred alternative is UrlEncode(String).")]
|
|
public static string UrlEncodeUnicode(string str) {
|
|
return HttpEncoder.Current.UrlEncodeUnicode(str, false /* ignoreAscii */);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
[Obsolete("This method produces non-standards-compliant output and has interoperability issues. The preferred alternative is UrlEncodeToBytes(String).")]
|
|
public static byte[] UrlEncodeUnicodeToBytes(string str) {
|
|
if (str == null)
|
|
return null;
|
|
return Encoding.ASCII.GetBytes(UrlEncodeUnicode(str));
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static string UrlDecode(string str) {
|
|
if (str == null)
|
|
return null;
|
|
return UrlDecode(str, Encoding.UTF8);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static string UrlDecode(string str, Encoding e) {
|
|
return HttpEncoder.Current.UrlDecode(str, e);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static string UrlDecode(byte[] bytes, Encoding e) {
|
|
if (bytes == null)
|
|
return null;
|
|
return UrlDecode(bytes, 0, bytes.Length, e);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e) {
|
|
return HttpEncoder.Current.UrlDecode(bytes, offset, count, e);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static byte[] UrlDecodeToBytes(string str) {
|
|
if (str == null)
|
|
return null;
|
|
return UrlDecodeToBytes(str, Encoding.UTF8);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static byte[] UrlDecodeToBytes(string str, Encoding e) {
|
|
if (str == null)
|
|
return null;
|
|
return UrlDecodeToBytes(e.GetBytes(str));
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static byte[] UrlDecodeToBytes(byte[] bytes) {
|
|
if (bytes == null)
|
|
return null;
|
|
return UrlDecodeToBytes(bytes, 0, (bytes != null) ? bytes.Length : 0);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count) {
|
|
return HttpEncoder.Current.UrlDecode(bytes, offset, count);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Misc helpers
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
internal static String FormatHttpDateTime(DateTime dt) {
|
|
if (dt < DateTime.MaxValue.AddDays(-1) && dt > DateTime.MinValue.AddDays(1))
|
|
dt = dt.ToUniversalTime();
|
|
return dt.ToString("R", DateTimeFormatInfo.InvariantInfo);
|
|
}
|
|
|
|
internal static String FormatHttpDateTimeUtc(DateTime dt) {
|
|
return dt.ToString("R", DateTimeFormatInfo.InvariantInfo);
|
|
}
|
|
|
|
internal static String FormatHttpCookieDateTime(DateTime dt) {
|
|
if (dt < DateTime.MaxValue.AddDays(-1) && dt > DateTime.MinValue.AddDays(1))
|
|
dt = dt.ToUniversalTime();
|
|
return dt.ToString("ddd, dd-MMM-yyyy HH':'mm':'ss 'GMT'", DateTimeFormatInfo.InvariantInfo);
|
|
}
|
|
|
|
//
|
|
// JavaScriptStringEncode
|
|
//
|
|
|
|
public static String JavaScriptStringEncode(string value) {
|
|
return JavaScriptStringEncode(value, false);
|
|
}
|
|
|
|
public static String JavaScriptStringEncode(string value, bool addDoubleQuotes) {
|
|
string encoded = HttpEncoder.Current.JavaScriptStringEncode(value);
|
|
return (addDoubleQuotes) ? "\"" + encoded + "\"" : encoded;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attempts to parse a co-ordinate as a double precision floating point value.
|
|
/// This essentially does a Double.TryParse while disallowing specific floating point constructs such as the exponent.
|
|
/// </summary>
|
|
internal static bool TryParseCoordinates(string value, out double doubleValue) {
|
|
var flags = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite | NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
|
|
return Double.TryParse(value, flags, CultureInfo.InvariantCulture, out doubleValue);
|
|
}
|
|
}
|
|
}
|