Skip to content

Commit

Permalink
Temp solution for URI with backslash and slash
Browse files Browse the repository at this point in the history
  • Loading branch information
chinadragon0515 committed Jun 6, 2016
1 parent 0cddf3f commit 589bb5a
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,17 @@ public static Task<ODataRoute> MapRestierRoute<TApi>(
batchHandler.ApiFactory = apiFactory;
}


// Customized path handler should be added in ConfigureApi as service
// Allow to handle URL encoded slash (%2F), and backslash(%5C) with customized handler
var handler = api.Context.GetApiService<IODataPathHandler>();
if (handler == null)
{
handler = new DefaultODataPathHandler();
}

var route = config.MapODataServiceRoute(
routeName, routePrefix, model, new DefaultODataPathHandler(), conventions, batchHandler);
routeName, routePrefix, model, handler, conventions, batchHandler);

// Customized converter should be added in ConfigureApi as service
var converter = api.Context.GetApiService<ODataPayloadValueConverter>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,24 @@ public void AddressingPropertyValue()
TestGetStatusCodeIs("People(1)/LastName/$value", 200);
}

[Fact]
public void AddressingKeyWithSlash()
{
TestGetStatusCodeIs("Airlines(AirlineCode='S%2F')", 200);
}

[Fact]
public void AddressingKeyWithSlashDoubleEscape()
{
TestGetStatusCodeIs("Airlines(AirlineCode='S%252F')", 200);
}

[Fact]
public void AddressingKeyWithBackSlash()
{
TestGetStatusCodeIs("Airlines(AirlineCode='BS%255C')", 200);
}

[Fact]
public void AddressingCollectionCount()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
using System.Threading;
using System.Threading.Tasks;
using System.Web.OData.Query;
using System.Web.OData.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OData.Core;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Library;
using Microsoft.OData.Edm.Library.Annotations;
using Microsoft.OData.Edm.Library.Values;
using Microsoft.OData.Service.Sample.Trippin.Extension;
using Microsoft.OData.Service.Sample.Trippin.Models;
using Microsoft.OData.Service.Sample.Trippin.Submit;
using Microsoft.Restier.Core;
using Microsoft.Restier.Core.Model;
using Microsoft.Restier.Core.Submit;
Expand Down Expand Up @@ -150,7 +151,7 @@ protected bool CanDeleteTrips()

