Azure Function disabled setting "user" field to HTTP request object on the 26th of April 2022

294 Views Asked by At

(!) Issue cannot be reproduced locally.
Azure Function Version ~4
Node Version 14.18.1

Creating a simple HTTP triggered Azure Function and setting just two simple properties we get the following code:

module.exports = async function (context, req) {

    req.auth = {authField: 'some value'}
    req.user = {userField: 'some value'}
    context.log(`${JSON.stringify(req,null,2)}`);

    context.res = {
        body: 'responseMessage'
    };
}

The logger prints the following object:

{
  "method": "POST",
  "url": "xxx",
  "originalUrl": "xxx",
  "headers": {
    /// ...
  },
  "query": {},
  "params": {},
  "body": { "name": "Azure" },
  "rawBody": "{\"name\":\"Azure\"}",
  "auth": { "authField": "some value" }
}

As you see only auth is set and not user. The same failing behavior can be seen in version 4.2.0.

When I test with Azure Function ~3 the output looks like this:

{
  "method": "POST",
  "url": "xxx",
  "originalUrl": "xxx",
  "headers": {
    // ...
  },
  "query": {},
  "params": {},
  "body": { "name": "Azure" },
  "rawBody": "{\"name\":\"Azure\"}",
  "auth": { "authField": "some value" },
  "user": { "userField": "some value" }
}

As you see the field is set. The following custom v4 4.1.0-17156 also sets the user field.

The field user was used by us through the express-jwt (v6.1.0) which is using it when no value is provided for requestProperty.

I could not yet reproduce it but in out transpiled from Typescript project, we get the following runtime error:

FailureException: Cannot set property user of [object Object] which has only a getterStack: TypeError: Cannot set property user of [object Object] which has only a getterat Object.run

The issue started at the beginning of the day of 26th of April 2022.

Questions:

  • what is the reason?
  • is a quick roll back to the functioning Azure Function custom version possible?
1

There are 1 best solutions below

5
On BEST ANSWER

I found the culprit in this PR, which was added for Azure Function runtime v4.2.0.

The user field was added with only a getter.
We took the code and made the minimal example:

class Request {
    #cachedUser?: string | null;
    constructor() {
    }
    get user(): string | null {
        if (this.#cachedUser === undefined) {
            this.#cachedUser = "some value";
        }
        return this.#cachedUser;
    }
}

and got the following transpilied version:

var __classPrivateFieldGet =
    (this && this.__classPrivateFieldGet) ||
    function (receiver, state, kind, f) {
        if (kind === 'a' && !f) throw new TypeError('Private accessor was defined without a getter')
        if (typeof state === 'function' ? receiver !== state || !f : !state.has(receiver))
            throw new TypeError('Cannot read private member from an object whose class did not declare it')
        return kind === 'm' ? f : kind === 'a' ? f.call(receiver) : f ? f.value : state.get(receiver)
    }
var __classPrivateFieldSet =
    (this && this.__classPrivateFieldSet) ||
    function (receiver, state, value, kind, f) {
        if (kind === 'm') throw new TypeError('Private method is not writable')
        if (kind === 'a' && !f) throw new TypeError('Private accessor was defined without a setter')
        if (typeof state === 'function' ? receiver !== state || !f : !state.has(receiver))
            throw new TypeError('Cannot write private member to an object whose class did not declare it')
        return kind === 'a' ? f.call(receiver, value) : f ? (f.value = value) : state.set(receiver, value), value
    }
var _Request_cachedUser
class Request {
    constructor() {
        _Request_cachedUser.set(this, void 0)
    }
    get user() {
        if (__classPrivateFieldGet(this, _Request_cachedUser, 'f') === undefined) {
            __classPrivateFieldSet(this, _Request_cachedUser, 'some value', 'f')
        }
        return __classPrivateFieldGet(this, _Request_cachedUser, 'f')
    }
}
_Request_cachedUser = new WeakMap()

// this section is added for testing
const request = new Request()
request.user = 'new value'
console.log(JSON.stringify(request.user))

So, it always returns the the initial value, which in our example is "some value" but in the original code is simply undefined and does not allow to set it.