From: Jaben C. <ja...@us...> - 2007-02-08 00:49:44
|
Update of /cvsroot/yafdotnet/yafsrc/URLRewriter.NET In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv25871/yafsrc/URLRewriter.NET Added Files: Tag: v1_0_2_NETv2 AssemblyInfo.cs Form.cs Intelligencia.UrlRewriter.csproj Intelligencia.UrlRewriter.xml Messages.resx RewriteContext.cs RewriteProcessing.cs RewriterEngine.cs RewriterHttpModule.cs Log Message: URL Rewriter class --- NEW FILE: Intelligencia.UrlRewriter.xml --- <?xml version="1.0"?> <doc> <assembly> <name>Intelligencia.UrlRewriter</name> </assembly> <members> <member name="T:Intelligencia.UrlRewriter.Utilities.IContextFacade"> <summary> Interface for a facade to the context. Useful for plugging out the HttpContext object in unit tests. </summary> </member> <member name="M:Intelligencia.UrlRewriter.Utilities.IContextFacade.GetApplicationPath"> <summary> Retrieves the application path. </summary> <returns>The application path.</returns> </member> <member name="M:Intelligencia.UrlRewriter.Utilities.IContextFacade.GetRawUrl"> [...2073 lines suppressed...] <param name="url">Url of the error page.</param> </member> <member name="M:Intelligencia.UrlRewriter.Errors.DefaultErrorHandler.HandleError(System.Web.HttpContext)"> <summary> Handles the error by rewriting to the error page url. </summary> <param name="context">The context.</param> </member> <member name="T:Intelligencia.UrlRewriter.Actions.ForbiddenAction"> <summary> Returns a 403 Forbidden HTTP status code. </summary> </member> <member name="M:Intelligencia.UrlRewriter.Actions.ForbiddenAction.#ctor"> <summary> Default constructor. </summary> </member> </members> </doc> --- NEW FILE: RewriterHttpModule.cs --- // UrlRewriter - A .NET URL Rewriter module // Version 1.7 // // Copyright 2006 Intelligencia // Copyright 2006 Seth Yates // using System; using System.IO; using System.Net; using System.Web; using System.Resources; using System.Reflection; using Intelligencia.UrlRewriter.Configuration; using Intelligencia.UrlRewriter.Utilities; namespace Intelligencia.UrlRewriter { /// <summary> /// Rewrites urls based on patterns and conditions specified in the configuration file. /// This class cannot be inherited. /// </summary> public sealed class RewriterHttpModule : IHttpModule { /// <summary> /// Initialises the module. /// </summary> /// <param name="context">The application context.</param> void IHttpModule.Init(HttpApplication context) { context.BeginRequest += new EventHandler(BeginRequest); } /// <summary> /// Disposes of the module. /// </summary> void IHttpModule.Dispose() { } /// <summary> /// Configuration of the rewriter. /// </summary> public static RewriterConfiguration Configuration { get { return RewriterConfiguration.Current; } } /// <summary> /// Resolves an Application-path relative location /// </summary> /// <param name="location">The location</param> /// <returns>The absolute location.</returns> public static string ResolveLocation(string location) { return _rewriter.ResolveLocation(location); } /// <summary> /// The original query string. /// </summary> public static string OriginalQueryString { get { return _rewriter.OriginalQueryString; } set { _rewriter.OriginalQueryString = value; } } /// <summary> /// The final querystring, after rewriting. /// </summary> public static string QueryString { get { return _rewriter.QueryString; } set { _rewriter.QueryString = value; } } private void BeginRequest(object sender, EventArgs e) { // Add our PoweredBy header HttpContext.Current.Response.AddHeader(Constants.HeaderXPoweredBy, Configuration.XPoweredBy); _rewriter.Rewrite(); } private static RewriterEngine _rewriter = new RewriterEngine(new HttpContextFacade(), RewriterConfiguration.Current); } } --- NEW FILE: Form.cs --- using System; using System.Collections; using System.Collections.Specialized; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using Intelligencia.UrlRewriter.Utilities; namespace Intelligencia.UrlRewriter { /// <summary> /// Replacement for <asp:form> to handle rewritten form postback. /// </summary> /// <remarks> /// <p>This form should be used for pages that use the url rewriter and have /// forms that are posted back. If you use the normal ASP.NET <see cref="System.Web.UI.HtmlControls.HtmlForm">HtmlForm</see>, /// then the postback will not be able to correctly resolve the postback data to the form data. /// </p> /// <p>This form is a direct replacement for the <asp:form> tag. /// </p> /// <p>The following code demonstrates the usage of this control.</p> /// <code> /// <%@ Page language="c#" Codebehind="MyPage.aspx.cs" AutoEventWireup="false" Inherits="MyPage" %> /// <%@ Register TagPrefix="url" Namespace="Intelligencia.UrlRewriter" Assembly="Intelligencia.UrlRewriter" %> /// <html> /// ... /// <body> /// <url:form id="MyForm" runat="server"> /// ... /// </url:form> /// </body> /// </html> /// </code> /// </remarks> [ToolboxData("<{0}:Form runat=server></{0}:RewrittenForm>")] public class Form : HtmlForm { /// <summary> /// Renders children of the form control. /// </summary> /// <param name="writer">The output writer.</param> /// <exclude /> protected override void RenderChildren(HtmlTextWriter writer) { writer.RenderBeginTag(HtmlTextWriterTag.Div); base.RenderChildren(writer); writer.RenderEndTag(); } /// <summary> /// Renders attributes. /// </summary> /// <param name="writer">The output writer.</param> /// <exclude /> protected override void RenderAttributes(HtmlTextWriter writer) { writer.WriteAttribute(Constants.AttrName, GetName()); Attributes.Remove(Constants.AttrName); writer.WriteAttribute(Constants.AttrMethod, GetMethod()); Attributes.Remove(Constants.AttrMethod); writer.WriteAttribute(Constants.AttrAction, GetAction(), true); Attributes.Remove(Constants.AttrAction); Attributes.Render(writer); if (ID != null) { writer.WriteAttribute(Constants.AttrID, GetID()); } } private string GetID() { return ClientID; } private string GetName() { return Name; } private string GetMethod() { return Method; } private string GetAction() { return Page.Request.RawUrl; } } } --- NEW FILE: RewriteProcessing.cs --- // UrlRewriter - A .NET URL Rewriter module // Version 1.7 // // Copyright 2006 Intelligencia // Copyright 2006 Seth Yates // using System; namespace Intelligencia.UrlRewriter { /// <summary> /// Processing flag. Tells the rewriter how to continue processing (or not). /// </summary> public enum RewriteProcessing { /// <summary> /// Continue processing at the next rule. /// </summary> ContinueProcessing, /// <summary> /// Halt processing. /// </summary> StopProcessing, /// <summary> /// Restart processing at the first rule. /// </summary> RestartProcessing } } --- NEW FILE: AssemblyInfo.cs --- // UrlRewriter - A .NET URL Rewriter module // Version 1.7 // // Copyright 2006 Intelligencia // Copyright 2006 Seth Yates // using System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("UrlRewriter")] [assembly: AssemblyDescription("An extendible, rule-based URL Rewriter for .NET")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Intelligencia")] [assembly: AssemblyProduct("UrlRewriter")] [assembly: AssemblyCopyright("(C) 2006 Intelligencia, (C) 2006 Seth Yates")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: AssemblyVersion("1.7.0.0")] [assembly: AssemblyDelaySign(false)] [assembly: AssemblyKeyFile("")] [assembly: AssemblyKeyName("")] --- NEW FILE: RewriterEngine.cs --- // UrlRewriter - A .NET URL Rewriter module // Version 1.7 // // Copyright 2006 Intelligencia // Copyright 2006 Seth Yates // using System; using System.IO; using System.Xml; using System.Net; using System.Web; using System.Web.Caching; using System.Configuration; using System.Collections; using System.Collections.Specialized; using System.Text.RegularExpressions; using Intelligencia.UrlRewriter.Configuration; using Intelligencia.UrlRewriter.Actions; using Intelligencia.UrlRewriter.Errors; using Intelligencia.UrlRewriter.Conditions; using Intelligencia.UrlRewriter.Utilities; namespace Intelligencia.UrlRewriter { /// <summary> /// The core RewriterEngine class. /// </summary> public class RewriterEngine { /// <summary> /// Constructor. /// </summary> /// <param name="contextFacade">The context facade to use.</param> /// <param name="configuration">The configuration to use.</param> public RewriterEngine(IContextFacade contextFacade, RewriterConfiguration configuration) { ContextFacade = contextFacade; _configuration = configuration; } /// <summary> /// Resolves an Application-path relative location /// </summary> /// <param name="location">The location</param> /// <returns>The absolute location.</returns> public string ResolveLocation(string location) { string appPath = ContextFacade.GetApplicationPath(); if (appPath.Length > 1) { appPath += "/"; } return location.Replace("~/", appPath); } /// <summary> /// Performs the rewriting. /// </summary> public void Rewrite() { string originalUrl = ContextFacade.GetRawUrl(); // Create the context RewriteContext context = new RewriteContext(this, originalUrl, ContextFacade.GetHttpMethod(), new RewriteContext.MapPathDelegate(ContextFacade.MapPath), ContextFacade.GetServerVariables(), ContextFacade.GetHeaders(), ContextFacade.GetCookies()); // Process each rule. ProcessRules(context); // Append any headers defined. AppendHeaders(context); // Append any cookies defined. AppendCookies(context); // Rewrite the path if the location has changed. ContextFacade.SetStatusCode((int)context.StatusCode); if ((context.Location != originalUrl) && ((int)context.StatusCode < 400)) { if ((int)context.StatusCode < 300) { // Successful status if less than 300 _configuration.Logger.Info(MessageProvider.FormatString(Message.RewritingXtoY, ContextFacade.GetRawUrl(), context.Location)); // Verify that the url exists on this server. VerifyResultExists(context); ContextFacade.RewritePath(context.Location); } else { // Redirection _configuration.Logger.Info(MessageProvider.FormatString(Message.RedirectingXtoY, ContextFacade.GetRawUrl(), context.Location)); ContextFacade.SetRedirectLocation(context.Location); } } else if ((int)context.StatusCode >= 400) { HandleError(context); } // Sets the context items. SetContextItems(context); } /// <summary> /// Expands the given input based on the current context. /// </summary> /// <param name="context">The current context</param> /// <param name="input">The input to expand.</param> /// <returns>The expanded input</returns> public string Expand(RewriteContext context, string input) { /* replacement :- $n * | ${[a-zA-Z0-9\-]+} * | ${fn( <replacement> )} * | ${<replacement-or-id>:<replacement-or-value>:<replacement-or-value>} * * replacement-or-id :- <replacement> | <id> * replacement-or-value :- <replacement> | <value> */ /* $1 - regex replacement * ${propertyname} * ${map-name:value} map-name is replacement, value is replacement * ${map-name:value|default-value} map-name is replacement, value is replacement, default-value is replacement * ${fn(value)} value is replacement */ StringReader reader = new StringReader(input); StringWriter writer = new StringWriter(); char ch = (char)reader.Read(); while (ch != (char)65535) { if ((char)ch == '$') { writer.Write(Reduce(context, reader)); } else { writer.Write((char)ch); } ch = (char)reader.Read(); } return writer.GetStringBuilder().ToString(); } private void ProcessRules(RewriteContext context) { const int MaxRestart = 10; // Controls the number of restarts so we don't get into an infinite loop IList rewriteRules = _configuration.Rules; int restarts = 0; for (int i = 0; i < rewriteRules.Count; i++) { // If the rule is conditional, ensure the conditions are met. IRewriteCondition condition = rewriteRules[i] as IRewriteCondition; if (condition == null || condition.IsMatch(context)) { // Execute the action. IRewriteAction action = rewriteRules[i] as IRewriteAction; action.Execute(context); // If the action is Stop, then break out of the processing loop if (action.Processing == RewriteProcessing.StopProcessing) { _configuration.Logger.Debug(MessageProvider.FormatString(Message.StoppingBecauseOfRule)); break; } else if (action.Processing == RewriteProcessing.RestartProcessing) { _configuration.Logger.Debug(MessageProvider.FormatString(Message.RestartingBecauseOfRule)); // Restart from the first rule. i = 0; if (++restarts > MaxRestart) { throw new InvalidOperationException(MessageProvider.FormatString(Message.TooManyRestarts)); } } } } } private void VerifyResultExists(RewriteContext context) { if ((String.Compare(context.Location, ContextFacade.GetRawUrl()) != 0) && ((int)context.StatusCode < 300)) { Uri uri = new Uri(ContextFacade.GetRequestUrl(), context.Location); if (uri.Host == ContextFacade.GetRequestUrl().Host) { string filename = ContextFacade.MapPath(uri.AbsolutePath); if (!File.Exists(filename)) { _configuration.Logger.Debug(MessageProvider.FormatString(Message.ResultNotFound, filename)); context.StatusCode = HttpStatusCode.NotFound; } } } } private void HandleError(RewriteContext context) { // Return the status code. ContextFacade.SetStatusCode((int)context.StatusCode); // Get the error handler if there is one. IRewriteErrorHandler handler = _configuration.ErrorHandlers[(int)context.StatusCode] as IRewriteErrorHandler; if (handler != null) { try { _configuration.Logger.Debug(MessageProvider.FormatString(Message.CallingErrorHandler)); // Execute the error handler. ContextFacade.HandleError(handler); } catch (HttpException) { throw; } catch (Exception exc) { _configuration.Logger.Fatal(exc.Message, exc); throw new HttpException((int)HttpStatusCode.InternalServerError, HttpStatusCode.InternalServerError.ToString()); } } else { throw new HttpException((int)context.StatusCode, context.StatusCode.ToString()); } } private void AppendHeaders(RewriteContext context) { foreach (string headerKey in context.Headers) { ContextFacade.AppendHeader(headerKey, context.Headers[headerKey]); } } private void AppendCookies(RewriteContext context) { for (int i = 0; i < context.Cookies.Count; i++) { HttpCookie cookie = context.Cookies[i]; ContextFacade.AppendCookie(cookie); } } private void SetContextItems(RewriteContext context) { OriginalQueryString = new Uri(ContextFacade.GetRequestUrl(), ContextFacade.GetRawUrl()).Query.Replace("?", ""); QueryString = new Uri(ContextFacade.GetRequestUrl(), context.Location).Query.Replace("?", ""); } /// <summary> /// The original query string. /// </summary> public string OriginalQueryString { get { return (string)ContextFacade.GetItem(ContextOriginalQueryString); } set { ContextFacade.SetItem(ContextOriginalQueryString, value); } } /// <summary> /// The final querystring, after rewriting. /// </summary> public string QueryString { get { return (string)ContextFacade.GetItem(ContextQueryString); } set { ContextFacade.SetItem(ContextQueryString, value); } } private string Reduce(RewriteContext context, StringReader reader) { string result; char ch = (char)reader.Read(); if (Char.IsDigit(ch)) { string num = ch.ToString(); if (Char.IsDigit((char)reader.Peek())) { ch = (char)reader.Read(); num += ch.ToString(); } if (context.LastMatch != null) { Group group = context.LastMatch.Groups[Convert.ToInt32(num)]; if (group != null) { result = group.Value; } else { result = String.Empty; } } else { result = String.Empty; } } else if (ch == '<') { StringWriter writer = new StringWriter(); ch = (char)reader.Read(); while (ch != '>' && ch != (char)65535) { if (ch == '$') { writer.Write(Reduce(context, reader)); } else { writer.Write(ch); } ch = (char)reader.Read(); } string expr = writer.GetStringBuilder().ToString(); if (context.LastMatch != null) { Group group = context.LastMatch.Groups[expr]; if (group != null) { result = group.Value; } else { result = String.Empty; } } else { result = String.Empty; } } else if (ch == '{') { StringWriter writer = new StringWriter(); bool isMap = false; bool isFunction = false; ch = (char)reader.Read(); while (ch != '}' && ch != (char)65535) { if (ch == '$') { writer.Write(Reduce(context, reader)); } else { if (ch == ':') isMap = true; else if (ch == '(') isFunction = true; writer.Write(ch); } ch = (char)reader.Read(); } string expr = writer.GetStringBuilder().ToString(); if (isMap) { Match match = Regex.Match(expr, @"^([^\:]+)\:([^\|]+)(\|(.+))?$"); string mapName = match.Groups[1].Value; string mapArgument = match.Groups[2].Value; string mapDefault = match.Groups[4].Value; result = _configuration.TransformFactory.GetTransform(mapName).ApplyTransform(mapArgument); if (result == null) { result = mapDefault; } } else if (isFunction) { Match match = Regex.Match(expr, @"^([^\(]+)\(([^\)]+)\)$"); string functionName = match.Groups[1].Value; string functionArgument = match.Groups[2].Value; result = _configuration.TransformFactory.GetTransform(functionName).ApplyTransform(functionArgument); } else { result = context.Properties[expr]; } } else { result = ch.ToString(); } return result; } private const string ContextQueryString = "UrlRewriter.NET.QueryString"; private const string ContextOriginalQueryString = "UrlRewriter.NET.OriginalQueryString"; private RewriterConfiguration _configuration; private IContextFacade ContextFacade; } } --- NEW FILE: Intelligencia.UrlRewriter.csproj --- (This appears to be a binary file; contents omitted.) --- NEW FILE: Messages.resx --- <?xml version="1.0" encoding="utf-8" ?> <root> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:element name="root" msdata:IsDataSet="true"> <xsd:complexType> <xsd:choice maxOccurs="unbounded"> <xsd:element name="data"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" /> <xsd:attribute name="type" type="xsd:string" /> <xsd:attribute name="mimetype" type="xsd:string" /> </xsd:complexType> </xsd:element> <xsd:element name="resheader"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required" /> </xsd:complexType> </xsd:element> </xsd:choice> </xsd:complexType> </xsd:element> </xsd:schema> <resheader name="ResMimeType"> <value>text/microsoft-resx</value> </resheader> <resheader name="Version"> <value>1.0.0.0</value> </resheader> <resheader name="Reader"> <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> <resheader name="Writer"> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> <data name="MappedValuesNotAllowed"> <value>Mapped values are not allowed if a mapper type is specified.</value> </data> <data name="ElementNotAllowed"> <value>The element '{0}' is not allowed.</value> </data> <data name="ValueOfProcessingAttribute"> <value>The value '{0}' of the processing attribute is invalid. It must be either '{1}', '{2}' or '{3}'.</value> </data> <data name="AttributeNotAllowed"> <value>The attribute '{0}' is not allowed.</value> </data> <data name="ElementNoAttributes"> <value>The '{0}' element does not allow attributes.</value> </data> <data name="ElementNoElements"> <value>The '{0}' element does not allow nested elements.</value> </data> <data name="AttributeRequired"> <value>The attribute '{0}' is required.</value> </data> <data name="TypeNameRequired"> <value>Type name is required.</value> </data> <data name="InvalidTypeSpecified"> <value>Type is specified does not support the required interface.</value> </data> <data name="AssemblyNameRequired"> <value>Assembly name is required.</value> </data> <data name="FullTypeNameRequiresAssemblyName"> <value>Full type name must include assembly name.</value> </data> <data name="MapAlreadyDefined"> <value>Map '{0}' has already been defined.</value> </data> <data name="InputIsNotHex"> <value>The input is not hex.</value> </data> <data name="AddressesNotOfSameType"> <value>Addresses are not of the same type.</value> </data> <data name="ProductName"> <value>UrlRewriter.NET {0}</value> </data> <data name="StoppingBecauseOfRule"> <value>Stopping because of rule.</value> </data> <data name="RestartingBecauseOfRule"> <value>Restarting because of rule.</value> </data> <data name="ResultNotFound"> <value>Result '{0}' not found.</value> </data> <data name="CallingErrorHandler"> <value>Calling error handler.</value> </data> <data name="RewritingXtoY"> <value>Rewriting '{0}' to '{1}'.</value> </data> <data name="RedirectingXtoY"> <value>Redirecting '{0}' to '{1}'.</value> </data> <data name="TooManyRestarts"> <value>As configured, the rules caused too many restarts. Please review your rewriting rules and ensure there are no infinite loops.</value> </data> </root> --- NEW FILE: RewriteContext.cs --- // UrlRewriter - A .NET URL Rewriter module // Version 1.7 // // Copyright 2006 Intelligencia // Copyright 2006 Seth Yates // using System; using System.IO; using System.Net; using System.Xml; using System.Web; using System.Web.Caching; using System.Configuration; using System.Text.RegularExpressions; using System.Collections.Specialized; using Intelligencia.UrlRewriter.Configuration; namespace Intelligencia.UrlRewriter { /// <summary> /// Encapsulates all rewriting information about an individual rewrite request. This class cannot be inherited. /// </summary> /// <remarks> /// This class cannot be created directly. It will be provided to actions and conditions /// by the framework. /// </remarks> public sealed class RewriteContext { internal delegate string MapPathDelegate(string url); /// <summary> /// Default constructor. /// </summary> /// <param name="engine">The rewriting engine.</param> /// <param name="rawUrl">The initial, raw URL.</param> /// <param name="httpMethod">The HTTP method used (GET, POST, ...)</param> /// <param name="mapPath">The method to use for mapping paths.</param> /// <param name="serverVariables">Collection of server variables.</param> /// <param name="headers">Collection of headers.</param> /// <param name="cookies">Collection of cookies.</param> internal RewriteContext(RewriterEngine engine, string rawUrl, string httpMethod, MapPathDelegate mapPath, NameValueCollection serverVariables, NameValueCollection headers, HttpCookieCollection cookies) { _engine = engine; _location = rawUrl; _method = httpMethod; _mapPath = mapPath; foreach (string key in serverVariables) { _properties.Add(key, serverVariables[key]); } foreach (string key in headers) { _properties.Add(key, headers[key]); } foreach (string key in cookies) { _properties.Add(key, cookies[key].Value); } } /// <summary> /// Maps the given URL to the absolute local path. /// </summary> /// <param name="url">The URL to map.</param> /// <returns>The absolute local file path relating to the url.</returns> public string MapPath(string url) { return _mapPath(url); } /// <summary> /// The current location being rewritten. /// </summary> /// <remarks> /// This property starts out as Request.RawUrl and is altered by various /// rewrite actions. /// </remarks> public string Location { get { return _location; } set { _location = value; } } /// <summary> /// The request method (GET, PUT, POST, HEAD, DELETE). /// </summary> public string Method { get { return _method; } } /// <summary> /// The Processing flag. /// </summary> private RewriteProcessing Processing { get { return _processing; } set { _processing = value; } } /// <summary> /// The properties for the context, including headers and cookie values. /// </summary> public NameValueCollection Properties { get { return _properties; } } /// <summary> /// Output headers. /// </summary> /// <remarks> /// This collection is the collection of headers to add to the response. /// For the headers sent in the request, use the <see cref="RewriteContext.Properties">Properties</see> property. /// </remarks> public NameValueCollection Headers { get { return _headers; } } /// <summary> /// The status code to send in the response. /// </summary> public HttpStatusCode StatusCode { get { return _statusCode; } set { _statusCode = value; } } /// <summary> /// Collection of output cookies. /// </summary> /// <remarks> /// This is the collection of cookies to send in the response. For the cookies /// received in the request, use the <see cref="RewriteContext.Properties">Properties</see> property. /// </remarks> public HttpCookieCollection Cookies { get { return _cookies; } } /// <summary> /// Last matching pattern from a match (if any). /// </summary> public Match LastMatch { get { return _lastMatch; } set { _lastMatch = value; } } /// <summary> /// Expands the given input using the last match, properties, maps and transforms. /// </summary> /// <param name="input">The input to expand.</param> /// <returns>The expanded form of the input.</returns> public string Expand(string input) { return _engine.Expand(this, input); } /// <summary> /// Resolves the location to an absolute reference. /// </summary> /// <param name="location">The application-referenced location.</param> /// <returns>The absolute location.</returns> public string ResolveLocation(string location) { return _engine.ResolveLocation(location); } private RewriterEngine _engine; private string _method = String.Empty; private HttpStatusCode _statusCode = HttpStatusCode.OK; private RewriteProcessing _processing = RewriteProcessing.ContinueProcessing; private string _location; private NameValueCollection _properties = new NameValueCollection(); private NameValueCollection _headers = new NameValueCollection(); private HttpCookieCollection _cookies = new HttpCookieCollection(); private Match _lastMatch = null; private MapPathDelegate _mapPath; } } |