Skip to content

Buffer type check is broken after upgrade rsocket.js to 0.0.22 #110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
yingjieg opened this issue Dec 21, 2020 · 25 comments · Fixed by #114
Closed

Buffer type check is broken after upgrade rsocket.js to 0.0.22 #110

yingjieg opened this issue Dec 21, 2020 · 25 comments · Fixed by #114
Assignees
Labels

Comments

@yingjieg
Copy link

rsocket.js introduces new LiteBuffer implementation in recent versions, but in file /rsocket-core/src/RSocketEncoding.js, it still use the raw Buffer.isBuffer to check the type, this change break the working code based on 0.0.19.

Steps to Reproduce

Use BufferEncoders as following:

  const transport = new RSocketWebSocketClient(
    {
      url: getSocketURL(),
      wsCreator: (url: string) => new WebSocket(url),
      debug: true,
    },
    BufferEncoders,
  );

then you will get the error message raised by RSocketEncoding.js

RSocketEncoding: Expected value to be a buffer,

Possible Solution

Update the Buffer.isBuffer check to compatible with LiteBuffer.

Environment

  • RSocket version(s) used: 0.0.22
@OlegDokuka OlegDokuka added bug and removed bug labels Dec 21, 2020
@OlegDokuka
Copy link
Member

Hi @yingjieg!

