Skip to content
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

missing isBrowser function in util package triggers an exception #84

Closed
modean opened this issue Apr 8, 2021 · 18 comments
Closed

missing isBrowser function in util package triggers an exception #84

modean opened this issue Apr 8, 2021 · 18 comments

Comments

@modean
Copy link

modean commented Apr 8, 2021

Since "ibm-cos-sdk": "1.10.0", the isBrowser function seems to be missing in master/lib/util.js. Thus the following exception will be thrown if using the SDK.

image

@IBMeric
Copy link
Member

IBMeric commented Apr 12, 2021

Thank you for your report. Could you provide more details about your code and environment? I can use 1.10.0 and a simple script to create, list, get, put, and delete objects and buckets without seeing this exception.

@modean
Copy link
Author

modean commented Apr 12, 2021

@IBMeric basically we instantiate the SDK like this:

import IBMS3 from "ibm-cos-sdk/clients/s3"

new IBMS3({
			endpoint: endpoint,
			serviceInstanceId: storageInstanceId,
			sslEnabled: true,
			s3ForcePathStyle: true,
			// @ts-ignore
			tokenManager: {
				getToken: function () {
					return { accessToken: token };
				}
			}
		});

On the instance we then call upload with the following upload options:

uploadOptions = {
  Bucket: auth.bucket,
  Key: key,
  Body: body,
  progressEventListener: /* some function */
};

