-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
S3UTILS-149 Prevent deleting versions with pending replication
- Loading branch information
1 parent
8ebc522
commit 32b64fa
Showing
3 changed files
with
266 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
const { auth } = require('arsenal'); | ||
|
||
const http = require('http'); | ||
const https = require('https'); | ||
const querystring = require('querystring'); | ||
const fs = require('fs'); | ||
|
||
const ipAddress = process.env.IP ? process.env.IP : '127.0.0.1'; | ||
|
||
function _parseError(responseBody, statusCode, jsonResponse) { | ||
if (jsonResponse && statusCode !== 200) { | ||
return JSON.parse(responseBody); | ||
} | ||
if (responseBody.indexOf('<Error>') > -1) { | ||
const error = {}; | ||
const codeStartIndex = responseBody.indexOf('<Code>') + 6; | ||
const codeEndIndex = responseBody.indexOf('</Code>'); | ||
error.code = responseBody.slice(codeStartIndex, codeEndIndex); | ||
const msgStartIndex = responseBody.indexOf('<Message>') + 9; | ||
const msgEndIndex = responseBody.indexOf('</Message>'); | ||
error.message = responseBody.slice(msgStartIndex, msgEndIndex); | ||
return error; | ||
} | ||
return null; | ||
} | ||
|
||
function _decodeURI(uri) { | ||
// do the same decoding than in S3 server | ||
return decodeURIComponent(uri.replace(/\+/g, ' ')); | ||
} | ||
|
||
/** _makeRequest - utility function to generate a request | ||
* @param {object} params - params for making request | ||
* @param {string} params.hostname - request hostname | ||
* @param {number} [params.port] - request port | ||
* @param {string} params.method - request method | ||
* @param {string} [params.path] - URL-encoded request path | ||
* @param {boolean} [params.jsonResponse] - if true, response is | ||
* expected to be received in JSON format (including errors) | ||
* @param {object} [params.queryObj] - query fields and their string values | ||
* @param {object} [params.authCredentials] - authentication credentials | ||
* @param {object} params.authCredentials.accessKey - access key | ||
* @param {object} params.authCredentials.secretKey - secret key | ||
* @param {boolean} [params.isHttps] - whether the request is made using the HTTPS protocol | ||
* @param {object} [params.agent] - request agent | ||
* @param {object} [params.headers] - headers and their string values | ||
* @param {string} [params.requestBody] - request body contents | ||
* @param {function} callback - with error and response parameters | ||
* @return {undefined} - and call callback | ||
*/ | ||
function _makeRequest(params, callback) { | ||
const { | ||
hostname, | ||
port, | ||
method, | ||
path, | ||
jsonResponse, | ||
queryObj, | ||
authCredentials, | ||
isHttps, | ||
agent, | ||
headers, | ||
requestBody, | ||
} = params; | ||
|
||
const options = { | ||
hostname, | ||
port, | ||
method, | ||
headers, | ||
path: path || '/', | ||
rejectUnauthorized: false, | ||
agent, | ||
}; | ||
|
||
const qs = querystring.stringify(queryObj); | ||
|
||
const transport = isHttps ? https : http; | ||
|
||
const req = transport.request(options, res => { | ||
const body = []; | ||
res.on('data', chunk => { | ||
body.push(chunk); | ||
}); | ||
res.on('error', callback); | ||
res.on('end', () => { | ||
const total = body.join(''); | ||
const data = { | ||
headers: res.headers, | ||
statusCode: res.statusCode, | ||
body: total, | ||
}; | ||
const err = _parseError(total, res.statusCode, jsonResponse); | ||
if (err) { | ||
err.statusCode = res.statusCode; | ||
} | ||
return callback(err, data); | ||
}); | ||
}); | ||
|
||
req.on('error', callback); | ||
// generate v4 headers if authentication credentials are provided | ||
const encodedPath = req.path; | ||
// decode path because signing code re-encodes it | ||
req.path = _decodeURI(encodedPath); | ||
if (authCredentials) { | ||
if (queryObj) { | ||
auth.client.generateV4Headers(req, queryObj, authCredentials.accessKey, authCredentials.secretKey, 's3'); | ||
// may update later if request may contain POST body | ||
} else { | ||
auth.client.generateV4Headers(req, '', authCredentials.accessKey, authCredentials.secretKey, 's3'); | ||
} | ||
} | ||
// restore original URL-encoded path | ||
req.path = encodedPath; | ||
req.path = queryObj ? `${options.path}?${qs}` : req.path; | ||
if (requestBody) { | ||
req.write(requestBody); | ||
} | ||
req.end(); | ||
} | ||
|
||
|
||
/** _makeBackbeatRequest - utility function to generate a request going | ||
* through backbeat route | ||
* @param {object} params - params for making request | ||
* @param {string} params.hostname - request hostname | ||
* @param {string} params.port - request port | ||
* @param {string} params.method - request method | ||
* @param {string} params.resourceType - request source type ("data", "metadata", "multiplebackenddata", ...) | ||
* @param {string} params.bucket - bucket name | ||
* @param {string} params.objectKey - object key | ||
* @param {object} [params.queryObj] - query params | ||
* @param {object} [params.authCredentials] - authentication credentials | ||
* @param {object} params.authCredentials.accessKey - access key | ||
* @param {object} params.authCredentials.secretKey - secret key | ||
* @param {string} params.isHttps - whether the request is made using the HTTPS protocol | ||
* @param {string} params.agent - request agent | ||
* @param {object} [params.headers] - headers and their string values | ||
* @param {string} [params.requestBody] - request body content | ||
* @param {function} callback - with error and response parameters | ||
* @return {undefined} - and call callback | ||
*/ | ||
function makeBackbeatRequest(params, callback) { | ||
const { | ||
hostname, | ||
port, | ||
method, | ||
resourceType, | ||
bucket, | ||
objectKey, | ||
queryObj, | ||
authCredentials, | ||
isHttps, | ||
agent, | ||
headers, | ||
requestBody, | ||
} = params; | ||
|
||
const options = { | ||
hostname, | ||
port, | ||
method, | ||
path: `/_/backbeat/${resourceType}/${bucket}/${objectKey}`, | ||
jsonResponse: true, | ||
queryObj, | ||
authCredentials, | ||
isHttps, | ||
agent, | ||
headers, | ||
requestBody, | ||
}; | ||
_makeRequest(options, callback); | ||
} | ||
|
||
module.exports = { makeBackbeatRequest }; |