public async Task <HttpResponseMessage> HandleRequestAsync(FunctionDescriptor function, HttpRequestMessage request, Func <HttpRequestMessage, Task <HttpResponseMessage> > invokeFunction) { // First check if there is a registered WebHook Receiver for this request, and if // so use it HttpBindingMetadata httpFunctionMetadata = (HttpBindingMetadata)function.Metadata.InputBindings.FirstOrDefault(p => p.Type == BindingType.HttpTrigger); string webHookReceiver = httpFunctionMetadata.WebHookType; IWebHookReceiver receiver = null; if (string.IsNullOrEmpty(webHookReceiver) || !_receiverLookup.TryGetValue(webHookReceiver, out receiver)) { // If the function is a not a correctly configured WebHook return 500 return(new HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError)); } HttpRequestContext context = new HttpRequestContext { Configuration = _httpConfiguration }; request.SetConfiguration(_httpConfiguration); // add the anonymous handler function from above to the request properties // so our custom WebHookHandler can invoke it at the right time request.Properties.Add(AzureFunctionsCallbackKey, invokeFunction); // TODO: Is there a better way? Requests content can't be read multiple // times, so this forces it to buffer await request.Content.ReadAsStringAsync(); string receiverId = function.Name.ToLowerInvariant(); return(await receiver.ReceiveAsync(receiverId, context, request)); }
public void GenerateHttpTriggerFunction() { HttpBindingMetadata trigger = new HttpBindingMetadata { Type = BindingType.HttpTrigger }; MethodInfo method = GenerateMethod(trigger); VerifyCommonProperties(method); // verify trigger parameter ParameterInfo parameter = method.GetParameters()[0]; Assert.Equal("req", parameter.Name); Assert.Equal(typeof(HttpRequestMessage), parameter.ParameterType); NoAutomaticTriggerAttribute attribute = method.GetCustomAttribute <NoAutomaticTriggerAttribute>(); Assert.NotNull(attribute); }
public override async Task <HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) { HttpRequestMessage request = controllerContext.Request; // First see if the request maps to an HTTP function FunctionDescriptor function = _scriptHostManager.GetHttpFunctionOrNull(request.RequestUri); if (function == null) { return(new HttpResponseMessage(HttpStatusCode.NotFound)); } // Authorize the request SecretManager secretManager = (SecretManager)controllerContext.Configuration.DependencyResolver.GetService(typeof(SecretManager)); HttpBindingMetadata httpFunctionMetadata = (HttpBindingMetadata)function.Metadata.InputBindings.FirstOrDefault(p => p.Type == BindingType.HttpTrigger); bool isWebHook = !string.IsNullOrEmpty(httpFunctionMetadata.WebHookType); if (!isWebHook && !AuthorizationLevelAttribute.IsAuthorized(request, httpFunctionMetadata.AuthLevel, secretManager, functionName: function.Name)) { return(new HttpResponseMessage(HttpStatusCode.Unauthorized)); } HttpResponseMessage response = null; if (isWebHook) { // This is a WebHook request so define a delegate for the user function. // The WebHook Receiver pipeline will first validate the request fully // then invoke this callback. Func <HttpRequestMessage, Task <HttpResponseMessage> > invokeFunction = async(req) => { return(await _scriptHostManager.HandleRequestAsync(function, req, cancellationToken)); }; response = await _webHookReceiverManager.HandleRequestAsync(function, request, invokeFunction); } else { // Not a WebHook request so dispatch directly response = await _scriptHostManager.HandleRequestAsync(function, request, cancellationToken); } return(response); }
protected override void OnHostStarted() { base.OnHostStarted(); // whenever the host is created (or recreated) we build a cache map of // all http function routes HttpFunctions = new Dictionary <string, FunctionDescriptor>(); foreach (var function in Instance.Functions) { HttpBindingMetadata httpTriggerBinding = (HttpBindingMetadata)function.Metadata.InputBindings.SingleOrDefault(p => p.Type == BindingType.HttpTrigger); if (httpTriggerBinding != null) { string route = httpTriggerBinding.Route; if (!string.IsNullOrEmpty(route)) { route += "/"; } route += function.Name; HttpFunctions.Add(route.ToLowerInvariant(), function); } } }
internal static Collection <FunctionBinding> GetBindings(ScriptHostConfiguration config, IEnumerable <BindingMetadata> bindingMetadatas, FileAccess fileAccess) { Collection <FunctionBinding> bindings = new Collection <FunctionBinding>(); if (bindings != null) { foreach (var bindingMetadata in bindingMetadatas) { BindingType type = bindingMetadata.Type; string name = bindingMetadata.Name; switch (type) { case BindingType.Blob: case BindingType.BlobTrigger: BlobBindingMetadata blobBindingMetadata = (BlobBindingMetadata)bindingMetadata; bindings.Add(new BlobBinding(config, name, blobBindingMetadata.Path, fileAccess, bindingMetadata.IsTrigger)); break; case BindingType.Queue: case BindingType.QueueTrigger: QueueBindingMetadata queueBindingMetadata = (QueueBindingMetadata)bindingMetadata; if (!queueBindingMetadata.IsTrigger && fileAccess != FileAccess.Write) { throw new InvalidOperationException("Queue binding can only be used for output."); } bindings.Add(new QueueBinding(config, name, queueBindingMetadata.QueueName, fileAccess, bindingMetadata.IsTrigger)); break; case BindingType.ServiceBus: case BindingType.ServiceBusTrigger: ServiceBusBindingMetadata serviceBusBindingMetadata = (ServiceBusBindingMetadata)bindingMetadata; if (!serviceBusBindingMetadata.IsTrigger && fileAccess != FileAccess.Write) { throw new InvalidOperationException("ServiceBus binding can only be used for output."); } string queueOrTopicName = serviceBusBindingMetadata.QueueName ?? serviceBusBindingMetadata.TopicName; bindings.Add(new ServiceBusBinding(config, name, queueOrTopicName, fileAccess, bindingMetadata.IsTrigger)); break; case BindingType.Table: TableBindingMetadata tableBindingMetadata = (TableBindingMetadata)bindingMetadata; TableQuery tableQuery = new TableQuery { TakeCount = tableBindingMetadata.Take, FilterString = tableBindingMetadata.Filter }; bindings.Add(new TableBinding(config, name, tableBindingMetadata.TableName, tableBindingMetadata.PartitionKey, tableBindingMetadata.RowKey, fileAccess, tableQuery)); break; case BindingType.Http: HttpBindingMetadata httpBindingMetadata = (HttpBindingMetadata)bindingMetadata; if (fileAccess != FileAccess.Write) { throw new InvalidOperationException("Http binding can only be used for output."); } name = name ?? "res"; bindings.Add(new HttpBinding(config, name, FileAccess.Write, bindingMetadata.IsTrigger)); break; } } } return(bindings); }