IBMS3.upload(uploadOptions, function (err, dataObj) {}

Our environment is a React microservice that runs on a Node 14.16.0 runtime. The code from above is part of the client-side code of the UI microservice.

Not sure whether this helps answering your question. I am also available on IBM Slack, feel free to reach out.

@daka1510
Copy link
Member

daka1510 commented May 6, 2021

@IBMeric - any updates? I've hit the same issue while upgrading from "ibm-cos-sdk": "1.9.0" -> "ibm-cos-sdk": "1.10.0"

Some changes in this diff must cause the problem

Our code fails in this line (running in a browser environment) because AWS.util.isBrowser is not a function

var prefix = AWS.util.isBrowser() ? 'X-Amz-' : '';

The stack trace that lead to the invocation of this line is below

# the exact line numbers I have access to wouldn't help because they refer to bundled code on our side
 at HttpRequest.getUserAgentHeaderName
 at HttpRequest.setUserAgent
 at new HttpRequest
 at new Request 
 at features.constructor.makeRequest
 at features.constructor.svc.<computed> [as putObject]
 at ManagedUpload.nextChunk
 at ManagedUpload.fillBuffer
 at ManagedUpload.send

Below lines were removed in the referenced diff and at least look suspicious:

isBrowser: function isBrowser() { return process && process.browser; },
isNode: function isNode() { return !util.isBrowser(); },

Is there anything else you need to drive this forward?

@IBMeric
Copy link
Member

IBMeric commented May 6, 2021

This seems to be an interaction issue with the way the SDK is being used. When using require('ibm-cos-sdk'), everything works as expected. When only importing from a directory in the SDK, the above exception can happen. The workaround is to add those two lines above back in. This issue has been reproduced and is being tracked internally.

For reference: https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-node#node-examples-init

@IBMeric
Copy link
Member

IBMeric commented May 6, 2021

I created a new project from scratch for test purposes and am unable to reproduce the exception (the previous reproduction turned out to be an unrelated problem). Could you provide additional details on differences between this sample code and your project? Since I cannot reproduce the problem in pure Javascript, are you using a dialect? Which one?

npm install ibm-cos-sdk

main.js

import S3 from 'ibm-cos-sdk/clients/s3.js'
import myCreds from './creds.js'

const s3Config = {
		endpoint: 'https://' + myCreds.api_endpoint + ':8443',
		apiKeyId: myCreds.ibm_api_key,
		serviceInstanceId: myCreds.ibm_service_instance_id,
		ibmAuthEndpoint: myCreds.ibm_auth_endpoint,
		signatureVersion: 'iam',
		// accessKeyId: myCreds.aws_access_key_id,
		// secretAccessKey: myCreds.aws_secret_access_key,
		// signatureVersion: 'v4',
		s3ForcePathStyle: true,
};

var s3Client = new S3(s3Config);

async function main() {
  var bucketName = `cos-${Date.now()}`;
  console.log('createBucket');
  var createBucketParams = {Bucket: bucketName, CreateBucketConfiguration: {LocationConstraint: ''}};
  var response = await s3Client.createBucket(createBucketParams).promise();
  console.log('deleteBucket');
  response = await s3Client.deleteBucket({Bucket: bucketName}).promise();
  console.log('Complete!');
}

main();

package.json

{
  "type": "module"
}

@daka1510
Copy link
Member

daka1510 commented May 7, 2021

@IBMeric the most obvious difference from your test code and the snippet shared by @modean is that you tested with s3Client.createBucket, s3Client.deleteBucket but the problem surfaces when s3Client.upload is used.

I can try to work on a small reproducer next week but first I'd like to understand if you were able to run an upload and could verify that the code successfully passed this line

var prefix = AWS.util.isBrowser() ? 'X-Amz-' : '';

If so, can you add a breakpoint in there and share what properties are set on AWS.util?

@IBMeric
Copy link
Member

IBMeric commented May 7, 2021

@daka1510 Perhaps see #83. There is no difference when I use s3Client.upload.

import stream from 'stream';
import fs from 'fs';

...

  console.log('upload');
  var key = 'foo';
  var body = 'bar';
  var filename = 'mydata.txt';
  var readStream = fs.createReadStream(filename);
  console.log(readStream);
  var params = {Bucket: bucketName, Key: key, Body: readStream};
  var options = {partSize: 10 * 2**20, queueSize: 10};
  response = await s3Client.upload(params, options).promise();
  console.log('delete');
  response = await s3Client.deleteObject({Bucket: bucketName, Key: key}).promise();

@IBMeric
Copy link
Member

IBMeric commented May 7, 2021

I added a breakpoint at the line you requested. I truncated multiline output (it's over 200 lines), but you will see the two functions of interest are there.

> console.log(AWS.util)
undefined
< {
<   environment: 'nodejs',
<   engine: [Function: engine],
<   userAgent: [Function: userAgent],
<   uriEscape: [Function: uriEscape],
<   uriEscapePath: [Function: uriEscapePath],
<   urlParse: [Function: urlParse],
<   urlFormat: [Function: urlFormat],
<   queryStringParse: [Function: queryStringParse],
<   queryParamsToString: [Function: queryParamsToString],
<   readFileSync: [Function: readFileSync],
<   base64: { encode: [Function: encode64], decode: [Function: decode64] },
<   buffer: { <truncated> },
<   string: { <truncated> },
<   ini: { parse: [Function: string] },
<   fn: { <truncated> },
<   date: { <truncated> },
<   crypto: { <truncated> },
<   abort: {},
<   each: [Function: each],
<   arrayEach: [Function: arrayEach],
<   update: [Function: update],
<   merge: [Function: merge],
<   copy: [Function: copy],
<   isEmpty: [Function: isEmpty],
<   arraySliceFn: [Function: arraySliceFn],
<   isType: [Function: isType],
<   typeName: [Function: typeName],
<   error: [Function: error],
<   inherit: [Function: inherit],
<   mixin: [Function: mixin],
<   hideProperties: [Function: hideProperties],
<   property: [Function: property],
<   memoizedProperty: [Function: memoizedProperty],
<   hoistPayloadMember: [Function: hoistPayloadMember],
<   computeSha256: [Function: computeSha256],
<   computeContentMD5: [Function: computeContentMD5],
<   isClockSkewed: [Function: isClockSkewed],
<   applyClockOffset: [Function: applyClockOffset],
<   extractRequestId: [Function: extractRequestId],
<   addPromises: [Function: addPromises],
<   promisifyMethod: [Function: promisifyMethod],
<   isDualstackAvailable: [Function: isDualstackAvailable],
<   calculateRetryDelay: [Function: calculateRetryDelay],
<   handleRequestWithRetries: [Function: handleRequestWithRetries],
<   uuid: { v4: [Function: uuidV4] },
<   convertPayloadToString: [Function: convertPayloadToString],
<   defer: [Function: defer],
<   getRequestPayloadShape: [Function: getRequestPayloadShape],
<   getProfilesFromSharedConfig: [Function: getProfilesFromSharedConfig],
<   defaultProfile: 'default',
<   configOptInEnv: 'AWS_SDK_LOAD_CONFIG',
<   sharedCredentialsFileEnv: 'AWS_SHARED_CREDENTIALS_FILE',
<   sharedConfigFileEnv: 'AWS_CONFIG_FILE',
<   imdsDisabledEnv: 'AWS_EC2_METADATA_DISABLED',
**<   isBrowser: [Function (anonymous)],**
**<   isNode: [Function (anonymous)],**
<   Buffer: [Function: Buffer] { <truncated> },
<   domain: { <truncated> },
<   stream: <ref *1> [Function: Stream] { <truncated> },
<   url: { <truncated> },
<   querystring: { <truncated> },
<   iniLoader: IniLoader { resolvedProfiles: {} }
< }

@daka1510
Copy link
Member

@IBMeric - I created a small repository with code that allows to reproduce the problem in isolation. See https://github.com/daka1510/ibm-cos-sdk-issue-reproducer#reproducer-for-httpsgithubcomibmibm-cos-sdk-jsissues84 for details.
image

Most of the code is generated by https://reactjs.org/docs/create-a-new-react-app.html#create-react-app. The second commit adds what is needed to reproduce the problem.

Can you give it a try?

@IBMeric
Copy link
Member

IBMeric commented May 12, 2021

Thank you for the project. I have been able to reproduce the issue in Firefox 88. The problem appears to be an interaction with React that could also apply to other frameworks. I need to discuss this internally and have opened a tracking ticket.

@modean
Copy link
Author

modean commented May 28, 2021

@rrodriguez06 isn't this exactly the line that was removed and thus did cause the breakage?

@rrodriguez06
Copy link

@IBMeric @modean

For those who are still experiencing this issue, here is an hotfix of the problem.

const AWS = require('ibm-cos-sdk')
AWS.util.isBrowser = function isBrowser() { return process && process.browser; };
AWS.util.isNode = function isNode() { return !AWS.util.isBrowser(); };

it's a bit tricky !

@IBMeric
Copy link
Member

IBMeric commented Jun 21, 2021

Sorry for a delayed response. I've tested a resolution against @daka1510's project. I no longer see output in the browser console. The plan is to publish this fix in the next point release. Currently there are some other fixes we are working on. If those appear to require too much time, we'll do a separate update for this fix.

@daka1510
Copy link
Member

@IBMeric - can you share a rough release timeline for this fix?

@IBMeric
Copy link
Member

IBMeric commented Jul 7, 2021

The release will either be this week or early next week.

@IBMeric
Copy link
Member

IBMeric commented Jul 13, 2021

@modean We have published 1.10.1, and I have verified that @daka1510's example project prints no errors to the console. Could you verify your issue is resolved and then close this ticket?

@IBMeric
Copy link
Member

IBMeric commented Jul 21, 2021

Closing this issue as resolved.

@IBMeric IBMeric closed this as completed Jul 21, 2021
@modean
Copy link
Author

modean commented Jul 21, 2021

@IBMeric I verified the published version 1.10.1 locally and it seems to be working.

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

No branches or pull requests

4 participants