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

integrate support for GAE dev #328

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions lib/common/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,21 @@ function makeWritableStream(dup, options, onComplete) {
module.exports.makeWritableStream = makeWritableStream;

function makeAuthorizedRequest(config) {
var GAE_OR_GCE = !config || (!config.credentials && !config.keyFile);
var ENV = {
GAE_DEV: process.env.GAE_LONG_APP_ID && !process.env.GAE_VM,
NO_CREDENTIALS: !config || (!config.credentials && !config.keyFile)
};

var authorize;

if (ENV.GAE_DEV && ENV.NO_CREDENTIALS) {
// Google App Engine Development mode doesn't require authorization.
authorize = function(reqOpts, callback) {
callback(null, reqOpts);
};
} else {
authorize = gsa(config);
}

var missingCredentialsError = new Error();
missingCredentialsError.message = [
Expand All @@ -357,8 +371,6 @@ function makeAuthorizedRequest(config) {
'\n'
].join('');

var authorize = gsa(config);

function makeRequest(reqOpts, callback) {
var tokenRefreshAttempts = 0;
reqOpts.headers = reqOpts.headers || {};
Expand All @@ -371,9 +383,8 @@ function makeAuthorizedRequest(config) {

function onAuthorizedRequest(err, authorizedReqOpts) {
if (err) {
if (GAE_OR_GCE && err.code === 'ENOTFOUND') {
// The metadata server wasn't found. The user must not actually be in
// a GAE or GCE environment.
if (ENV.NO_CREDENTIALS && err.code === 'ENOTFOUND') {
// The metadata server wasn't found. This must not be GAE or GCE.
throw missingCredentialsError;
}

Expand All @@ -385,8 +396,7 @@ function makeAuthorizedRequest(config) {

// For detecting Sign errors on io.js (1.x) (or node 0.11.x)
// E.g. errors in form: error:code:PEM routines:PEM_read_bio:error_name
var pemError = err.message &&
err.message.indexOf('error:') !== -1;
var pemError = err.message && err.message.indexOf('error:') !== -1;

if (err.message === 'SignFinal error' || pemError) {
err.message = [
Expand All @@ -412,6 +422,9 @@ function makeAuthorizedRequest(config) {
}

makeRequest.getCredentials = authorize.getCredentials;
makeRequest.getEnvironment = function() {
return ENV;
};

return makeRequest;
}
Expand Down
20 changes: 17 additions & 3 deletions lib/datastore/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

'use strict';

var http = require('http');
var https = require('https');
var streamEvents = require('stream-events');
var through = require('through2');
Expand Down Expand Up @@ -209,7 +210,7 @@ DatastoreRequest.prototype.get = function(keys, callback) {
* //-
* var companyKey = dataset.key(['Company', 123]);
* var productKey = dataset.key(['Product', 'Computer']);
*
*
* dataset.save([
* {
* key: companyKey,
Expand Down Expand Up @@ -492,6 +493,8 @@ DatastoreRequest.prototype.allocateIds = function(incompleteKey, n, callback) {
* Make a request to the API endpoint. Properties to indicate a transactional or
* non-transactional operation are added automatically.
*
* @todo Handle non-HTTP 200 cases.
*
* @param {string} method - Datastore action (allocateIds, commit, etc.).
* @param {object=} body - Request configuration object.
* @param {function} callback - The callback function.
Expand All @@ -507,7 +510,8 @@ DatastoreRequest.prototype.allocateIds = function(incompleteKey, n, callback) {
* transaction.makeReq('commit', deleteRequest, function(err) {});
*/
DatastoreRequest.prototype.makeReq_ = function(method, body, callback) {
// TODO: Handle non-HTTP 200 cases.
var ENV = this.makeAuthorizedRequest_.getEnvironment();

if (!callback) {
callback = body;
body = {};
Expand Down Expand Up @@ -550,7 +554,17 @@ DatastoreRequest.prototype.makeReq_ = function(method, body, callback) {
return;
}

var remoteStream = https.request(authorizedReqOpts, function(resp) {
var remoteStream;

if (ENV.GAE_DEV && ENV.NO_CREDENTIALS) {
authorizedReqOpts.host = process.env.API_HOST;
authorizedReqOpts.port = process.env.GAE_SERVER_PORT;
remoteStream = http.request(authorizedReqOpts);
} else {
remoteStream = https.request(authorizedReqOpts);
}

remoteStream.on('response', function(resp) {
var buffer = new Buffer('');
resp.on('data', function(chunk) {
buffer = Buffer.concat([buffer, chunk]);
Expand Down
75 changes: 69 additions & 6 deletions test/datastore/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var assert = require('assert');
var ByteBuffer = require('bytebuffer');
var entity = require('../../lib/datastore/entity.js');
var extend = require('extend');
var http = require('http');
var https = require('https');
var mockery = require('mockery');
var mockRespGet = require('../testdata/response_get.json');
Expand All @@ -39,6 +40,15 @@ extend(true, https, {
}
});

var httpRequestCached = http.request;
var httpRequestOverride = util.noop;

extend(true, http, {
request: function() {
return httpRequestOverride.apply(this, util.toArray(arguments));
}
});

// Create a protobuf "FakeMethod" request & response.
pb.FakeMethodRequest = function() {
this.toBuffer = function() {
Expand All @@ -62,6 +72,7 @@ describe('Request', function() {
before(function() {
mockery.registerMock('./pb.js', pb);
mockery.registerMock('https', https);
mockery.registerMock('http', http);
mockery.enable({
useCleanCache: true,
warnOnUnregistered: false
Expand All @@ -73,6 +84,7 @@ describe('Request', function() {
mockery.deregisterAll();
mockery.disable();
httpsRequestOverride = httpsRequestCached;
httpRequestOverride = httpRequestCached;
});

beforeEach(function() {
Expand All @@ -85,6 +97,9 @@ describe('Request', function() {
request.makeAuthorizedRequest_ = function(req, callback) {
(callback.onAuthorized || callback)(null, req);
};
request.makeAuthorizedRequest_.getEnvironment = function() {
return {};
};
});

describe('get', function() {
Expand Down Expand Up @@ -487,10 +502,13 @@ describe('Request', function() {
assert.equal(opts.headers['Content-Type'], 'application/x-protobuf');
done();
};
request.makeAuthorizedRequest_.getEnvironment = function() {
return {};
};
request.makeReq_(method, {}, util.noop);
});

it('should make https request', function(done) {
it('should make https request if not gae dev and no creds', function(done) {
var mockRequest = { mock: 'request' };
httpsRequestOverride = function(req) {
assert.deepEqual(req, mockRequest);
Expand All @@ -500,6 +518,45 @@ describe('Request', function() {
request.makeAuthorizedRequest_ = function(opts, callback) {
(callback.onAuthorized || callback)(null, mockRequest);
};
request.makeAuthorizedRequest_.getEnvironment = function() {
return {
GAE_DEV: false,
NO_CREDENTIALS: false
};
};
request.makeReq_('commit', {}, util.noop);
});

it('should make http call to API_HOST if no credentials', function(done) {
var mockRequest = { mock: 'request' };

var API_HOST_CACHED = process.env.API_HOST;
var GAE_SERVER_PORT_CACHED = process.env.GAE_SERVER_PORT;

process.env.API_HOST = 'API_HOST';
process.env.GAE_SERVER_PORT = 99;

httpRequestOverride = function(req) {
assert.deepEqual(req, mockRequest);
assert.equal(req.host, process.env.API_HOST);
assert.equal(req.port, process.env.GAE_SERVER_PORT);

done();

process.env.API_HOST = API_HOST_CACHED;
process.env.GAE_SERVER_PORT = GAE_SERVER_PORT_CACHED;

return new stream.Writable();
};
request.makeAuthorizedRequest_ = function(opts, callback) {
(callback.onAuthorized || callback)(null, mockRequest);
};
request.makeAuthorizedRequest_.getEnvironment = function() {
return {
GAE_DEV: true,
NO_CREDENTIALS: true
};
};
request.makeReq_('commit', {}, util.noop);
});

Expand All @@ -521,11 +578,14 @@ describe('Request', function() {
pbFakeMethodResponseDecode = function() {
done();
};
httpsRequestOverride = function(req, callback) {
var ws = new stream.Writable();
callback(ws);
ws.emit('end');
return ws;
httpsRequestOverride = function() {
var requestStream = new stream.PassThrough();
var responseStream = new stream.PassThrough();
setImmediate(function() {
requestStream.emit('response', responseStream);
responseStream.end();
});
return requestStream;
};
request.makeReq_('fakeMethod', util.noop);
});
Expand All @@ -535,6 +595,9 @@ describe('Request', function() {
request.createAuthorizedRequest_ = function(opts, callback) {
(callback.onAuthorized || callback)();
};
request.makeAuthorizedRequest_.getEnvironment = function() {
return {};
};
});

describe('commit', function() {
Expand Down