using System.Web.Util;
using System.Collections.Specialized;
using System.Security.Permissions;
+using System.Text;
namespace System.Web {
public void Execute (string path)
{
- Execute (path, null);
+ Execute (path, null, true);
}
public void Execute (string path, TextWriter writer)
{
- Execute (path, writer, false);
+ Execute (path, writer, true);
}
+#if NET_2_0
+ public void Execute (string path, bool preserveForm)
+ {
+ Execute (path, null, preserveForm);
+ }
+#endif
+
#if NET_2_0
public
#else
internal
#endif
- void Execute (string path, TextWriter writer, bool preserveQuery)
- {
+ void Execute (string path, TextWriter writer, bool preserveForm)
+ {
if (path == null)
throw new ArgumentNullException ("path");
if (path.IndexOf (':') != -1)
throw new ArgumentException ("Invalid path.");
+ HttpRequest request = context.Request;
+ string oldQuery = request.QueryStringRaw;
int qmark = path.IndexOf ('?');
- string query;
if (qmark != -1) {
- query = path.Substring (qmark + 1);
+ request.QueryStringRaw = path.Substring (qmark + 1);
path = path.Substring (0, qmark);
- } else {
- query = "";
+ } else if (!preserveForm) {
+ request.QueryStringRaw = "";
}
- HttpRequest request = context.Request;
HttpResponse response = context.Response;
-
- string oldQuery = request.QueryStringRaw;
- request.QueryStringRaw = query;
-
WebROCollection oldForm = null;
- if (!preserveQuery) {
+ if (!preserveForm) {
oldForm = request.Form as WebROCollection;
request.SetForm (new WebROCollection ());
}
string oldFilePath = request.FilePath;
request.SetCurrentExePath (UrlUtils.Combine (request.BaseVirtualDir, path));
IHttpHandler handler = context.ApplicationInstance.GetHandler (context);
+ request.SetCurrentExePath (oldFilePath);
+
+#if NET_2_0
+ // If the target handler is not Page, the transfer must not occur.
+ // InTransit == true means we're being called from Transfer
+ if (context.InTransit && !(handler is Page))
+ throw new HttpException ("Transfer is possible only to .aspx files");
+#endif
+
TextWriter previous = null;
try {
+#if NET_2_0
+ context.PushHandler (handler);
+#endif
previous = response.SetTextWriter (output);
+
if (!(handler is IHttpAsyncHandler)) {
handler.ProcessRequest (context);
} else {
asyncHandler.EndProcessRequest (ar);
}
} finally {
- request.SetCurrentExePath (oldFilePath);
- request.QueryStringRaw = oldQuery;
+ if (oldQuery != null && oldQuery != "" && oldQuery != request.QueryStringRaw) {
+ oldQuery = oldQuery.Substring (1); // Ignore initial '?'
+ request.QueryStringRaw = oldQuery; // which is added here.
+ }
response.SetTextWriter (previous);
- if (!preserveQuery)
+ if (!preserveForm)
request.SetForm (oldForm);
+ context.InTransit = false;
+#if NET_2_0
+ context.PopHandler ();
+#endif
}
}
Page page = (Page) context.Handler;
preserveForm = !page.IsPostBack;
}
+#if NET_2_0
+ else
+ throw new HttpException ("Transfer may only be called from within a Page instance");
+#endif
Transfer (path, preserveForm);
}
public void Transfer (string path, bool preserveForm)
{
+#if NET_2_0
+ if (!(context.Handler is Page))
+ throw new HttpException ("Transfer may only be called from within a Page instance");
+#endif
+
+ context.InTransit = true;
Execute (path, null, preserveForm);
context.Response.End ();
}
#if NET_2_0
- [MonoTODO]
public void Transfer (IHttpHandler handler, bool preserveForm)
{
- throw new NotImplementedException ();
+ if (handler == null)
+ throw new ArgumentNullException ("handler");
+ if (!(handler is Page))
+ throw new HttpException ("Transfer may only be called from within a Page instance");
+
+ // TODO: see the MS doc and search for "enableViewStateMac": this method is not
+ // allowed for pages when preserveForm is true and the page IsCallback property
+ // is true.
+
+ Execute (handler, null, preserveForm);
+ context.Response.End ();
+ }
+
+ public void Execute (IHttpHandler handler, TextWriter writer, bool preserveForm)
+ {
+ if (handler == null)
+ throw new ArgumentNullException ("handler");
+
+ // If the target handler is not Page, the transfer must not occur.
+ // InTransit == true means we're being called from Transfer
+ if (context.InTransit && !(handler is Page))
+ throw new HttpException ("Transfer is possible only to .aspx files");
+
+ HttpRequest request = context.Request;
+ string oldQuery = request.QueryStringRaw;
+ if (!preserveForm) {
+ request.QueryStringRaw = "";
+ }
+
+ HttpResponse response = context.Response;
+ WebROCollection oldForm = null;
+ if (!preserveForm) {
+ oldForm = request.Form as WebROCollection;
+ request.SetForm (new WebROCollection ());
+ }
+
+ TextWriter output = writer;
+ if (output == null)
+ output = response.Output;
+
+ TextWriter previous = null;
+ try {
+ previous = response.SetTextWriter (output);
+ if (!(handler is IHttpAsyncHandler)) {
+ handler.ProcessRequest (context);
+ } else {
+ IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler) handler;
+ IAsyncResult ar = asyncHandler.BeginProcessRequest (context, null, null);
+ ar.AsyncWaitHandle.WaitOne ();
+ asyncHandler.EndProcessRequest (ar);
+ }
+ } finally {
+ if (oldQuery != null && oldQuery != "" && oldQuery != request.QueryStringRaw) {
+ oldQuery = oldQuery.Substring (1); // Ignore initial '?'
+ request.QueryStringRaw = oldQuery; // which is added here.
+ }
+ response.SetTextWriter (previous);
+ if (!preserveForm)
+ request.SetForm (oldForm);
+ }
+ }
+
+ public static byte[] UrlTokenDecode (string input)
+ {
+ if (input == null)
+ throw new ArgumentNullException ("input");
+ if (input.Length < 1)
+ return new byte[0];
+ byte[] bytes = Encoding.ASCII.GetBytes (input);
+ int inputLength = input.Length - 1;
+ int equalsCount = (int)(((char)bytes[inputLength]) - 0x30);
+ char[] ret = new char[inputLength + equalsCount];
+ int i = 0;
+ for (; i < inputLength; i++) {
+ switch ((char)bytes[i]) {
+ case '-':
+ ret[i] = '+';
+ break;
+
+ case '_':
+ ret[i] = '/';
+ break;
+
+ default:
+ ret[i] = (char)bytes[i];
+ break;
+ }
+ }
+ while (equalsCount > 0) {
+ ret[i++] = '=';
+ equalsCount--;
+ }
+
+ return Convert.FromBase64CharArray (ret, 0, ret.Length);
+ }
+
+ public static string UrlTokenEncode (byte[] input)
+ {
+ if (input == null)
+ throw new ArgumentNullException ("input");
+ if (input.Length < 1)
+ return String.Empty;
+ string base64 = Convert.ToBase64String (input);
+ int retlen;
+ if (base64 == null || (retlen = base64.Length) == 0)
+ return String.Empty;
+
+ // MS.NET implementation seems to process the base64
+ // string before returning. It replaces the chars:
+ //
+ // + with -
+ // / with _
+ //
+ // Then removes trailing ==, which may appear in the
+ // base64 string, and replaces them with a single digit
+ // that's the count of removed '=' characters (0 if none
+ // were removed)
+ int equalsCount = 0x30;
+ while (retlen > 0 && base64[retlen - 1] == '=') {
+ equalsCount++;
+ retlen--;
+ }
+ char[] chars = new char[retlen + 1];
+ chars[retlen] = (char)equalsCount;
+ for (int i = 0; i < retlen; i++) {
+ switch (base64[i]) {
+ case '+':
+ chars[i] = '-';
+ break;
+
+ case '/':
+ chars[i] = '_';
+ break;
+
+ default:
+ chars[i] = base64[i];
+ break;
+ }
+ }
+ return new string (chars);
}
#endif
+
public string UrlDecode (string s)
{
return HttpUtility.UrlDecode (s);