encoding support in options #16

Open
ldd opened this Issue Jul 9, 2013 · 11 comments

Comments

Projects
None yet
4 participants
@ldd

ldd commented Jul 9, 2013

The latest request has an option 'encoding' which allows getting files as buffers or at least, bypassing the conversion to unicode. This option is not present in browser-request not does it warn the user about it.

@caasi

This comment has been minimized.

Show comment Hide comment
@caasi

caasi Oct 1, 2014

🆙 for this issue

caasi commented Oct 1, 2014

🆙 for this issue

@yegodz

This comment has been minimized.

Show comment Hide comment
@yegodz

yegodz Mar 5, 2015

Hi...
I ran into this problem as well. If you are looking to receive binary data as an ArrayBuffer or Buffer, you can set the xhr.responseType property to arraybuffer before sending the request. On return the xhr.response will contain the response as a ArrayBuffer object.
You can convert the ArrayBuffer to a Buffer thus

var buff = new Buffer( new Uint8Array(xhr.response));

Keep in mind that browserify creates the Buffer type for use in the browser. So if you are not using browserify, user the buffer library directly from npm

See pull request #29

yegodz commented Mar 5, 2015

Hi...
I ran into this problem as well. If you are looking to receive binary data as an ArrayBuffer or Buffer, you can set the xhr.responseType property to arraybuffer before sending the request. On return the xhr.response will contain the response as a ArrayBuffer object.
You can convert the ArrayBuffer to a Buffer thus

var buff = new Buffer( new Uint8Array(xhr.response));

Keep in mind that browserify creates the Buffer type for use in the browser. So if you are not using browserify, user the buffer library directly from npm

See pull request #29

@novellizator

This comment has been minimized.

Show comment Hide comment
@novellizator

novellizator Jul 31, 2015

how do you set the responseType in this browser-request module? there do you put this?

how do you set the responseType in this browser-request module? there do you put this?

@yegodz

This comment has been minimized.

Show comment Hide comment
@yegodz

yegodz Jul 31, 2015

Hi .. it seems a lot of pull requests haven't been added in here.
I have extensively modified browser-request to add in a bunch of features such as binary buffers, callbacks, binary file uploads in multiple formats etc.
You can download it from https://github.com/yegodz/browser-request
I haven't updated the documentation from the original fork, but this code is working in a fairly complex web application.

yegodz commented Jul 31, 2015

Hi .. it seems a lot of pull requests haven't been added in here.
I have extensively modified browser-request to add in a bunch of features such as binary buffers, callbacks, binary file uploads in multiple formats etc.
You can download it from https://github.com/yegodz/browser-request
I haven't updated the documentation from the original fork, but this code is working in a fairly complex web application.

@novellizator

This comment has been minimized.

Show comment Hide comment
@novellizator

novellizator Jul 31, 2015

@yegodz ok, a few questions then: 1. does "npm install browser-request" install your version? or should I download it manually?
2. is there any other besides reading the sources to find out how to send/receive binary data?
(at least some test/example/...)

@yegodz ok, a few questions then: 1. does "npm install browser-request" install your version? or should I download it manually?
2. is there any other besides reading the sources to find out how to send/receive binary data?
(at least some test/example/...)

@yegodz

This comment has been minimized.

Show comment Hide comment
@yegodz

yegodz Jul 31, 2015

I haven’t uploaded to npm yet (meaning to do so sometime :-)

For now, just download and use it from Github.

I will be updating the documentation on github shortly, but meanwhile, you can do two things:

  1. See some code snippets below
  2. See the changes I have put in by looking at the last commit on my repo. That will tell you exactly what has changed.