Thank you for rising that!
Unfortunatelly I can not reproduce this issue with my setup (https://github.com/OlegDokuka/rsocket-crosslanguage-example/blob/master/js-client/package.json) can you please provide more details or a sample project which reproduces that?

Cheers,
Oleh

@OlegDokuka
Copy link
Member

Alright. Reproduced locally. Looking into that.

Thanks,
Oleh

@OlegDokuka OlegDokuka added invalid and removed bug labels Dec 21, 2020
@OlegDokuka
Copy link
Member

OlegDokuka commented Dec 21, 2020

After some investigation, it was figured out that it is not related to rsocket but rather related to webpack setup (assume the bundler used is webpack).

The problem is that by default webpack uses polyfills if it finds any node dependencies and bundles them all the way to the browser (for more info see -> https://stackoverflow.com/questions/40467141/webpack2-node-libs-browser-exclude).

Previously, it happened that our Buffer implementation was directly derived from a library used in webpack-lib-browser, hence - no issues appeared before. Nevertheless, in the newer version or rsocket-js, we have rewritten completely that implementation and now it does not intersect with the one bundled by webpack. Therefore, once different Buffer implementations meet at Buffer.isBuffer it results in an obvious false outcome. To fix that, you have to disable webpack-node-libs putting the following property into the config

const webpackConfig = {
  node: false
}

please see the following project for the reference -> https://github.com/OlegDokuka/rsocket-crosslanguage-example

@yingjieg
Copy link
Author

Hi @OlegDokuka

Thank you for investigating this issue. you are right, the root cause is the conflict of polyfill Buffer implementation and LiteBuffer, but I think disable webpack-node-libs is not a good choice, lots of UI projects based on polyfill Buffer implementation. Like our project, it heavily depends on Buffer base64 encode/decode.

After investigation, I think following solutions might work.

Make sure Buffer.isBuffer import the LiteBuffer implementation in RSocketEncoding.js

 import type {Encodable} from 'rsocket-types';

// add this import in rsocket-core/src/RSocketEncoding.js
+import {LiteBuffer as Buffer} from './LiteBuffer'; 

then we can import toBuffer, createBuffer from rsocket-core

  import { toBuffer, createBuffer } from 'rsocket-core';

  return encodeAndAddWellKnownMetadata(
    encodeAndAddCustomMetadata(
      createBuffer(0),
      'message/x.rsocket.authentication.bearer.v0',
      toBuffer(token),
    ),
    MESSAGE_RSOCKET_ROUTING,
    toBuffer(String.fromCharCode(ROUTE.length) + ROUTE),
  );

or we can inject LiteBuffer in webpack:

  new webpack.ProvidePlugin({
    Buffer: ['buffer', 'Buffer'],
    LiteBuffer: ['rsocket-core/build/LiteBuffer.js', 'LiteBuffer'],
  }),
export function getMetadata(token: string) {
  return encodeAndAddWellKnownMetadata(
    encodeAndAddCustomMetadata(
      LiteBuffer.alloc(0),
      'message/x.rsocket.authentication.bearer.v0',
      LiteBuffer.from(token),
    ),
    MESSAGE_RSOCKET_ROUTING,
    LiteBuffer.from(String.fromCharCode(ROUTE.length) + ROUTE),
  );
}

What do you think ?

BR
Yingjie

@OlegDokuka
Copy link
Member

OlegDokuka commented Dec 22, 2020

@yingjieg There are 3 options which we can follow:

  1. We can take the LiteBuffer module off the core to a separate module and one can decide how to go (this is a breaking change)
  2. We can go away from Node buffer and create our own Data representation (another breaking change that does not reduce complexity)
  3. We keep it as it is now and since node-libs-browser is deprecated a user has to decide which polyfills to take into the project.

Definitely, I'm for the 3d option. Noteworthy, the webpack-libs-browser was deprecated for a reason which is - "user has to decide what to do on its own" and not Webpack has to do some magic inclusion.

We will consider the first option to give more flexibility and avoid any limitations from our side, but that will happen not earlier than in 0.1.x or 1.0.0.

@yingjieg
Copy link
Author

@OlegDokuka

Thanks to explain the 3 options. I will remove polyfill part in our project and import specific "Buffer" implementation to solve this issue. The first option is cool, looking forward to see the enhancement in the future.

Thank you!

BR
Yingjie

@OlegDokuka
Copy link
Member

OlegDokuka commented Dec 22, 2020

@yingjieg what you need to do is to exclude Buffer polyfill brought by Webpack. We automatically import our LiteBuffer implementation as a global scope Buffer (via the window scope). You don't need to import anything explicitly

@yingjieg
Copy link
Author

yingjieg commented Dec 22, 2020

@OlegDokuka In our project, we use lots of buffer base64 encode/decode operations, but there is no implementation in LiteBuffer.

const notImplementedEncodings = [
  'base64',
  'hex',
  'ascii',
  'binary',
  'latin1',
  'ucs2',
  'utf16le',
];

@OlegDokuka
Copy link
Member

Sounds reasonable. I will add a separate issue on moving lite-buffer to a separate module

@myklt
Copy link
Contributor

myklt commented Jan 13, 2021

Hi @OlegDokuka ,

I've faced the same issue, but unfortunately do not have control of webpack default polyfills (using create-react-app). Could you please give me a hint, why the proposed solution by @yingjieg to use LiteBuffer.isBuffer in RSocketEncoding.js wouldn't work?

For now, a very quick and dirty solution was to set buffer._isBuffer = true to created composite buffer using RSocket utils.

Regards,
Mykolas.

@OlegDokuka
Copy link
Member

@myklt as I mentioned, Webpack sets its own polyfills which are incompatible with LiteBuffer.

Looks like it is a common issue for the webpack users. I will try to make a workaround. Stay tuned

Cheers,
Oleh

@OlegDokuka OlegDokuka reopened this Jan 18, 2021
@lempikaSolutions
Copy link

I had the same issue that @MyKit and indeed the solution that he proposed works for me !!!
const metadataBuffer = encodeCompositeMetadata([
[TEXT_PLAIN, Buffer.from('Hello World')],
[MESSAGE_RSOCKET_ROUTING, () => encodeRoute(getTokenRoute)],
[MESSAGE_RSOCKET_AUTHENTICATION, () => encodeSimpleAuthMetadata(username, password)]
]);
// eslint-disable-next-line no-underscore-dangle
metadataBuffer._isBuffer = true;

@myklt
Copy link
Contributor

myklt commented Jan 29, 2021

@OlegDokuka , thanks for the fix! Upgraded to 0.0.23 and it works as expected now.

@myklt
Copy link
Contributor

myklt commented Jan 29, 2021

Apparently I got happy too early. It works perfectly while running locally, but something wrong happens, when the production bundle is built: two type of Buffer objects are being created & compared again. I will investigate it further next week, how to avoid the Buffer from Webpack being used.

@myklt
Copy link
Contributor

myklt commented Feb 1, 2021

Update: I was able to solve the issue by using toBuffer from rsocket-core instead of using global Buffer.from in data serializer. I think it would be a good idea to use RSocket compatible buffer implementation explicitly everywhere. I think solving this issue #112 should help to avoid such errors I've faced.

@OlegDokuka
Copy link
Member

@myklt yeah, I dont wanna require anyone to use LiteBuffer. In the meanwhile, if you have an example that reproducers the issues with your setup - don't hesitate to send it to me

@myklt
Copy link
Contributor

myklt commented Feb 7, 2021

@OlegDokuka sorry for the delay. Here is a minimalistic example using create-react-app: https://github.com/myklt/cra-rsocket .

@kkojot
Copy link

kkojot commented Feb 16, 2021

After updating rsocket to 0.0.23 my resumable connection ended up with an endless loop :) Locally everything worked fine (webpack) but after generating static pages (with vue and nuxt) and hosting them on apache I saw {error: Invariant Violation: RSocketEncoding: Expected value to be a buffer, got.... error.
The proposed solution here #110 (comment) helped me to solve the issue (using createBuffer() and toBuffer() instead of Buffer.aloc() and Buffer.from())

@OlegDokuka OlegDokuka reopened this Mar 6, 2021
OlegDokuka added a commit that referenced this issue Mar 6, 2021
Signed-off-by: Oleh Dokuka <[email protected]>
Signed-off-by: Oleh Dokuka <[email protected]>
Signed-off-by: Oleh Dokuka <[email protected]>
@OlegDokuka
Copy link
Member

@myklt, @kkojot @lempikaSolutions @yingjieg I did a temporary fix in 0.0.25 which should eliminate that bad experience you all faced before. I recommend updating on 0.0.25 as soon as possible.

@myklt I did a check with 0.0.25 and the app you mentioned before and everything worked like a charm!

@myklt
Copy link
Contributor

myklt commented Mar 9, 2021

Hi @OlegDokuka! Thanks a lot, I've just tried it out and it works like a charm!

@SerCeMan
Copy link
Member

We've noticed the same issue with 0.0.25, some of the third-party libraries managed to pick up a polyfil and started failing with Error: Not implemented: "base64" encoding.

facebook-github-bot referenced this issue in facebook/flipper Mar 23, 2021
Summary:
Bumps [rsocket-flowable](https://github.com/rsocket/rsocket-js) from 0.0.23 to 0.0.25.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/rsocket/rsocket-js/commit/a85a4db0417717a8734b594e24de9c374eca2851"><code>a85a4db</code></a> v0.0.25</li>
<li><a href="https://github.com/rsocket/rsocket-js/commit/b279d675698163447a31a920ffd7c50c07d647a6"><code>b279d67</code></a> ammend versions</li>
<li><a href="https://github.com/rsocket/rsocket-js/commit/1e15f3c9752f17a06537ee8741900ba12a151a42"><code>1e15f3c</code></a> v0.0.24</li>
<li><a href="https://github.com/rsocket/rsocket-js/commit/a4b7a93dc0dc3decde2fc3310076995f85be28f4"><code>a4b7a93</code></a> provides a temporary fix for <a href="https://github.com/rsocket/rsocket-js/issues/110">https://github.com/facebook/flipper/issues/110</a></li>
<li><a href="https://github.com/rsocket/rsocket-js/commit/c271a3712882d4e5ad5398f5d0f82b050e02a76a"><code>c271a37</code></a> exports missing TlsClient</li>
<li><a href="https://github.com/rsocket/rsocket-js/commit/844b10b35b76d16bf0b12ad1f96e5851fc32f6e5"><code>844b10b</code></a> updates docs</li>
<li><a href="https://github.com/rsocket/rsocket-js/commit/39a86dfa5fe43df074bd2b52450af141ad12f331"><code>39a86df</code></a> updates docs</li>
<li><a href="https://github.com/rsocket/rsocket-js/commit/97e1e9f9220b813b6a173e76fb02580dbb04a72f"><code>97e1e9f</code></a> updates versions</li>
<li><a href="https://github.com/rsocket/rsocket-js/commit/90e70580d14ae2fef3051ce7010cfa9208902f00"><code>90e7058</code></a> fixes RSocketMachine leak on the server-side (<a href="https://github.com/rsocket/rsocket-js/issues/120">https://github.com/facebook/flipper/issues/120</a>)</li>
<li><a href="https://github.com/rsocket/rsocket-js/commit/f665cd1038739aaded25ab46d313cdb7c4f0e147"><code>f665cd1</code></a> adds METADATA_PUSH support (<a href="https://github.com/rsocket/rsocket-js/issues/119">https://github.com/facebook/flipper/issues/119</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/rsocket/rsocket-js/compare/v0.0.23...v0.0.25">compare view</a></li>
</ul>
</details>
<br />

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rsocket-flowable&package-manager=npm_and_yarn&previous-version=0.0.23&new-version=0.0.25)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

 ---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `dependabot rebase` will rebase this PR
- `dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `dependabot merge` will merge this PR after your CI passes on it
- `dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `dependabot cancel merge` will cancel a previously requested merge and block automerging
- `dependabot reopen` will reopen this PR if it is closed
- `dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

</details>

Pull Request resolved: #2069

Reviewed By: passy

Differential Revision: D27230118

Pulled By: priteshrnandgaonkar

fbshipit-source-id: 814a094dabdffae71b26abd8b8ef0d6691ef94ee
@ascpeter
Copy link

I'm getting a buffer warning like this:
RSocketEncoding: Expected value to be a buffer, got '�����route-here'

Strangely enough, this does NOT occur if using webpack's devtool: 'eval'. But it happens with anything else. Consequently, it works in dev but breaks in production. :(

This is with rsocket-core 0.0.25.

@ascpeter
Copy link

The _isBuffer appears to work for me.

@zur4ik
Copy link

zur4ik commented Mar 12, 2022

Getting this error in 0.0.27

Invariant Violation: RSocketEncoding: Expected value to be a buffer, got `)message/x.rsocket.authentication.bearer.v0...

Using CRA and there are no errors in dev mode, only in production builds

@roie16
Copy link

roie16 commented Aug 7, 2022

Hi,
I have experienced this issue with rsocket 0.0.27
as this is a temp demo project I looked for a quick workaround, and I fixed it by just added the following dependency to package.json:
"node-polyfill-webpack-plugin": "^2.0.1"
leaving it here in case someone will need a temp quick workaround

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants