Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion WebJobs.Script.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26906.1
VisualStudioVersion = 15.0.27130.2027
MinimumVisualStudioVersion = 15.0.0.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{16351B76-87CA-4A8C-80A1-3DD83A0C4AA6}"
EndProject
Expand Down
44 changes: 0 additions & 44 deletions src/WebJobs.Script.WebHost/Controllers/HomeController.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Azure.WebJobs.Extensions.Http;
Expand Down Expand Up @@ -37,13 +38,27 @@ public async Task Invoke(HttpContext context, WebScriptHostManager manager)
// downstream middleware and filters rely on this
context.Items.Add(ScriptConstants.AzureFunctionsHostManagerKey, manager);
SetRequestId(context.Request);
await _next(context);
if (_next != null)
{
await _next(context);
}

IFunctionExecutionFeature functionExecution = context.Features.Get<IFunctionExecutionFeature>();

int nestedProxiesCount = GetNestedProxiesCount(context, functionExecution);

IActionResult result = null;

if (functionExecution != null && !context.Response.HasStarted)
{
IActionResult result = await GetResultAsync(context, functionExecution);
result = await GetResultAsync(context, functionExecution);

if (nestedProxiesCount > 0)
{
// if Proxy, the rest of the pipleline will be processed bt Proxies in case there are response overrides and what not.
SetProxyResult(context, nestedProxiesCount, result);
return;
}

var actionContext = new ActionContext
{
Expand All @@ -54,6 +69,33 @@ public async Task Invoke(HttpContext context, WebScriptHostManager manager)
}
}

private static void SetProxyResult(HttpContext context, int nestedProxiesCount, IActionResult result)
{
context.Items.Add(ScriptConstants.AzureFunctionsProxyResult, result);

context.Items[ScriptConstants.AzureFunctionsNestedProxyCount] = nestedProxiesCount - 1;
}

private static int GetNestedProxiesCount(HttpContext context, IFunctionExecutionFeature functionExecution)
{
context.Items.TryGetValue(ScriptConstants.AzureFunctionsNestedProxyCount, out object nestedProxiesCount);

//HttpBufferingService is disabled for non - proxy functions.
if (functionExecution != null && !functionExecution.Descriptor.Metadata.IsProxy && nestedProxiesCount == null)
{
var bufferingFeature = context.Features.Get<IHttpBufferingFeature>();
bufferingFeature?.DisableRequestBuffering();
bufferingFeature?.DisableResponseBuffering();
}

if (nestedProxiesCount != null)
{
return (int)nestedProxiesCount;
}

return 0;
}

private async Task<IActionResult> GetResultAsync(HttpContext context, IFunctionExecutionFeature functionExecution)
{
if (functionExecution.Descriptor == null)
Expand Down
78 changes: 78 additions & 0 deletions src/WebJobs.Script.WebHost/Middleware/HomepageMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs.Script.Config;
using Microsoft.Azure.WebJobs.Script.WebHost.Features;

namespace Microsoft.Azure.WebJobs.Script.WebHost.Middleware
{
public class HomepageMiddleware
{
private readonly RequestDelegate _next;

public HomepageMiddleware(RequestDelegate next)
{
_next = next;
}

public static bool IsHomepageDisabled
{
get
{
return string.Equals(ScriptSettingsManager.Instance.GetSetting(EnvironmentSettingNames.AzureWebJobsDisableHomepage),
bool.TrueString, StringComparison.OrdinalIgnoreCase);
}
}

public async Task Invoke(HttpContext context, WebScriptHostManager manager)
{
await _next(context);

IFunctionExecutionFeature functionExecution = context.Features.Get<IFunctionExecutionFeature>();

if (functionExecution == null
&& context.Request.Path.Value == "/")
{
IActionResult result = null;

if (IsHomepageDisabled)
{
result = new NoContentResult();
}
else
{
result = new ContentResult()
{
Content = GetHomepage(),
ContentType = "text/html",
StatusCode = 200
};
}

if (!context.Response.HasStarted)
{
var actionContext = new ActionContext
{
HttpContext = context
};

await result.ExecuteResultAsync(actionContext);
}
}
}

private string GetHomepage()
{
var assembly = typeof(HomepageMiddleware).Assembly;
using (Stream resource = assembly.GetManifestResourceStream(assembly.GetName().Name + ".Home.html"))
using (var reader = new StreamReader(resource))
{
return reader.ReadToEnd();
}
}
}
}
124 changes: 124 additions & 0 deletions src/WebJobs.Script.WebHost/Proxy/ProxyFunctionExecutor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Azure.AppService.Proxy.Client;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Logging;
using Microsoft.Azure.WebJobs.Script.Config;
using Microsoft.Azure.WebJobs.Script.Description;
using Microsoft.Azure.WebJobs.Script.WebHost.Features;
using Microsoft.Azure.WebJobs.Script.WebHost.Middleware;
using Microsoft.Azure.WebJobs.Script.WebHost.Security.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;

namespace Microsoft.Azure.WebJobs.Script.WebHost.Proxy
{
public class ProxyFunctionExecutor : IFuncExecutor
{
private readonly WebScriptHostManager _scriptHostManager;

internal ProxyFunctionExecutor(WebScriptHostManager scriptHostManager)
{
_scriptHostManager = scriptHostManager;
}

public async Task<IActionResult> ExecuteFuncAsync(string functionName, Dictionary<string, object> arguments, CancellationToken cancellationToken)
{
var request = arguments[ScriptConstants.AzureFunctionsHttpRequestKey] as HttpRequest;

if (CheckForInfiniteLoop(request))
{
return new BadRequestObjectResult("Infinite loop detected when trying to call a local function or proxy from a proxy.");
}

var httpContext = request.HttpContext;

httpContext.Items.Add(HttpExtensionConstants.AzureWebJobsUseReverseRoutesKey, true);

var route = httpContext.GetRouteData();

RouteContext rc = new RouteContext(httpContext);

foreach (var router in route.Routers)
{
if (router is WebJobsRouter webJobsRouter)
{
await webJobsRouter.RouteAsync(rc);

if (rc.Handler != null)
{
break;
}
}
}

httpContext.Items.Remove(HttpExtensionConstants.AzureWebJobsUseReverseRoutesKey);
httpContext.Items.Remove(ScriptConstants.AzureFunctionsHostManagerKey);

if (rc.Handler == null)
{
return new NotFoundResult();
}

await rc.Handler.Invoke(httpContext);

FunctionInvocationMiddleware functionInvocationMiddleware = new FunctionInvocationMiddleware(null);

if (!httpContext.Items.TryGetValue(ScriptConstants.AzureFunctionsNestedProxyCount, out object nestedProxiesCount))
{
httpContext.Items.Add(ScriptConstants.AzureFunctionsNestedProxyCount, 1);
}
else
{
httpContext.Items[ScriptConstants.AzureFunctionsNestedProxyCount] = (int)nestedProxiesCount + 1;
}

await functionInvocationMiddleware.Invoke(httpContext, _scriptHostManager);

var result = (IActionResult)httpContext.Items[ScriptConstants.AzureFunctionsProxyResult];

httpContext.Items.Remove(ScriptConstants.AzureFunctionsProxyResult);

return result;
}

private bool CheckForInfiniteLoop(HttpRequest request)
{
var httpContext = request.HttpContext;

// Local Function calls do not go thru ARR, so implementing the ARR's MAX-FORWARDs header logic here to avoid infinte redirects.
object values;
int redirectCount = 0;
if (httpContext.Items.TryGetValue(ScriptConstants.AzureProxyFunctionLocalRedirectKey, out values))
{
redirectCount = (int)values;

if (redirectCount >= ScriptConstants.AzureProxyFunctionMaxLocalRedirects)
{
return true;
}
}
else
{
httpContext.Items.Add(ScriptConstants.AzureProxyFunctionLocalRedirectKey, redirectCount);
return false;
}

redirectCount++;
httpContext.Items[ScriptConstants.AzureProxyFunctionLocalRedirectKey] = redirectCount;

return false;
}
}
}
35 changes: 0 additions & 35 deletions src/WebJobs.Script.WebHost/ProxyFunctionExecutor.cs

This file was deleted.

Loading