Some extra options are available to be added to the ‘options’ object that is passed to request
e.g.
progressCallback points to a function that is called everytime some block of data is loaded by the system. This helps you to display a progress bar etc for file upload/downloads
responseType: ‘buffer’ indicates that the expected data returned in the ‘body’ argument of the callback should be in a binary buffer

      var options = {
          url: res.downloadUrl,
          headers: {
              //'User-Agent': 'xo',
              Authorization: 'Bearer ' + thisObj.tokens.access_token
          },
          progressCallback: function (progressEvt){
            thisObj.downloads[fileid].total = progressEvt.total;
            thisObj.downloads[fileid].loaded = progressEvt.loaded;
            if (progressEvt.loaded >= chunkDoc.size)
              console.log('Completed Google download')
          },
          encoding: null,
          responseType: 'buffer' // required in the browser version of request
      };

      request.get(options,
          function (err, response, body) {
              if (err) {
                  ...
              }
        …

Support for Multipart/related uploads

    var fileMeta = {
      'Content-Type': 'application/json',
      body: JSON.stringify({
        modifiedDate: chunkDoc.mtime
      })
    }
    var fileData = {
      'Content-Type': 'application/octet-stream',
      body: chunkBuff
    }
    var options = {
        url: 'https://www.googleapis.com/upload/drive/v2/files/'
        headers: {
            'Authorization': 'Bearer ' + thisObj.tokens.access_token
        },
        qs: {uploadType: 'multipart'},
        progressCallback: function (progressEvt){
          thisObj.uploads[filename].total = progressEvt.total;
          thisObj.uploads[filename].loaded = progressEvt.loaded;
          if (progressEvt.loaded >= chunkDoc.size)
            console.log('Completed Google upload')
        },
        multipart: [fileMeta, fileData]
    }

Support for multipart/formData file upload

    var formData = {
        attributes: JSON.stringify({
            name: chunkDoc.uri,
            parent: {
                id: thisObj.rootFolderId
            }
        }),
        file: {
            value: chunkBuff,
            options: {
                filename: 'file',
                contentType: 'application/octet-stream'
            }
        }
    }
    var options = {
        url: 'https://upload.box.com/api/2.0/files/content',
        headers: {
            //'User-Agent': 'xo',
            Authorization: 'Bearer ' + thisObj.tokens.access_token
        },
        formData: formData,
        progressCallback: function (progressEvt){
          thisObj.uploads[fileDoc_id].total = progressEvt.total;
          thisObj.uploads[fileDoc_id].loaded = progressEvt.loaded;
          if (progressEvt.loaded >= chunkDoc.size)
            console.log('Completed Box upload')
        }
    }

Ruchir Godura
ruchir@cerient.com
Founder, Cerient Technology, LLC.

Keep your cloud data private at http://www.xooui.com http://www.xooui.com/

On Jul 31, 2015, at 10:47 AM, Tomas Novella notifications@github.com wrote:

@yegodz https://github.com/yegodz ok, a few questions then: 1. does "npm install browser-request" install your version? or should I download it manually?
2. is there any other besides reading the sources to find out how to send/receive binary data?
(at least some test/example/...)


Reply to this email directly or view it on GitHub #16 (comment).

yegodz commented Jul 31, 2015

I haven’t uploaded to npm yet (meaning to do so sometime :-)

For now, just download and use it from Github.

I will be updating the documentation on github shortly, but meanwhile, you can do two things:

  1. See some code snippets below
  2. See the changes I have put in by looking at the last commit on my repo. That will tell you exactly what has changed.

Some extra options are available to be added to the ‘options’ object that is passed to request
e.g.
progressCallback points to a function that is called everytime some block of data is loaded by the system. This helps you to display a progress bar etc for file upload/downloads
responseType: ‘buffer’ indicates that the expected data returned in the ‘body’ argument of the callback should be in a binary buffer

      var options = {
          url: res.downloadUrl,
          headers: {
              //'User-Agent': 'xo',
              Authorization: 'Bearer ' + thisObj.tokens.access_token
          },
          progressCallback: function (progressEvt){
            thisObj.downloads[fileid].total = progressEvt.total;
            thisObj.downloads[fileid].loaded = progressEvt.loaded;
            if (progressEvt.loaded >= chunkDoc.size)
              console.log('Completed Google download')
          },
          encoding: null,
          responseType: 'buffer' // required in the browser version of request
      };

      request.get(options,
          function (err, response, body) {
              if (err) {
                  ...
              }
        …

Support for Multipart/related uploads

    var fileMeta = {
      'Content-Type': 'application/json',
      body: JSON.stringify({
        modifiedDate: chunkDoc.mtime
      })
    }
    var fileData = {
      'Content-Type': 'application/octet-stream',
      body: chunkBuff
    }
    var options = {
        url: 'https://www.googleapis.com/upload/drive/v2/files/'
        headers: {
            'Authorization': 'Bearer ' + thisObj.tokens.access_token
        },
        qs: {uploadType: 'multipart'},
        progressCallback: function (progressEvt){
          thisObj.uploads[filename].total = progressEvt.total;
          thisObj.uploads[filename].loaded = progressEvt.loaded;
          if (progressEvt.loaded >= chunkDoc.size)
            console.log('Completed Google upload')
        },
        multipart: [fileMeta, fileData]
    }

Support for multipart/formData file upload

    var formData = {
        attributes: JSON.stringify({
            name: chunkDoc.uri,
            parent: {
                id: thisObj.rootFolderId
            }
        }),
        file: {
            value: chunkBuff,
            options: {
                filename: 'file',
                contentType: 'application/octet-stream'
            }
        }
    }
    var options = {
        url: 'https://upload.box.com/api/2.0/files/content',
        headers: {
            //'User-Agent': 'xo',
            Authorization: 'Bearer ' + thisObj.tokens.access_token
        },
        formData: formData,
        progressCallback: function (progressEvt){
          thisObj.uploads[fileDoc_id].total = progressEvt.total;
          thisObj.uploads[fileDoc_id].loaded = progressEvt.loaded;
          if (progressEvt.loaded >= chunkDoc.size)
            console.log('Completed Box upload')
        }
    }

Ruchir Godura
ruchir@cerient.com
Founder, Cerient Technology, LLC.

Keep your cloud data private at http://www.xooui.com http://www.xooui.com/

On Jul 31, 2015, at 10:47 AM, Tomas Novella notifications@github.com wrote:

@yegodz https://github.com/yegodz ok, a few questions then: 1. does "npm install browser-request" install your version? or should I download it manually?
2. is there any other besides reading the sources to find out how to send/receive binary data?
(at least some test/example/...)


Reply to this email directly or view it on GitHub #16 (comment).

@novellizator

This comment has been minimized.

Show comment Hide comment
@novellizator

novellizator Aug 3, 2015

Hey. Thank you for the examples!
I tried it, but still I'm having the same problem - in node(iojs) environment the script runs like clockwork, whereas in the browser I get "Failed to load resource: the server responded with a status of 400 (OK)".
Has it ever happened to you?

  let syncRequest = new Bufferr(new Uint8Array(BuildSyncRequest(db)));
  let url = /*'http://localhost/chrome-sync/command';//*/'https://clients4.google.com/chrome-sync/command';

  console.log('syncRequest instanceof Uint8Array?', syncRequest instanceof Uint8Array,
    'len:', syncRequest.length, 'TYPE:', syncRequest.toString());

  request.post({
    url: url,
    //qs: {
    //  'client': 'Google Chrome',
    //  'client_id': config.clientId
    //},
    headers: {
      // todo just test, send the same headers from node as from browser...
      'Accept': '*/*',
      'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.15 Safari/537.36',
      'Accept-Encoding': 'gzip, deflate',
      'Accept-Language': 'en-US,en;q=0.8,cs;q=0.6,sk;q=0.4,de;q=0.2',

      'Content-Type': 'application/octet-stream',
      'Authorization': 'Bearer '+ accessToken
    },
    encoding: null, //  if you expect binary data
    responseType: 'buffer',
    body: syncRequest
  }, (error, response, body) => {
    console.log('error', error,'body', body);
    if (!error) {
      readSyncRequest(body, cb);
    }
  });

Is this module supposed to handle also SENDING binary data?

Hey. Thank you for the examples!
I tried it, but still I'm having the same problem - in node(iojs) environment the script runs like clockwork, whereas in the browser I get "Failed to load resource: the server responded with a status of 400 (OK)".
Has it ever happened to you?

  let syncRequest = new Bufferr(new Uint8Array(BuildSyncRequest(db)));
  let url = /*'http://localhost/chrome-sync/command';//*/'https://clients4.google.com/chrome-sync/command';

  console.log('syncRequest instanceof Uint8Array?', syncRequest instanceof Uint8Array,
    'len:', syncRequest.length, 'TYPE:', syncRequest.toString());

  request.post({
    url: url,
    //qs: {
    //  'client': 'Google Chrome',
    //  'client_id': config.clientId
    //},
    headers: {
      // todo just test, send the same headers from node as from browser...
      'Accept': '*/*',
      'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.15 Safari/537.36',
      'Accept-Encoding': 'gzip, deflate',
      'Accept-Language': 'en-US,en;q=0.8,cs;q=0.6,sk;q=0.4,de;q=0.2',

      'Content-Type': 'application/octet-stream',
      'Authorization': 'Bearer '+ accessToken
    },
    encoding: null, //  if you expect binary data
    responseType: 'buffer',
    body: syncRequest
  }, (error, response, body) => {
    console.log('error', error,'body', body);
    if (!error) {
      readSyncRequest(body, cb);
    }
  });

Is this module supposed to handle also SENDING binary data?

@yegodz

This comment has been minimized.

Show comment Hide comment
@yegodz

yegodz Aug 3, 2015

Not really … if you use Chrome, you can look at the dev tools and actually capture every HTTP request as it goes out.
There you can check if the outgoing HTTP request has been constructed properly.
It seems like you are creating a database query that you are sending to a remote server that executes it and returns the results in a binary buffer. However, the remote server does not seem to be getting the body of your post properly formatted, hence the 400 response.

  1. Try not adding the ‘User-Agent’ header… you are not allowed to add those when sending http req from a browser, and in general should be ignored, but it may causing some error.
  2. Try not adding the new Buffer( ) around the new UIn8Array in the browser
  3. Are you sure the syncRequest that you are building is expected by the servers as a binary file? Try just setting the ‘body’ in the post request to the string returned by the BuildSyncRequest

Ruchir Godura
ruchir@cerient.com
Founder, Cerient Technology, LLC.

Keep your cloud data private at http://www.xooui.com http://www.xooui.com/

On Aug 3, 2015, at 5:34 AM, Tomas Novella notifications@github.com wrote:

Hey. Thank you for the examples!
I tried it, but still I'm having the same problem - in node(iojs) environment the script runs like clockwork, whereas in the browser I get "Failed to load resource: the server responded with a status of 400 (OK)".
Has it ever happened to you?

let syncRequest = new Bufferr(new Uint8Array(BuildSyncRequest(db)));
let url = /_'http://localhost/chrome-sync/command';//_/'https://clients4.google.com/chrome-sync/command';

console.log('syncRequest instanceof Uint8Array?', syncRequest instanceof Uint8Array,
'len:', syncRequest.length, 'TYPE:', syncRequest.toString());

request.post({
url: url,
//qs: {
// 'client': 'Google Chrome',
// 'client_id': config.clientId
//},
headers: {
// todo just test, send the same headers from node as from browser...
'Accept': '/',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.15 Safari/537.36',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'en-US,en;q=0.8,cs;q=0.6,sk;q=0.4,de;q=0.2',

  'Content-Type': 'application/octet-stream',
  'Authorization': 'Bearer '+ accessToken
},
encoding: null, //  if you expect binary data
responseType: 'buffer',
body: syncRequest

}, (error, response, body) => {
console.log('error', error,'body', body);
if (!error) {
readSyncRequest(body, cb);
}
});

Reply to this email directly or view it on GitHub #16 (comment).

yegodz commented Aug 3, 2015

Not really … if you use Chrome, you can look at the dev tools and actually capture every HTTP request as it goes out.
There you can check if the outgoing HTTP request has been constructed properly.
It seems like you are creating a database query that you are sending to a remote server that executes it and returns the results in a binary buffer. However, the remote server does not seem to be getting the body of your post properly formatted, hence the 400 response.

  1. Try not adding the ‘User-Agent’ header… you are not allowed to add those when sending http req from a browser, and in general should be ignored, but it may causing some error.
  2. Try not adding the new Buffer( ) around the new UIn8Array in the browser
  3. Are you sure the syncRequest that you are building is expected by the servers as a binary file? Try just setting the ‘body’ in the post request to the string returned by the BuildSyncRequest

Ruchir Godura
ruchir@cerient.com
Founder, Cerient Technology, LLC.

Keep your cloud data private at http://www.xooui.com http://www.xooui.com/

On Aug 3, 2015, at 5:34 AM, Tomas Novella notifications@github.com wrote:

Hey. Thank you for the examples!
I tried it, but still I'm having the same problem - in node(iojs) environment the script runs like clockwork, whereas in the browser I get "Failed to load resource: the server responded with a status of 400 (OK)".
Has it ever happened to you?

let syncRequest = new Bufferr(new Uint8Array(BuildSyncRequest(db)));
let url = /_'http://localhost/chrome-sync/command';//_/'https://clients4.google.com/chrome-sync/command';

console.log('syncRequest instanceof Uint8Array?', syncRequest instanceof Uint8Array,
'len:', syncRequest.length, 'TYPE:', syncRequest.toString());

request.post({
url: url,
//qs: {
// 'client': 'Google Chrome',
// 'client_id': config.clientId
//},
headers: {
// todo just test, send the same headers from node as from browser...
'Accept': '/',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.15 Safari/537.36',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'en-US,en;q=0.8,cs;q=0.6,sk;q=0.4,de;q=0.2',

  'Content-Type': 'application/octet-stream',
  'Authorization': 'Bearer '+ accessToken
},
encoding: null, //  if you expect binary data
responseType: 'buffer',
body: syncRequest

}, (error, response, body) => {
console.log('error', error,'body', body);
if (!error) {
readSyncRequest(body, cb);
}
});

Reply to this email directly or view it on GitHub #16 (comment).

@novellizator

This comment has been minimized.

Show comment Hide comment
@novellizator

novellizator Aug 3, 2015

Thanks for the advice!. Tried all the things, didnt work. Now I got one hypothesis and this seems to be the case: google sends 400 if I send any cookies in that request(chrome adds automatically cookies relevant for the domain).

Thanks for the advice!. Tried all the things, didnt work. Now I got one hypothesis and this seems to be the case: google sends 400 if I send any cookies in that request(chrome adds automatically cookies relevant for the domain).

@yegodz

This comment has been minimized.

Show comment Hide comment
@yegodz

yegodz Aug 3, 2015

yes.. that is one more difference between the browser and node.js is that the browser will automatically send any relevant cookies whereas node will only send those that you explicitly add to the request.

Ruchir Godura
ruchir@cerient.com
Founder, Cerient Technology, LLC.

Keep your cloud data private at http://www.xooui.com http://www.xooui.com/

On Aug 3, 2015, at 9:55 AM, Tomas Novella notifications@github.com wrote:

Tried all the things, didnt work. Now I got one hypothesis and this seems to be the case: google sends 400 if I send any cookies. And it seems to be sending cookies (that belong to google).


Reply to this email directly or view it on GitHub #16 (comment).

yegodz commented Aug 3, 2015

yes.. that is one more difference between the browser and node.js is that the browser will automatically send any relevant cookies whereas node will only send those that you explicitly add to the request.

Ruchir Godura
ruchir@cerient.com
Founder, Cerient Technology, LLC.

Keep your cloud data private at http://www.xooui.com http://www.xooui.com/

On Aug 3, 2015, at 9:55 AM, Tomas Novella notifications@github.com wrote:

Tried all the things, didnt work. Now I got one hypothesis and this seems to be the case: google sends 400 if I send any cookies. And it seems to be sending cookies (that belong to google).


Reply to this email directly or view it on GitHub #16 (comment).

@novellizator

This comment has been minimized.

Show comment Hide comment
@novellizator

novellizator Aug 5, 2015

Yeah, in the end the problem was with the cookie. Thanks for the examples:)

Yeah, in the end the problem was with the cookie. Thanks for the examples:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment