Skip to content

Commit

Permalink
Fixed dist file build error.
Browse files Browse the repository at this point in the history
  • Loading branch information
jonsamwell committed Aug 21, 2015
1 parent 588773e commit 02d2c74
Show file tree
Hide file tree
Showing 9 changed files with 632 additions and 204 deletions.
5 changes: 3 additions & 2 deletions bower.json
@@ -1,6 +1,6 @@
{
"name": "angular-http-batcher",
"version": "1.11.1",
"version": "1.11.2",
"description": "Enables transparent HTTP batch requests with Angular",
"main": "dist/angular-http-batch.js",
"keywords": [
Expand Down Expand Up @@ -34,7 +34,8 @@
],
"devDependencies": {
"sinon": "~1.10.3",
"angular-mocks": ">=1.2.23"
"angular-mocks": ">=1.2.23",
"angular-resource": ">=1.2.23"
},
"dependencies": {
"angular": ">= 1.2.23"
Expand Down
3 changes: 3 additions & 0 deletions dist/ChangeLog.txt
@@ -1,3 +1,6 @@
21/08/2015 V1.11.2
Fixed dist file build error.

11/08/2015 V1.11.1
Added support for the Angular Json protection vulnerability when parsing json (see https://docs.angularjs.org/api/ng/service/$http#json-vulnerability-protection)
thanks to @riann (https://github.com/riaann) for this!!
Expand Down
351 changes: 350 additions & 1 deletion dist/angular-http-batch.js
@@ -1,5 +1,5 @@
/*
* angular-http-batcher - v1.11.1 - 2015-08-11
* angular-http-batcher - v1.11.2 - 2015-08-21
* https://github.com/jonsamwell/angular-http-batcher
* Copyright (c) 2015 Jon Samwell
*/
Expand Down Expand Up @@ -174,6 +174,355 @@ function HttpBatchConfigFn() {

angular.module(window.ahb.name).provider('httpBatchConfig', HttpBatchConfigFn);

/**
*
* @param request
* @param statusCode
* @param statusText
* @param data
* @param headers - object or string
* @constructor
*/
function HttpBatchResponseData(request, statusCode, statusText, data, headers) {
this.request = request;
this.statusCode = statusCode;
this.statusText = statusText;
this.data = data;
this.headers = headers;
}

window.ahb.HttpBatchResponseData = HttpBatchResponseData;

function HttpBatchAdapter($document, $window, httpBatchConfig) {
var self = this,
constants = {
httpVersion: 'HTTP/1.1',
contentType: 'Content-Type',
newline: '\r\n',
emptyString: '',
singleSpace: ' ',
forwardSlash: '/',
doubleDash: '--',
colon: ':'
};

self.key = 'httpBatchAdapter';
self.buildRequest = buildRequestFn;
self.parseResponse = parseResponseFn;
self.canBatchRequest = canBatchRequestFn;

/**
* Builds the single batch request from the given batch of pending requests.
* Returns a standard angular httpConfig object that will be use to invoke the $http service.
* See:
* https://developers.google.com/storage/docs/json_api/v1/how-tos/batch
* http://blogs.msdn.com/b/webdev/archive/2013/11/01/introducing-batch-support-in-web-api-and-web-api-odata.aspx
*
* @param requests - the collection of pending http request to build into a single http batch request.
* @param config - the http batch config.
* @returns {object} - a http config object.
*/
function buildRequestFn(requests, config) {
var boundary = httpBatchConfig.calculateBoundary(),
httpConfig = {
method: 'POST',
url: config.batchEndpointUrl,
cache: false,
headers: config.batchRequestHeaders || {}
},
batchBody = [],
urlInfo, i, request, header;

httpConfig.headers[constants.contentType] = 'multipart/mixed; boundary=' + boundary;

for (i = 0; i < requests.length; i += 1) {
request = requests[i];
urlInfo = getUrlInfo(request.url);

batchBody.push(constants.doubleDash + boundary);
if (config.batchPartRequestHeaders) {
for (header in config.batchPartRequestHeaders) {
batchBody.push(header + constants.colon + constants.singleSpace + config.batchPartRequestHeaders[header]);
}
}

batchBody.push('Content-Type: application/http; msgtype=request', constants.emptyString);

batchBody.push(request.method + ' ' + urlInfo.relativeUrl + ' ' + constants.httpVersion);
batchBody.push('Host: ' + urlInfo.host);

for (header in request.headers) {
batchBody.push(header + constants.colon + constants.singleSpace + request.headers[header]);
}

if (config.sendCookies === true && $document[0].cookie && $document[0].cookie.length > 0) {
batchBody.push('Cookie: ' + $document[0].cookie);
}

batchBody.push(constants.emptyString);

if (request.data) {
batchBody.push(request.data);
}

batchBody.push(constants.emptyString);
}

batchBody.push(constants.doubleDash + boundary + constants.doubleDash);
httpConfig.data = batchBody.join(constants.newline);
return httpConfig;
}

/**
* Parses the raw response into an array of HttpBatchResponseData objects. If is this methods job
* to parse the response and match it up with the orginal request object.
* @param rawResponse
* @param config
* @returns {Array.HttpBatchResponseData[]}
*/
function parseResponseFn(requests, rawResponse, config) {
var batchResponses = [],
boundaryToken = findResponseBoundary(rawResponse.headers()['content-type']),
parts = rawResponse.data.split(constants.doubleDash + boundaryToken + constants.newline),
i,
part,
responseCount = 0;

for (i = 0; i < parts.length; i += 1) {
part = parts[i];
if (part !== constants.emptyString) {
batchResponses.push(processResponse(part, requests[responseCount], boundaryToken));
responseCount += 1;
}
}

return batchResponses;
}

/**
* Gaurd method to ensure the adapter supports this given request.
* @param request
* @param config
* @returns {boolean} false to indicate the request type is not supported.
*/
function canBatchRequestFn(request, config) {
return true;
}

/**
* mainly here to polyfill ie8 :-(
*/
function trim(data) {
if (data.trim) {
data = data.trim();
} else {
data = data.replace(/^\s+|\s+$/g, '');
}

return data;
}

function getUrlInfo(url) {
var protocol,
host,
relativeUrl,
protocolEndIndex,
urlParts;

if (url.indexOf('./') > -1 || url.indexOf('../') > -1) {
// we have a complex relative url i.e. './api/products' or '../api/products
var parser = document.createElement('a');
parser.href = url;
url = parser.href;
}

if (url.indexOf('://') > -1) {
protocolEndIndex = url.indexOf('://') + 3;
urlParts = url.slice(protocolEndIndex).split(constants.forwardSlash);
// we have an absolute url
protocol = url.substring(0, protocolEndIndex);
// Get the host portion of the url from '://' to the next'/'
// [https://www.somedomain.com/]api/messages
host = urlParts[0];
relativeUrl = (function () {
delete urlParts[0];
return urlParts.join(constants.forwardSlash);
}());
} else {
//we have a relative url
relativeUrl = url;
protocol = $window.location.protocol;
host = $window.location.host;
}

return {
protocol: protocol,
host: host,
relativeUrl: relativeUrl
};
}

function findResponseBoundary(contentType) {
var boundaryText = 'boundary=',
startIndex = contentType.indexOf(boundaryText),
boundary = contentType.substring(startIndex + boundaryText.length);

// the boundary might be quoted so remove the quotes
boundary = boundary.replace(/"/g, constants.emptyString);
return boundary;
}

function convertDataToCorrectType(contentType, dataStr) {
var data = dataStr;
contentType = contentType.toLowerCase();

if (contentType.indexOf('json') > -1) {
data = angular.fromJson(dataStr);
}

return data;
}

function processResponse(part, request, boundaryToken) {
var responseParts = part.split(constants.newline),
result = {
headers: {}
},
responsePart,
i, j, regex, lineParts, headerParts, parsedSpaceBetweenHeadersAndMessage = false;

for (i = 0; i < responseParts.length; i += 1) {
responsePart = responseParts[i];
if (responsePart === constants.emptyString) {
parsedSpaceBetweenHeadersAndMessage = result.contentType !== undefined;
continue;
}

if (result.contentType === undefined && responsePart.indexOf('-Type') !== -1 && responsePart.indexOf('; msgtype=response') === -1) {
result.contentType = responsePart.split(constants.forwardSlash)[1];
} else if (result.contentType !== undefined && parsedSpaceBetweenHeadersAndMessage === false) {
headerParts = responsePart.split(constants.colon);
result.headers[headerParts[0]] = trim(headerParts[1]);
} else if (result.statusCode === undefined && responsePart.indexOf(constants.httpVersion) !== -1) {
lineParts = responsePart.split(constants.singleSpace);
result.statusCode = parseInt(lineParts[1], 10);
result.statusText = lineParts.slice(2).join(constants.singleSpace);
} else if (result.data === undefined && parsedSpaceBetweenHeadersAndMessage) {
// need to get all the lines left apart from the last multipart seperator.
result.data = '';
j = 1;
regex = new RegExp('--' + boundaryToken + '--', 'i');
while (regex.test(responsePart) === false && ((i + j) <= responseParts.length)) {
result.data += responsePart;
responsePart = responseParts[i + j];
j += 1;
}

result.data = convertDataToCorrectType(result.contentType, result.data);
break;
}
}

result.headers[constants.contentType] = result.contentType;
return new window.ahb.HttpBatchResponseData(request, result.statusCode, result.statusText, result.data, result.headers);
}
}

HttpBatchAdapter.$inject = [
'$document',
'$window',
'httpBatchConfig'
];

angular.module(window.ahb.name).service('httpBatchAdapter', HttpBatchAdapter);

function NodeJsMultiFetchAdapter() {
var self = this;

self.key = 'nodeJsMultiFetchAdapter';
self.buildRequest = buildRequestFn;
self.parseResponse = parseResponseFn;
self.canBatchRequest = canBatchRequestFn;

/**
* Builds the single batch request from the given batch of pending requests.
* Returns a standard angular httpConfig object that will be use to invoke the $http service.
* See:
* https://developers.google.com/storage/docs/json_api/v1/how-tos/batch
* http://blogs.msdn.com/b/webdev/archive/2013/11/01/introducing-batch-support-in-web-api-and-web-api-odata.aspx
*
* @param requests - the collection of pending http request to build into a single http batch request.
* @param config - the http batch config.
* @returns {object} - a http config object.
*/
function buildRequestFn(requests, config) {
var httpConfig = {
method: 'GET',
url: config.batchEndpointUrl + '?',
cache: false,
headers: config.batchRequestHeaders || {}
},
encodedUrl, i, request,
urlParts;

for (i = 0; i < requests.length; i += 1) {
request = requests[i];
urlParts = request.url.split('?');

encodedUrl = urlParts[0].replace(config.serviceUrl, '');
if (urlParts.length > 1) {
encodedUrl += '?' + encodeURIComponent(urlParts[1]);
}

if (i > 0) {
httpConfig.url += '&';
}

httpConfig.url += i.toString() + '=' + encodedUrl;
}

return httpConfig;
}

/**
* Parses the raw response into an array of HttpBatchResponseData objects. If is this methods job
* to parse the response and match it up with the orginal request object.
* @param rawResponse
* @returns {Array.HttpBatchResponseData[]}
*/
function parseResponseFn(requests, rawResponse) {
var batchResponses = [],
i, request,
responseData = rawResponse.data,
dataPart;

for (i = 0; i < requests.length; i += 1) {
request = requests[i];
dataPart = responseData[i.toString()];

batchResponses.push(new window.ahb.HttpBatchResponseData(
request,
dataPart.statusCode,
'',
dataPart.body,
dataPart.headers));
}

return batchResponses;
}

/**
* Gaurd method to ensure the adapter supports this given request.
* @param request
* @returns {boolean} false to indicate the request type is not supported.
*/
function canBatchRequestFn(request) {
return request.method === 'GET';
}
}

angular.module(window.ahb.name).service('nodeJsMultiFetchAdapter', NodeJsMultiFetchAdapter);

function convertHeadersToString(headers) {
var property,
result = '';
Expand Down

0 comments on commit 02d2c74

Please sign in to comment.