diff --git a/src/endpoint/endpoint.js b/src/endpoint/endpoint.js index eaaae0014d..db6a8c0f8e 100755 --- a/src/endpoint/endpoint.js +++ b/src/endpoint/endpoint.js @@ -234,6 +234,7 @@ function create_endpoint_handler(init_request_sdk, virtual_hosts, sts) { /** @type {EndpointHandler} */ const endpoint_request_handler = (req, res) => { + endpoint_utils.set_noobaa_server_header(res); endpoint_utils.prepare_rest_request(req); req.virtual_hosts = virtual_hosts; init_request_sdk(req, res); @@ -251,6 +252,7 @@ function create_endpoint_handler(init_request_sdk, virtual_hosts, sts) { }; /** @type {EndpointHandler} */ const endpoint_sts_request_handler = (req, res) => { + endpoint_utils.set_noobaa_server_header(res); endpoint_utils.prepare_rest_request(req); init_request_sdk(req, res); return sts_rest(req, res); diff --git a/src/endpoint/endpoint_utils.js b/src/endpoint/endpoint_utils.js index 373227d20f..71f93254bc 100644 --- a/src/endpoint/endpoint_utils.js +++ b/src/endpoint/endpoint_utils.js @@ -3,6 +3,7 @@ const querystring = require('querystring'); const http_utils = require('../util/http_utils'); +const pkg = require('../../package.json'); function prepare_rest_request(req) { // generate request id, this is lighter than uuid @@ -38,6 +39,10 @@ function parse_source_url(source_url) { return { query, bucket, key }; } +function set_noobaa_server_header(res) { + res.setHeader('Server', `NooBaa/${pkg.version}`); +} exports.prepare_rest_request = prepare_rest_request; exports.parse_source_url = parse_source_url; +exports.set_noobaa_server_header = set_noobaa_server_header; diff --git a/src/endpoint/s3/ops/s3_head_bucket.js b/src/endpoint/s3/ops/s3_head_bucket.js index 4d3eb0c89b..99c2d68de4 100644 --- a/src/endpoint/s3/ops/s3_head_bucket.js +++ b/src/endpoint/s3/ops/s3_head_bucket.js @@ -1,13 +1,14 @@ /* Copyright (C) 2016 NooBaa */ 'use strict'; +const s3_utils = require("../s3_utils"); + /** * http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketHEAD.html */ -async function head_bucket(req) { - await req.object_sdk.read_bucket({ name: req.params.bucket }); - // only called to check for existence - // no headers or reply needed +async function head_bucket(req, res) { + const bucket_info = await req.object_sdk.read_bucket({ name: req.params.bucket }); + s3_utils.set_response_supported_storage_classes(res, bucket_info.supported_storage_classes); } module.exports = { diff --git a/src/endpoint/s3/s3_utils.js b/src/endpoint/s3/s3_utils.js index 199ac5f4f2..bda575a69e 100644 --- a/src/endpoint/s3/s3_utils.js +++ b/src/endpoint/s3/s3_utils.js @@ -36,6 +36,8 @@ const DEFAULT_OBJECT_ACL = Object.freeze({ const XATTR_SORT_SYMBOL = Symbol('XATTR_SORT_SYMBOL'); const base64_regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/; +const X_NOOBAA_AVAILABLE_STORAGE_CLASSES = 'x-noobaa-available-storage-classes'; + function decode_chunked_upload(source_stream) { const decoder = new ChunkedContentDecoder(); // pipeline will back-propagate errors from the decoder to stop streaming from the source, @@ -283,6 +285,14 @@ function set_response_object_md(res, object_md) { } } +/** + * @param {nb.S3Response} res + * @param {Array} [supported_storage_classes] + */ +function set_response_supported_storage_classes(res, supported_storage_classes = []) { + res.setHeader(X_NOOBAA_AVAILABLE_STORAGE_CLASSES, supported_storage_classes); +} + /** * @param {nb.S3Request} req * @returns {nb.StorageClass} @@ -694,3 +704,4 @@ exports.get_response_field_encoder = get_response_field_encoder; exports.parse_decimal_int = parse_decimal_int; exports.parse_restore_request_days = parse_restore_request_days; exports.parse_version_id = parse_version_id; +exports.set_response_supported_storage_classes = set_response_supported_storage_classes; diff --git a/src/sdk/bucketspace_fs.js b/src/sdk/bucketspace_fs.js index e59ba3fd13..279ebd0d16 100644 --- a/src/sdk/bucketspace_fs.js +++ b/src/sdk/bucketspace_fs.js @@ -22,6 +22,7 @@ const { CONFIG_SUBDIRS } = require('../manage_nsfs/manage_nsfs_constants'); const KeysSemaphore = require('../util/keys_semaphore'); const native_fs_utils = require('../util/native_fs_utils'); const NoobaaEvent = require('../manage_nsfs/manage_nsfs_events_utils').NoobaaEvent; +const s3_utils = require('../endpoint/s3/s3_utils'); const dbg = require('../util/debug_module')(__filename); const bucket_semaphore = new KeysSemaphore(1); @@ -158,6 +159,7 @@ class BucketSpaceFS extends BucketSpaceSimpleFS { id: bucket.owner_account, email: bucket.bucket_owner }; + bucket.supported_storage_classes = this._supported_storage_class(); if (bucket.s3_policy) { for (const [s_index, statement] of bucket.s3_policy.Statement.entries()) { const statement_principal = statement.Principal || statement.NotPrincipal; @@ -710,6 +712,22 @@ class BucketSpaceFS extends BucketSpaceSimpleFS { throw err; } } + + /** + * returns a list of storage class supported by this bucketspace + * @returns {Array} + */ + _supported_storage_class() { + const storage_classes = []; + if (!config.DENY_UPLOAD_TO_STORAGE_CLASS_STANDARD) { + storage_classes.push(s3_utils.STORAGE_CLASS_STANDARD); + } + if (config.NSFS_GLACIER_ENABLED) { + storage_classes.push(s3_utils.STORAGE_CLASS_GLACIER); + } + + return storage_classes; + } } module.exports = BucketSpaceFS;