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

Allow users to configure forwarded headers? #916

Closed
jgeewax opened this issue Oct 26, 2015 · 5 comments
Closed

Allow users to configure forwarded headers? #916

jgeewax opened this issue Oct 26, 2015 · 5 comments
Assignees
Labels

Comments

@jgeewax
Copy link
Contributor

jgeewax commented Oct 26, 2015

The Cloud Trace team wants to make it easy for users to send trace IDs along with various API calls, effectively just adding a special header (X-Cloud-Trace-Context) with an opaque ID.

The issue is that this ID will vary across requests, which presents a bit of an issue in that whole concurrency thing...

For example, here's how I'd want to do this in my app: https://gist.github.com/jgeewax/3b351d3522fdf061bdea

Note that I have zero idea if this is at all reasonable given the isolation model for Node. (I think, for example, that this won't work for Express, and that we should be doing something with req.locals....? see http://stackoverflow.com/questions/33310324/using-express-middleware-for-per-request-module-configuration)

Anyway -- we need to find a way to allow users to...

  1. Set custom headers to be forwarded along with each API request to Google
  2. Configure those headers in one place (ie, not as arguments to each method as people don't want to change all their code for this)
  3. Make sure that it's obvious how to do this the right way (ie, avoid giving people a gun and aiming it at their feet -- which setTraceContext in my example might do...)
@stephenplusplus
Copy link
Contributor

👍 I imagine most of the time, users might just want their own custom UA, so we should support: (edit: maybe that doesn't make sense actually? Either way, they could manipulate whatever part of the request they want:)

var gcloud = require('gcloud')({
  decorateRequest: function(reqOpts) {
    reqOpts.headers['User-Agent'] = 'My App';
    return reqOpts;
  }
});

Then overriding per service should be pretty straightforward:

var dataset = gcloud.datastore.dataset({
  decorateRequest: function(reqOpts) {
    reqOpts.headers['X-App-Id'] = 'app-whatever';
    return reqOpts;
  }
});

As far as allowing per-request control, like "got a request for resource X, attach a custom header while we download it then remove it after", maybe we can go even one level deeper:

var bucket = gcloud.storage.bucket('my-app-bucket');
var file = bucket.file('my-app-file', {
  decorateRequest: function(reqOpts) {
    reqOpts.headers['X-Requester-Id'] = 'user-ip';
    return reqOpts;
  }
});

All of these have the decorated request options, while any other service (Dataset) or object (Bucket, File, Topic, etc) wouldn't be touched.

// X-Requester-Id header in place
file.createReadStream();
file.download();

// No X-Requester-Id header in place
bucket.upload();
bucket.getMetadata();

Regarding the gist, I put together how this would look: https://gist.github.com/jgeewax/3b351d3522fdf061bdea

@stephenplusplus
Copy link
Contributor

Another option:

// Global
gcloud.decorateRequest(function(reqOpts) {
  // modify reqOpts
  return reqOpts;
});

// Service
var gcs = gcloud.storage();
gcs.decorateRequest(function(reqOpts) {
  // modify reqOpts
  return reqOpts;
});

// Service object
var bucket = gcs.bucket('my-bucket');
var file = bucket.file('my-file');

file.decorateRequest(function(reqOpts) {
  // modify reqOpts
  return reqOpts;
});

@stephenplusplus
Copy link
Contributor

Let's go with this:

var opts = { projectId: 'my-project-id' };
var storage = gcloud.storage(opts);

// Need to set a custom header
var newOpts = extend({}, opts, {
  decorateRequest: function(reqOpts) {
    reqOpts.headers['X-Cloud-Trace-Context'] = '...';
  }
});

var newStorage = gcloud.storage(newOpts);

storage.getBuckets(); // no custom header sent
newStorage.getBuckets(); // custom header sent

gcloud as well as any service object will accept the decorateRequest function.

Sound okay?

@callmehiphop
Copy link
Contributor

Reminds me of angular interceptors, a similar interface to that could be nice

var storage = gcloud.storage({ projectId: 'my-project-id' });

storage.interceptors.push({
  request: function (reqOptions) {
    if (someCondition) {
      reqOptions.headers['X-Yay-Headers'] = 'woot';
    }  
    return reqOptions;
  }
});

And as a side note, with the upcoming switch to promises this could potentially provide a nice interface for failed request logic, assuming we followed angular's api.

@stephenplusplus
Copy link
Contributor

Looks cool to me. 👍

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

No branches or pull requests

3 participants