Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved relative path checking based on file existence #411

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c1f757b
Improved relative path checking based on file existence
NoahLerner Jan 30, 2020
962824f
Apply File.Exists logic to ReadResponseBodyAsString as well
NoahLerner Jan 30, 2020
9bc737f
Make path handling more robust since path is user defined
NoahLerner Jan 30, 2020
e8a8314
Unit tests for relative path feature
NoahLerner Jan 30, 2020
66448a9
Replace all back and forward slashes with system dependent DirectoryS…
NoahLerner Jan 30, 2020
3681e64
Attempt fix broken directory separator chars for Unix platforms
NoahLerner Jan 30, 2020
88f48ac
Revert wrapping GetMappingFolder with CleanPath
NoahLerner Jan 31, 2020
11f36fc
Move CleanPath logic to its own class
NoahLerner Jan 31, 2020
3061226
Remove whitespace
NoahLerner Jan 31, 2020
01b9c5d
Remove more whitespace
NoahLerner Jan 31, 2020
7428bc0
Improve CleanPath method
NoahLerner Feb 1, 2020
d3efefc
Move PathUtils tests to separate class
NoahLerner Feb 1, 2020
add7cc2
Fix Response_ProvideResponse_WithBodyFromFile_InAdminMappingFolder
NoahLerner Feb 1, 2020
51acc6c
Debug Linux CI build
NoahLerner Feb 1, 2020
7de55ba
Debug Linux CI
NoahLerner Feb 1, 2020
6539adc
print all files from admin mappings folder
NoahLerner Feb 1, 2020
249c82e
Debug CleanPath
NoahLerner Feb 1, 2020
dcd9003
Fix removed leading directory separator char in Linux breaks file path
NoahLerner Feb 1, 2020
99f422b
Move combine to PathUtils
NoahLerner Feb 2, 2020
49fff59
PathUtils + PathUtilsTests
StefH Feb 2, 2020
51aab36
Remove replicated (3x) tests throughout ResponseWithBodyFromFileTests
NoahLerner Feb 2, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/WireMock.Net/Handlers/LocalFileSystemHandler.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using WireMock.Util;
using WireMock.Validation;

namespace WireMock.Handlers
Expand Down Expand Up @@ -80,20 +81,20 @@ public void WriteMappingFile(string path, string text)
public byte[] ReadResponseBodyAsFile(string path)
{
Check.NotNullOrEmpty(path, nameof(path));

// In case the path is a filename, the path will be adjusted to the MappingFolder.
path = PathUtils.CleanPath(path);
// If the file exists at the given path relative to the MappingsFolder, then return that.
// Else the path will just be as-is.
return File.ReadAllBytes(Path.GetFileName(path) == path ? Path.Combine(GetMappingFolder(), path) : path);
return File.ReadAllBytes(File.Exists(Path.Combine(GetMappingFolder(), path)) ? Path.Combine(GetMappingFolder(), path) : path);
}

/// <inheritdoc cref="IFileSystemHandler.ReadResponseBodyAsString"/>
public string ReadResponseBodyAsString(string path)
{
Check.NotNullOrEmpty(path, nameof(path));

path = PathUtils.CleanPath(path);
// In case the path is a filename, the path will be adjusted to the MappingFolder.
// Else the path will just be as-is.
return File.ReadAllText(Path.GetFileName(path) == path ? Path.Combine(GetMappingFolder(), path) : path);
return File.ReadAllText(File.Exists(Path.Combine(GetMappingFolder(), path)) ? Path.Combine(GetMappingFolder(), path) : path);
}

/// <inheritdoc cref="IFileSystemHandler.FileExists"/>
Expand Down
25 changes: 25 additions & 0 deletions src/WireMock.Net/Util/PathUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.IO;

namespace WireMock.Util
{
internal static class PathUtils
NoahLerner marked this conversation as resolved.
Show resolved Hide resolved
{
/// <summary>
/// Robust handling of the user defined path.
/// Gets the path string ready for Path.Combine method.
/// Also supports Unix and Windows platforms
/// </summary>
/// <param name="path">Path to clean</param>
/// <returns></returns>
public static string CleanPath(string path)
NoahLerner marked this conversation as resolved.
Show resolved Hide resolved
{
path = path.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
// remove leading directory separator character which would break Path.Combine
path = path.StartsWith(Path.DirectorySeparatorChar.ToString()) ? path.Substring(1, path.Length - 1) : path;

return path;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using FluentAssertions;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
Expand Down Expand Up @@ -45,5 +46,95 @@ public async Task Response_ProvideResponse_WithBodyFromFile()
response2.Should().Contain("<hello>world</hello>");
response3.Should().Contain("<hello>world</hello>");
}

[Fact]
public async Task Response_ProvideResponse_WithBodyFromFile_InSubDirectory()
{
// Arrange
var server = WireMockServer.Start();
int path = 0;
List<string> pathList = new List<string>()
{
@"subdirectory/MyXmlResponse.xml",
NoahLerner marked this conversation as resolved.
Show resolved Hide resolved
@"subdirectory\MyXmlResponse.xml",
@"/subdirectory/MyXmlResponse.xml",
@"\subdirectory\MyXmlResponse.xml"
};

server
.Given(
Request
.Create()
.UsingGet()
.WithPath("/v1/content/path1")
)
.RespondWith(
Response
.Create()
.WithStatusCode(HttpStatusCode.OK)
.WithHeader("Content-Type", "application/xml")
.WithBodyFromFile(pathList[path])
);

path++;
server
.Given(
Request
.Create()
.UsingGet()
.WithPath("/v1/content/path2")
)
.RespondWith(
Response
.Create()
.WithStatusCode(HttpStatusCode.OK)
.WithHeader("Content-Type", "application/xml")
.WithBodyFromFile(pathList[path])
);

path++;
server
.Given(
Request
.Create()
.UsingGet()
.WithPath("/v1/content/path3")
)
.RespondWith(
Response
.Create()
.WithStatusCode(HttpStatusCode.OK)
.WithHeader("Content-Type", "application/xml")
.WithBodyFromFile(pathList[path])
);

path++;
server
.Given(
Request
.Create()
.UsingGet()
.WithPath("/v1/content/path4")
)
.RespondWith(
Response
.Create()
.WithStatusCode(HttpStatusCode.OK)
.WithHeader("Content-Type", "application/xml")
.WithBodyFromFile(pathList[path])
);

// Act
var response1 = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + "/v1/content/path1");
var response2 = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + "/v1/content/path2");
var response3 = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + "/v1/content/path3");
var response4 = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + "/v1/content/path4");

// Assert
response1.Should().Contain("<hello>world</hello>");
response2.Should().Contain("<hello>world</hello>");
response3.Should().Contain("<hello>world</hello>");
response4.Should().Contain("<hello>world</hello>");
}
}
}
3 changes: 3 additions & 0 deletions test/WireMock.Net.Tests/WireMock.Net.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
<None Update="__admin\mappings\MyXmlResponse.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\subdirectory\MyXmlResponse.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<xml>
<hello>world</hello>
</xml>