From 07ebc6bb554540e7c7f1e4141e19e20e036df8d1 Mon Sep 17 00:00:00 2001 From: Marie Hoeger Date: Wed, 16 Sep 2020 01:02:57 +0000 Subject: [PATCH] Add nullable header / query / params for HTTP (#326) * Add nullable * make sure backwards compatible * Updated subtree from https://github.com/azure/azure-functions-language-worker-protobuf. Tag: v1.3.9-protofile. Commit: eb8abdbe777a37d0a3f2ec4b32b5cde06ef72224 --- .../README.md | 4 ++-- .../src/proto/FunctionRpc.proto | 6 +++++ src/WorkerChannel.ts | 3 ++- src/converters/RpcHttpConverters.ts | 23 +++++++++++++++---- test/WorkerChannelTests.ts | 3 ++- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/azure-functions-language-worker-protobuf/README.md b/azure-functions-language-worker-protobuf/README.md index b22f0bb4..a307acfc 100644 --- a/azure-functions-language-worker-protobuf/README.md +++ b/azure-functions-language-worker-protobuf/README.md @@ -1,4 +1,4 @@ -# Azure Functions Languge Worker Protobuf +# Azure Functions Language Worker Protobuf This repository contains the protobuf definition file which defines the gRPC service which is used between the [Azure Functions Host](https://github.com/Azure/azure-functions-host) and the Azure Functions language workers. This repo is shared across many repos in many languages (for each worker) by using git commands. @@ -39,7 +39,7 @@ From within the Azure Functions language worker repo: ## Releasing a Language Worker Protobuf version 1. Draft a release in the GitHub UI - - Be sure to inculde details of the release + - Be sure to include details of the release 2. Create a release version, following semantic versioning guidelines ([semver.org](https://semver.org/)) 3. Tag the version with the pattern: `v..

-protofile` (example: `v1.1.0-protofile`) 3. Merge `dev` to `master` diff --git a/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto b/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto index 3ed1f058..dad7cfd2 100644 --- a/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto +++ b/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto @@ -96,6 +96,9 @@ message WorkerInitRequest { // inform worker of supported categories and their levels // i.e. Worker = Verbose, Function.MyFunc = None map log_categories = 3; + + // Full path of worker.config.json location + string worker_directory = 4; } // Worker responds with the result of initializing itself @@ -481,4 +484,7 @@ message RpcHttp { TypedData rawBody = 17; repeated RpcClaimsIdentity identities = 18; repeated RpcHttpCookie cookies = 19; + map nullable_headers = 20; + map nullable_params = 21; + map nullable_query = 22; } diff --git a/src/WorkerChannel.ts b/src/WorkerChannel.ts index c5319817..8cde2e34 100644 --- a/src/WorkerChannel.ts +++ b/src/WorkerChannel.ts @@ -116,7 +116,8 @@ export class WorkerChannel implements IWorkerChannel { let workerCapabilities = { RpcHttpTriggerMetadataRemoved: "true", RpcHttpBodyOnly: "true", - IgnoreEmptyValuedRpcHttpHeaders: "true" + IgnoreEmptyValuedRpcHttpHeaders: "true", + UseNullableValueDictionaryForHttp: "true" }; if (!this._v1WorkerBehavior) { diff --git a/src/converters/RpcHttpConverters.ts b/src/converters/RpcHttpConverters.ts index 0ad9575f..928f7178 100644 --- a/src/converters/RpcHttpConverters.ts +++ b/src/converters/RpcHttpConverters.ts @@ -1,4 +1,7 @@ -import { AzureFunctionsRpcMessages as rpc } from '../../azure-functions-language-worker-protobuf/src/rpc'; +import { + AzureFunctionsRpcMessages as rpc, + INullableString +} from '../../azure-functions-language-worker-protobuf/src/rpc'; import { HttpMethod, Cookie } from '../public/Interfaces'; import { RequestProperties } from '../http/Request'; import { Dict } from '../Context'; @@ -21,9 +24,9 @@ export function fromRpcHttp(rpcHttp: rpc.IRpcHttp): RequestProperties { method: rpcHttp.method, url: rpcHttp.url, originalUrl: rpcHttp.url, - headers: >rpcHttp.headers, - query: >rpcHttp.query, - params: >rpcHttp.params, + headers: fromNullableMapping(rpcHttp.nullableHeaders, rpcHttp.headers), + query: fromNullableMapping(rpcHttp.nullableQuery, rpcHttp.query), + params: fromNullableMapping(rpcHttp.nullableParams, rpcHttp.params), body: fromTypedData(rpcHttp.body), rawBody: fromRpcHttpBody(rpcHttp.body), }; @@ -46,6 +49,18 @@ function fromRpcHttpBody(body: rpc.ITypedData) { } } +function fromNullableMapping(nullableMapping: { [k: string]: INullableString } | null | undefined, originalMapping?: { [k: string]: string } | null): Dict { + let converted = {}; + if (nullableMapping && Object.keys(nullableMapping).length > 0) { + for (const key in nullableMapping) { + converted[key] = nullableMapping[key].value || ""; + } + } else if (originalMapping && Object.keys(originalMapping).length > 0) { + converted = >originalMapping; + } + return converted; +} + /** * Converts the HTTP 'Response' object to an 'ITypedData' 'http' type to be sent through the RPC layer. * 'http' types are a special case from other 'ITypedData' types, which come from primitive types. diff --git a/test/WorkerChannelTests.ts b/test/WorkerChannelTests.ts index f2bd570f..077ece5a 100644 --- a/test/WorkerChannelTests.ts +++ b/test/WorkerChannelTests.ts @@ -106,7 +106,8 @@ describe('WorkerChannel', () => { capabilities: { 'RpcHttpBodyOnly': 'true', 'RpcHttpTriggerMetadataRemoved': 'true', - 'IgnoreEmptyValuedRpcHttpHeaders': 'true' + 'IgnoreEmptyValuedRpcHttpHeaders': 'true', + 'UseNullableValueDictionaryForHttp': "true" }, result: { status: rpc.StatusResult.Status.Success