protected override IServiceCollection ConfigureApi(IServiceCollection services)
{
// Add customized OData valiadtion settings
// Add customized OData validation settings
Func<IServiceProvider, ODataValidationSettings> validationSettingFactory = (sp) => new ODataValidationSettings
{
MaxAnyAllExpressionDepth =3,
Expand All @@ -160,6 +161,7 @@ protected override IServiceCollection ConfigureApi(IServiceCollection services)
return base.ConfigureApi(services)
.AddSingleton<ODataPayloadValueConverter, CustomizedPayloadValueConverter>()
.AddSingleton<ODataValidationSettings>(validationSettingFactory)
.AddSingleton<IODataPathHandler, PathAndSlashEscapeODataPathHandler>()
.AddService<IChangeSetItemProcessor, CustomizedSubmitProcessor>()
.AddService<IModelBuilder, TrippinModelExtender>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Threading.Tasks;
using Microsoft.Restier.Core.Submit;

namespace Microsoft.OData.Service.Sample.Trippin.Submit
namespace Microsoft.OData.Service.Sample.Trippin.Extension
{
public class CustomizedSubmitProcessor : IChangeSetItemProcessor
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System;
using System.Text;
using System.Web.OData.Routing;
using Microsoft.OData.Edm;

namespace Microsoft.OData.Service.Sample.Trippin.Extension
{
/// <summary>
/// This class is similar to class PathAndSlashEscapeODataPathHandler.cs in Web API OData samples ODataPathAndSlashEscapeSample.
/// There are two major purpose of this class
/// 1. When URL has %2F, it will be converted to "/" by IIS, need to convert back to "%2F", also need to make Web Api code does not convert again.
/// 2. When URL has %5C, it will be converted to "/" but not "\" by IIS, so "\" need to use double escape
/// 3. When URL use double escape, need to change back to single escape.
///
/// For end user case, slash does not need double escape, but backslash need double escape.
/// For data stored in database, it is not escaped.
/// TODO, need to revisit when key alias is supported, which is tracked with https://github.com/OData/odata.net/issues/570
/// </summary>
public class PathAndSlashEscapeODataPathHandler : DefaultODataPathHandler
{

private const string EscapedQuote = "'";

public override ODataPath Parse(IEdmModel model, string serviceRoot, string odataPath)
{
if (!odataPath.Contains(EscapedQuote))
{
return base.Parse(model, serviceRoot, odataPath);
}

var pathBuilder = new StringBuilder();
var queryStringIndex = odataPath.IndexOf('?');
if (queryStringIndex == -1)
{
// In case there is double escape, replace them
odataPath = odataPath.Replace("%255C", "%5C").Replace("%252F", "%2F");
EscapeSlashBackslash(odataPath, pathBuilder);
}
else
{
var path = odataPath.Substring(0, queryStringIndex);
// In case there is double escape, replace them
path = path.Replace("%255C", "%5C").Replace("%252F", "%2F");
EscapeSlashBackslash(path, pathBuilder);
pathBuilder.Append(odataPath.Substring(queryStringIndex));
}
return base.Parse(model, serviceRoot, pathBuilder.ToString());
}

private void EscapeSlashBackslash(string uri, StringBuilder pathBuilder)
{
const string slash = "%2F";
const string backSlash = "%5C";

var startIndex = uri.IndexOf(EscapedQuote, StringComparison.OrdinalIgnoreCase);
var endIndex = uri.IndexOf(EscapedQuote, startIndex + EscapedQuote.Length, StringComparison.OrdinalIgnoreCase);
if (startIndex == -1 || endIndex == -1)
{
pathBuilder.Append(uri);
return;
}

endIndex = endIndex + EscapedQuote.Length;
pathBuilder.Append(uri.Substring(0, startIndex));
for (var i = startIndex; i < endIndex; ++i)
{
switch (uri[i])
{
case '/':
pathBuilder.Append(slash);
break;
// There will not such case now as IIS will convert "\" to "/",need to use double escape
case '\\':
pathBuilder.Append(backSlash);
break;
default:
pathBuilder.Append(uri[i]);
break;
}
}
EscapeSlashBackslash(uri.Substring(endIndex), pathBuilder);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<Compile Include="App_Start\WebApiConfig.cs" />
<Compile Include="Controllers\TrippinController.cs" />
<Compile Include="Api\TrippinApi.cs" />
<Compile Include="Extension\PathAndSlashEscapeODataPathHandler.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
Expand All @@ -68,7 +69,7 @@
<Compile Include="Models\Trip.cs" />
<Compile Include="Models\TrippinModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Submit\CustomizedSubmitProcessor.cs" />
<Compile Include="Extension\CustomizedSubmitProcessor.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="packages.config" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,18 @@ public static void ResetDataSource()
{
Name = "Emirates",
AirlineCode = "EK"
},

new Airline
{
Name = "Slash%2F",
AirlineCode = "S/"
},

new Airline
{
Name = "BackSlash%5C",
AirlineCode = "BS\\"
}
};
instance.Airlines.AddRange(airlines);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
-->
<system.web>
<compilation debug="true" targetFramework="4.5"/>
<httpRuntime requestPathInvalidCharacters="" />
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
Expand Down Expand Up @@ -66,11 +67,21 @@
<add name="TrippinModel" connectionString="data source=(localdb)\MSSQLLocalDB;initial catalog=TRIPPINE2EDB;integrated security=True;connect timeout=30;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="true"/>
</security>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
<remove name="OPTIONSVerbHandler"/>
<remove name="TRACEVerbHandler"/>
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>
</system.webServer>
<uri>
<schemeSettings>
<clear/>
<add name="https" genericUriParserOptions="DontUnescapePathDotsAndSlashes"/>
<add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes"/>
</schemeSettings>
</uri>
</configuration>

0 comments on commit 589bb5a

Please sign in to comment.