Skip to content

Commit cd0af65

Browse files
committed
Reserving "runtime" route
1 parent b490a2c commit cd0af65

File tree

3 files changed

+81
-68
lines changed

3 files changed

+81
-68
lines changed

src/WebJobs.Script.WebHost/Controllers/FunctionsController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,15 @@ public IActionResult Invoke(string name, [FromBody] FunctionInvocation invocatio
121121
[HttpGet]
122122
[Route("admin/functions/{name}/status")]
123123
[Authorize(Policy = PolicyNames.AdminAuthLevel)]
124-
public async Task<IActionResult> GetFunctionStatus(string name, [FromServices] IScriptJobHost scriptHost)
124+
public async Task<IActionResult> GetFunctionStatus(string name, [FromServices] IScriptJobHost scriptHost = null)
125125
{
126126
FunctionStatus status = new FunctionStatus();
127127

128128
// first see if the function has any errors
129129
// if the host is not running or is offline
130130
// there will be no error info
131-
if (scriptHost.FunctionErrors.TryGetValue(name, out ICollection<string> functionErrors))
131+
if (scriptHost != null &&
132+
scriptHost.FunctionErrors.TryGetValue(name, out ICollection<string> functionErrors))
132133
{
133134
status.Errors = functionErrors;
134135
}

src/WebJobs.Script/Host/ScriptHost.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,8 @@ internal static void ValidateHttpFunction(string functionName, HttpTriggerAttrib
764764

765765
// disallow custom routes in our own reserved route space
766766
string httpRoute = httpTrigger.Route.Trim('/').ToLowerInvariant();
767-
if (httpRoute.StartsWith("admin"))
767+
if (httpRoute.StartsWith("admin") ||
768+
httpRoute.StartsWith("runtime"))
768769
{
769770
throw new InvalidOperationException("The specified route conflicts with one or more built in routes.");
770771
}

test/WebJobs.Script.Tests/ScriptHostTests.cs

Lines changed: 76 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -927,67 +927,6 @@ public async Task InitializeRpcService_Throws()
927927
Assert.Equal("Failed to start Grpc Service. Check if your app is hitting connection limits.", ex.Message);
928928
}
929929

930-
#if WEBROUTING
931-
[Fact]
932-
public void HttpRoutesConflict_ReturnsExpectedResult()
933-
{
934-
var first = new HttpTriggerAttribute
935-
{
936-
Route = "foo/bar/baz"
937-
};
938-
var second = new HttpTriggerAttribute
939-
{
940-
Route = "foo/bar"
941-
};
942-
Assert.False(ScriptHost.HttpRoutesConflict(first, second));
943-
Assert.False(ScriptHost.HttpRoutesConflict(second, first));
944-
945-
first = new HttpTriggerAttribute
946-
{
947-
Route = "foo/bar/baz"
948-
};
949-
second = new HttpTriggerAttribute
950-
{
951-
Route = "foo/bar/baz"
952-
};
953-
Assert.True(ScriptHost.HttpRoutesConflict(first, second));
954-
Assert.True(ScriptHost.HttpRoutesConflict(second, first));
955-
956-
// no conflict since methods do not intersect
957-
first = new HttpTriggerAttribute(AuthorizationLevel.Function, "get", "head")
958-
{
959-
Route = "foo/bar/baz"
960-
};
961-
second = new HttpTriggerAttribute(AuthorizationLevel.Function, "post", "put")
962-
{
963-
Route = "foo/bar/baz"
964-
};
965-
Assert.False(ScriptHost.HttpRoutesConflict(first, second));
966-
Assert.False(ScriptHost.HttpRoutesConflict(second, first));
967-
968-
first = new HttpTriggerAttribute(AuthorizationLevel.Function, "get", "head")
969-
{
970-
Route = "foo/bar/baz"
971-
};
972-
second = new HttpTriggerAttribute
973-
{
974-
Route = "foo/bar/baz"
975-
};
976-
Assert.True(ScriptHost.HttpRoutesConflict(first, second));
977-
Assert.True(ScriptHost.HttpRoutesConflict(second, first));
978-
979-
first = new HttpTriggerAttribute(AuthorizationLevel.Function, "get", "head", "put", "post")
980-
{
981-
Route = "foo/bar/baz"
982-
};
983-
second = new HttpTriggerAttribute(AuthorizationLevel.Function, "put")
984-
{
985-
Route = "foo/bar/baz"
986-
};
987-
Assert.True(ScriptHost.HttpRoutesConflict(first, second));
988-
Assert.True(ScriptHost.HttpRoutesConflict(second, first));
989-
}
990-
991930
[Fact]
992931
public void ValidateFunction_ValidatesHttpRoutes()
993932
{
@@ -1056,16 +995,88 @@ public void ValidateFunction_ValidatesHttpRoutes()
1056995
});
1057996
Assert.Equal("The specified route conflicts with one or more built in routes.", ex.Message);
1058997

1059-
// verify that empty route is defaulted to function name
998+
// try to add a route under reserved runtime route
1060999
function = new Mock<FunctionDescriptor>(MockBehavior.Strict, "test6", null, metadata, null, null, null, null);
1000+
attribute = new HttpTriggerAttribute
1001+
{
1002+
Route = "runtime/foo/bar"
1003+
};
1004+
function.Setup(p => p.GetTriggerAttributeOrNull<HttpTriggerAttribute>()).Returns(() => attribute);
1005+
ex = Assert.Throws<InvalidOperationException>(() =>
1006+
{
1007+
ScriptHost.ValidateFunction(function.Object, httpFunctions);
1008+
});
1009+
Assert.Equal("The specified route conflicts with one or more built in routes.", ex.Message);
1010+
1011+
// verify that empty route is defaulted to function name
1012+
function = new Mock<FunctionDescriptor>(MockBehavior.Strict, "test7", null, metadata, null, null, null, null);
10611013
attribute = new HttpTriggerAttribute();
10621014
function.Setup(p => p.GetTriggerAttributeOrNull<HttpTriggerAttribute>()).Returns(() => attribute);
10631015
ScriptHost.ValidateFunction(function.Object, httpFunctions);
10641016
Assert.Equal(4, httpFunctions.Count);
1065-
Assert.True(httpFunctions.ContainsKey("test6"));
1066-
Assert.Equal("test6", attribute.Route);
1017+
Assert.True(httpFunctions.ContainsKey("test7"));
1018+
Assert.Equal("test7", attribute.Route);
1019+
}
1020+
1021+
[Fact]
1022+
public void HttpRoutesConflict_ReturnsExpectedResult()
1023+
{
1024+
var first = new HttpTriggerAttribute
1025+
{
1026+
Route = "foo/bar/baz"
1027+
};
1028+
var second = new HttpTriggerAttribute
1029+
{
1030+
Route = "foo/bar"
1031+
};
1032+
Assert.False(ScriptHost.HttpRoutesConflict(first, second));
1033+
Assert.False(ScriptHost.HttpRoutesConflict(second, first));
1034+
1035+
first = new HttpTriggerAttribute
1036+
{
1037+
Route = "foo/bar/baz"
1038+
};
1039+
second = new HttpTriggerAttribute
1040+
{
1041+
Route = "foo/bar/baz"
1042+
};
1043+
Assert.True(ScriptHost.HttpRoutesConflict(first, second));
1044+
Assert.True(ScriptHost.HttpRoutesConflict(second, first));
1045+
1046+
// no conflict since methods do not intersect
1047+
first = new HttpTriggerAttribute(AuthorizationLevel.Function, "get", "head")
1048+
{
1049+
Route = "foo/bar/baz"
1050+
};
1051+
second = new HttpTriggerAttribute(AuthorizationLevel.Function, "post", "put")
1052+
{
1053+
Route = "foo/bar/baz"
1054+
};
1055+
Assert.False(ScriptHost.HttpRoutesConflict(first, second));
1056+
Assert.False(ScriptHost.HttpRoutesConflict(second, first));
1057+
1058+
first = new HttpTriggerAttribute(AuthorizationLevel.Function, "get", "head")
1059+
{
1060+
Route = "foo/bar/baz"
1061+
};
1062+
second = new HttpTriggerAttribute
1063+
{
1064+
Route = "foo/bar/baz"
1065+
};
1066+
Assert.True(ScriptHost.HttpRoutesConflict(first, second));
1067+
Assert.True(ScriptHost.HttpRoutesConflict(second, first));
1068+
1069+
first = new HttpTriggerAttribute(AuthorizationLevel.Function, "get", "head", "put", "post")
1070+
{
1071+
Route = "foo/bar/baz"
1072+
};
1073+
second = new HttpTriggerAttribute(AuthorizationLevel.Function, "put")
1074+
{
1075+
Route = "foo/bar/baz"
1076+
};
1077+
Assert.True(ScriptHost.HttpRoutesConflict(first, second));
1078+
Assert.True(ScriptHost.HttpRoutesConflict(second, first));
10671079
}
1068-
#endif
10691080

10701081
[Fact]
10711082
public void ValidateFunction_ThrowsOnDuplicateName()

0 commit comments

Comments
 (0)