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

#498: Fixing incorrect error message processing #17

Merged
merged 2 commits into from Dec 22, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
185 changes: 111 additions & 74 deletions lib/services/core/serviceclient.js
Expand Up @@ -189,80 +189,86 @@ ServiceClient.prototype.performRequestInputStream = function (webResource, outpu
ServiceClient.prototype._performRequest = function (webResource, body, options, callback) {
var self = this;
self._buildRequestOptions(webResource, options, function (err, requestOptions) {
self.logger.log(Logger.LogLevels.DEBUG, "REQUEST OPTIONS:\n" + util.inspect(requestOptions));
if (err) {
callback({ error: err, response: null }, function (requestOptions, finalCallback) {
finalCallback(requestOptions);
});
} else {
self.logger.log(Logger.LogLevels.DEBUG, "REQUEST OPTIONS:\n" + util.inspect(requestOptions));

var operation = function (finalRequestOptions, operationCallback, next) {
self.logger.log(Logger.LogLevels.DEBUG, "FINAL REQUEST OPTIONS:\n" + util.inspect(finalRequestOptions));
var operation = function (finalRequestOptions, operationCallback, next) {
self.logger.log(Logger.LogLevels.DEBUG, "FINAL REQUEST OPTIONS:\n" + util.inspect(finalRequestOptions));

var processResponseCallback = function (error, response, responseBody) {
var responseObject;
var processResponseCallback = function (error, response, responseBody) {
var responseObject;

if (error) {
responseObject = { error: error, response: null };
} else {
responseObject = self._processResponse(webResource, response);
}
if (error) {
responseObject = { error: error, response: null };
} else {
responseObject = self._processResponse(webResource, response);
}

operationCallback(responseObject, next);
};
operationCallback(responseObject, next);
};

if (body && body.outputData) {
finalRequestOptions.body = body.outputData;
}
if (body && body.outputData) {
finalRequestOptions.body = body.outputData;
}

var buildRequest = function () {
// Build request (if body was set before, request will process immediately, if not it'll wait for the piping to happen)
var requestStream = request(finalRequestOptions, processResponseCallback);
var oldEnd = requestStream.end;
requestStream.end = function () {
if (finalRequestOptions.headers['content-length']) {
requestStream.headers['content-length'] = finalRequestOptions.headers['content-length'];
} else if (requestStream.headers['content-length']) {
delete requestStream.headers['content-length'];
}
var buildRequest = function () {
// Build request (if body was set before, request will process immediately, if not it'll wait for the piping to happen)
var requestStream = request(finalRequestOptions, processResponseCallback);
var oldEnd = requestStream.end;
requestStream.end = function () {
if (finalRequestOptions.headers['content-length']) {
requestStream.headers['content-length'] = finalRequestOptions.headers['content-length'];
} else if (requestStream.headers['content-length']) {
delete requestStream.headers['content-length'];
}

oldEnd.call(requestStream);
};

// Bubble events up
requestStream.on('response', function (response) {
self.emit('response', response);
});

oldEnd.call(requestStream);
return requestStream;
};

// Bubble events up
requestStream.on('response', function (response) {
self.emit('response', response);
});
// Pipe any input / output streams
if (body && body.inputStream) {
buildRequest().pipe(body.inputStream);
} else if (body && body.outputStream) {
if (!body.outputStream.readable) {
var requestStream = buildRequest();

return requestStream;
};

// Pipe any input / output streams
if (body && body.inputStream) {
buildRequest().pipe(body.inputStream);
} else if (body && body.outputStream) {
if (!body.outputStream.readable) {
var requestStream = buildRequest();
// This will wait until we know the readable stream is actually valid before piping
body.outputStream.on('open', function () {
body.outputStream.pipe(requestStream);
});
} else {
body.outputStream.pipe(buildRequest());
}

// This will wait until we know the readable stream is actually valid before piping
body.outputStream.on('open', function () {
body.outputStream.pipe(requestStream);
// This catches any errors that happen while creating the readable stream (usually invalid names)
body.outputStream.on('error', function(error) {
processResponseCallback(error);
});
} else {
body.outputStream.pipe(buildRequest());
buildRequest();
}
};

// This catches any errors that happen while creating the readable stream (usually invalid names)
body.outputStream.on('error', function(error) {
processResponseCallback(error);
});
} else {
buildRequest();
}
};

// The filter will do what it needs to the requestOptions and will provide a
// function to be handled after the reply
self.filter(requestOptions, function (postFiltersRequestOptions, nextPostCallback) {
// If there is a filter, flow is:
// filter -> operation -> process response -> next filter
operation(postFiltersRequestOptions, callback, nextPostCallback);
});
// The filter will do what it needs to the requestOptions and will provide a
// function to be handled after the reply
self.filter(requestOptions, function (postFiltersRequestOptions, nextPostCallback) {
// If there is a filter, flow is:
// filter -> operation -> process response -> next filter
operation(postFiltersRequestOptions, callback, nextPostCallback);
});
}
});
};

Expand Down Expand Up @@ -467,10 +473,11 @@ ServiceClient.prototype._buildResponse = function (isSuccessful, body, headers,
*/
ServiceClient.prototype._parseResponse = function (response) {
if (!azureutil.objectIsNull(response.body) && response.body.trim() !== '') {
var parsedBody = null;

if (response.headers['content-type'] &&
response.headers['content-type'].indexOf('application/json') != -1) {

var parsedBody = null;
try {
parsedBody = JSON.parse(response.body);
} catch (error) {
Expand All @@ -482,21 +489,46 @@ ServiceClient.prototype._parseResponse = function (response) {
parser.on('error', function (e) { parseError = e; });
parser.parseString(response.body);

var parsedBody;
if (parser.resultObject) {
parsedBody = parser.resultObject;
} else {
parsedBody = { parsingError: parseError };
// If it failed to parse, try to parse in string format
if (response.body) {
response.body = response.body.toLowerCase();

var codeIndex = response.body.indexOf('code:');
if (codeIndex !== -1) {
var resultObject = { };

var endIndex = response.body.indexOf(':', codeIndex);
if (endIndex === -1) {
endIndex = response.body.length - 1;
}

var codeMessage = response.body.substr(codeIndex + 5, endIndex - codeIndex - 1);
resultObject['code'] = codeMessage;

var detailIndex = response.body.indexOf('detail:');
if (detailIndex !== -1) {
var detailMessage = response.body.substr(detailIndex + 7);
resultObject['detail'] = detailMessage;
}

parsedBody = resultObject;
}
}

if (!parsedBody) {
parsedBody = { parsingError: parseError };
}
}
}

if (!azureutil.objectIsNull(parsedBody.parsingError)) {
response.isSuccessful = false;
response.parsingError = parsedBody.parsingError;
} else if (!azureutil.objectIsNull(parsedBody)) {
response.body = parsedBody;
} else {
response.isSuccessful = false;
response.body = parsedBody;
}
}

Expand Down Expand Up @@ -591,18 +623,23 @@ ServiceClient.isEmulated = function (host) {
* @return {Object} The normalized error object with all properties lower cased.
*/
ServiceClient.prototype._normalizeError = function (error) {
var normalizedError = new Error();
for (var property in error) {
if (property !== '@') {
if (error[property] && error[property]['#']) {
normalizedError[property.toLowerCase()] = error[property]['#'];
} else {
normalizedError[property.toLowerCase()] = error[property];
if (azureutil.objectIsString(error)) {
return new Error(error);
} else {
var normalizedError = new Error();

for (var property in error) {
if (property !== '@') {
if (error[property] && error[property]['#']) {
normalizedError[property.toLowerCase()] = error[property]['#'];
} else {
normalizedError[property.toLowerCase()] = error[property];
}
}
}
}

return normalizedError;
return normalizedError;
}
};

/**
Expand Down
12 changes: 7 additions & 5 deletions lib/services/serviceBus/servicebusservice.js
Expand Up @@ -666,12 +666,14 @@ ServiceBusService.prototype.createTopicIfNotExists = function (topic, optionsOrC
webResource.addOptionalHeader(HeaderConstants.CONTENT_LENGTH, Buffer.byteLength(topicXml, 'utf8'));

var processResponseCallback = function (responseObject, next) {
// Check if topic was actually created.
responseObject.created = (responseObject.response.statusCode === HttpConstants.HttpResponseCodes.CREATED_CODE);
if (responseObject.response) {
// Check if topic was actually created.
responseObject.created = (responseObject.response.statusCode === HttpConstants.HttpResponseCodes.CREATED_CODE);

if (responseObject.response.statusCode === HttpConstants.HttpResponseCodes.CREATED_CODE || responseObject.response.statusCode === HttpConstants.HttpResponseCodes.CONFLICT_CODE) {
// If it was created before, there was no actual error.
responseObject.error = null;
if (responseObject.response.statusCode === HttpConstants.HttpResponseCodes.CREATED_CODE || responseObject.response.statusCode === HttpConstants.HttpResponseCodes.CONFLICT_CODE) {
// If it was created before, there was no actual error.
responseObject.error = null;
}
}

var finalCallback = function (returnObject) {
Expand Down
22 changes: 22 additions & 0 deletions test/services/serviceBus/servicebusservice-tests.js
Expand Up @@ -1671,4 +1671,26 @@ suite('servicebusservice-tests', function () {

done();
});

test('invalidAccessKeyGivesError', function (done) {
var serviceBusService = azure.createServiceBusService(process.env['AZURE_SERVICEBUS_NAMESPACE'], 'key');
// fails, with an error on the callback.
serviceBusService.createTopicIfNotExists('Topic', function(error) {
assert.notEqual(error, null);
assert.equal(error.code, '401');

done();
});
});

test('invalidNamespaceGivesError', function (done) {
var serviceBusService = azure.createServiceBusService('BoGuS', process.env['AZURE_SERVICEBUS_ACCESS_KEY']);
// fails, with an error on the callback.
serviceBusService.createTopicIfNotExists('Topic', function(error) {
assert.notEqual(error, null);
assert.equal(error.code, 'ENOTFOUND');

done();
});
});
});