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

Addition of md5 calculation on get_blob blobs below 4mb and md5 header fixes #4716

Merged
merged 1 commit into from
Apr 24, 2018
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/endpoint/blob/blob_errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ const errors_defs = [{
code: 'InvalidBlobOrBlock',
message: 'The specified blob or block content is invalid.',
http_code: 400,
}, {
code: 'InvalidHeaderValue',
message: 'The value provided for one of the HTTP headers was not in the correct format.',
http_code: 400,
}, {
code: 'OutOfRangeQueryParameterValue',
message: 'A query parameter specified in the request URI is outside the permissible range.',
http_code: 400,
}, {
code: 'BlobNotFound',
message: 'The specified blob does not exist.',
Expand Down
29 changes: 28 additions & 1 deletion src/endpoint/blob/ops/blob_get_blob.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const dbg = require('../../../util/debug_module')(__filename);
const BlobError = require('../blob_errors').BlobError;
const blob_utils = require('../blob_utils');
const http_utils = require('../../../util/http_utils');
const crypto = require('crypto');

// TODO merge code with s3_get_object

Expand All @@ -13,6 +14,8 @@ const http_utils = require('../../../util/http_utils');
* GET : https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob
*/
function get_blob(req, res) {
const get_range_md5 = req.headers['x-ms-range-get-content-md5'] === 'true';

return req.object_sdk.read_object_md({
bucket: req.params.bucket,
key: req.params.key,
Expand All @@ -38,6 +41,8 @@ function get_blob(req, res) {
obj_size);

if (!ranges) {
if (get_range_md5) throw new BlobError(BlobError.InvalidHeaderValue);
if (object_md.md5_b64) res.setHeader('Content-MD5', object_md.md5_b64);
if (req.method === 'HEAD') return;
// stream the entire object to the response
dbg.log1('reading object', req.path, obj_size);
Expand All @@ -61,13 +66,18 @@ function get_blob(req, res) {
// reply with HTTP 206 Partial Content
params.start = ranges[0].start;
params.end = ranges[0].end + 1; // use exclusive end
const range_size = params.start - params.end;
const FOUR_MB_IN_BYTES = 4 * 1024 * 1024;
const content_range = `bytes ${params.start}-${params.end - 1}/${obj_size}`;
dbg.log1('reading object range', req.path, content_range, ranges);
res.setHeader('Content-Range', content_range);
res.setHeader('Content-Length', params.end - params.start);
// res.header('Cache-Control', 'max-age=0' || 'no-cache');

if (req.method === 'HEAD') return;
if (get_range_md5 && range_size > FOUR_MB_IN_BYTES) {
throw new BlobError(BlobError.OutOfRangeQueryParameterValue);
}
res.statusCode = 206;
return req.object_sdk.read_object_stream(params);

Expand All @@ -87,7 +97,24 @@ function get_blob(req, res) {
dbg.log0('response error:', err, req.path);
if (read_stream.close) read_stream.close();
});
read_stream.pipe(res);

if (get_range_md5) {
const buffers = [];
const hash = crypto.createHash('md5');
read_stream.on('data', data => {
buffers.push(data);
hash.update(data);
});
read_stream.on('end', () => {
res.setHeader('Content-MD5', hash.digest('base64'));
for (const data of buffers) {
res.write(data);
}
res.end();
});
} else {
read_stream.pipe(res);
}
});
}

Expand Down
2 changes: 2 additions & 0 deletions src/server/system_services/account_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ function get_system_roles(req) {
*/

async function add_external_connection(req) {
dbg.log0('add_external_connection:', req.rpc_params);
const res = await check_external_connection(req);
if (res.status !== 'SUCCESS') {
throw new RpcError(res.error.code, res.error.message);
Expand Down Expand Up @@ -639,6 +640,7 @@ async function add_external_connection(req) {
}

function check_external_connection(req) {
dbg.log0('check_external_connection:', req.rpc_params);
const { endpoint_type } = req.rpc_params;
const params = req.rpc_params;
const system = req.system;
Expand Down