host/AzureRecoveryLib/resthelper/CloudBlob.cpp (651 lines of code) (raw):
/*
+-------------------------------------------------------------------------------------------------+
Copyrigth(c) Microsoft Corp.
+-------------------------------------------------------------------------------------------------+
File : CloudPageBlob.cpp
Description : CloudPageBlob class member inmplementations.
History : 29-4-2015 (Venu Sivanadham) - Created
+-------------------------------------------------------------------------------------------------+
*/
#include "CloudBlob.h"
#include "../common/Trace.h"
#include "../common/AzureRecoveryException.h"
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
#include <boost/exception/all.hpp>
#include <boost/assert.hpp>
namespace AzureStorageRest {
/*
Method : CloudPageBlob::CloudPageBlob
Description : CloudPageBlob constructor
Parameters :
[in] blobSas: Azure page blob's SAS
[in] enableSSLAuthentication : flag to check if SSL authentication be verified
Return Code : None
*/
CloudPageBlob::CloudPageBlob(const std::string& blobSas,
bool enableSSLAuthentication)
:m_blob_sas(blobSas),
m_azure_http_client(new HttpClient(enableSSLAuthentication)),
m_timeout(0),
m_last_error(0),
m_http_status_code(0)
{
}
/*
Method : CloudPageBlob::CloudPageBlob
Description : CloudPageBlob constructor
Parameters :
[in] blobSas: Azure page blob's SAS
[in] ptrHttpClient : a shared_ptr to the HttpClient that should be used
[in] enableSSLAuthentication : flag to check if SSL authentication be verified
Return Code : None
*/
CloudPageBlob::CloudPageBlob(const std::string& blobSas,
boost::shared_ptr<HttpClient> ptrHttpClient,
bool enableSSLAuthentication)
:m_blob_sas(blobSas),
m_azure_http_client(ptrHttpClient),
m_timeout(0),
m_http_status_code(0)
{
assert(NULL != ptrHttpClient);
}
/*
Method : CloudPageBlob::~CloudPageBlob
Description : CloudPageBlob descrtuctor
Parameters : None
Return Code : None
*/
CloudPageBlob::~CloudPageBlob()
{
}
/*
Method : CloudPageBlob::ReadBlobPropertiesFromResponse
Description : Reads the http headers in HttpResponse object and fills the corresponding
members in blob_properites structure.
Parameters : [in] response: HttpResponse object which contains the Azure REST API Response headers.
[out] properties: blob_properties structure which will be filled with property values
recieved in REST API response.
Return Code: None
*/
void CloudPageBlob::ReadBlobPropertiesFromResponse(
const HttpResponse& response,
blob_properties& properties
)
{
TRACE_FUNC_BEGIN;
// Property: Size
try
{
properties.size = boost::lexical_cast<blob_size_t>(
response.GetHeaderValue(RestHeader::Content_Length)
);
}
catch (...)
{
TRACE_WARNING("%s: Content-Length property not found in response."
" Could not determine blob size\n", FUNCTION_NAME);
properties.size = 0;
}
// Property: Blob type
properties.type =
boost::iequals("PageBlob", response.GetHeaderValue(RestHeader::X_MS_BlobType)) ?
AZURE_PAGE_BLOB : AZURE_BLOCK_BLOB;
// Property: Lease Status
properties.lease_status = response.GetHeaderValue(RestHeader::X_MS_Lease_Status);
// Property: Lease State
properties.lease_state = response.GetHeaderValue(RestHeader::X_MS_Lease_State);
// Property: Last Modified
properties.last_modified = response.GetHeaderValue(RestHeader::Last_Modified);
// Property: ETag
properties.etag = response.GetHeaderValue(RestHeader::Etag);
// Fill metadata
ReadMetadataFromResponse(response, properties.metadata);
TRACE_FUNC_END;
}
/*
Method : CloudPageBlob::ReadMetadataFromResponse
Description : Reads the headers recieved in Azure blob REST API call and filters th metadata headers.
Translates the metadata headers into metadata property-value pairs and adds them into
metadata statucutre.
Parameters : [int] response: HttpResponse object which contains the Azure REST API Response headers.
[out] metadata: Filled with metadata property-value prais.
Return Code : None
*/
void CloudPageBlob::ReadMetadataFromResponse(const HttpResponse& response, metadata_t& metadata)
{
TRACE_FUNC_BEGIN;
header_const_iter_t iterHBegin = response.BeginHeaders(),
iterHEnd = response.EndHeaders();
for (; iterHBegin != iterHEnd; iterHBegin++)
{
if (boost::find_first(iterHBegin->first, RestHeader::X_MS_Meta_Prefix))
{
std::string key = iterHBegin->first;
std::string value = iterHBegin->second;
boost::erase_first(key, RestHeader::X_MS_Meta_Prefix);
boost::trim(key);
boost::trim(value);
if (!key.empty()) metadata[key] = value;
}
}
TRACE_FUNC_END;
}
/*
Method : CloudPageBlob::AddMetadataHeadersToRequest
Description : Translates the metata property-value pairs into Azure REST API request header format
and inserts them into HttpRequest object.
Parameters : [out] request: Filled with metadata headers as per the metadata property-value pairs
available in metadata object.
[in] metadata: Contains metadata property-value pairs to be added to HttpRequest object.
Return Code : None
*/
void CloudPageBlob::AddMetadataHeadersToRequest(HttpRequest& request, const metadata_t& metadata)
{
TRACE_FUNC_BEGIN;
metadata_const_iter_t iterBegin = metadata.begin(),
iterEnd = metadata.end();
for (; iterBegin != iterEnd; iterBegin++)
{
std::string key = iterBegin->first;
std::string value = iterBegin->second;
boost::trim(key);
boost::trim(value);
if (!key.empty() && !value.empty())
{
key = RestHeader::X_MS_Meta_Prefix + key;
request.AddHeader(key, value);
}
else
{
TRACE_WARNING("%s: Empty metadata key (or) values found. Hence ignoring [%s] -> [%s]\n",
FUNCTION_NAME, iterBegin->first.c_str(), iterBegin->second.c_str());
}
}
TRACE_FUNC_END;
}
/*
Method : CloudPageBlob::UploadFile
Description : Reads the file contents and uploads it to the page blob. Every time maximum of
64KB will be read from local file and the blob write happens at same file offset.
Parameters : [in] hFile : Valid local file handle.
[in] blob_size: size of the azure blob
Return Code : Return true on success, otherwise false.
The error details will be logged based on the logging level enabled.
Note: blob_size should be greater than or equal to file size.
*/
bool CloudPageBlob::UploadFile(ACE_HANDLE hFile, const blob_size_t blob_size)
{
TRACE_FUNC_BEGIN;
bool bRet = true;
BOOST_ASSERT(ACE_INVALID_HANDLE != hFile);
BOOST_ASSERT((blob_size%Blob::BlobPageSize) == 0);
blob_size_t fpPos = 0;
ssize_t nRet = 0;
do
{
//Buffer size should be multiples of blob-page size(512)
blob_byte_t put_page_buff[64 * 1024] = { 0 };
size_t bytes_read = 0, bytes_to_write = 0;
nRet = ACE_OS::read_n(hFile, put_page_buff, sizeof(put_page_buff), &bytes_read);
BOOST_ASSERT(bytes_read <= sizeof(put_page_buff));
// nRet : -1 => rean_n() error
// 0 => EOF on or before filling complete buffer
// +n => buffer is filled completely but EOF is not reached yet.
if (-1 == nRet)
{
TRACE_ERROR("%s: File read failed with error %d\n", FUNCTION_NAME, ACE_OS::last_error());
bRet = false;
break;
}
bytes_to_write = (0 == nRet) ? HttpRestUtil::RoundToProperBlobSize(bytes_read) : bytes_read;
BOOST_ASSERT(bytes_to_write <= sizeof(put_page_buff));
if (Write(fpPos, put_page_buff, bytes_to_write))
{
fpPos += bytes_to_write;
}
else
{
TRACE_ERROR("%s: Failed to write data to the blob\n", FUNCTION_NAME);
bRet = false;
break;
}
} while ((blob_size > fpPos) && (nRet > 0));
TRACE_FUNC_END;
return bRet;
}
/*
Method : CloudPageBlob::GetProperties
Description : Makes the Get Properties Azure REST call to the blob and fills the recieved property
data into blob_properties structure.
Parameters : [out] properties: Filled with blob properties on success.
Return Code : Returns true on success, otherwize false.
The error details will be logged based on the logging level enabled.
*/
bool CloudPageBlob::GetProperties(blob_properties& properties)
{
TRACE_FUNC_BEGIN;
bool bRet = true;
BOOST_ASSERT(!m_blob_sas.empty());
try
{
HttpRequest request(m_blob_sas);
request.AddHeader(RestHeader::X_MS_Version, HttpRestUtil::Get_X_MS_Version());
request.SetHttpMethod(AzureStorageRest::HTTP_HEAD);
HttpResponse response;
if (!m_azure_http_client->GetResponse(request, response))
{
m_last_error = response.GetErrorCode();
TRACE_ERROR("%s: Could not initiate get-blob-properties rest operation, error code %lu.\n",
FUNCTION_NAME, m_last_error);
bRet = false;
}
else if (response.GetResponseCode() != HttpErrorCode::OK)
{
bRet = false;
TRACE_ERROR("%s: Error: get-blob-properties rest api failed, http status code %lu.\n",
FUNCTION_NAME, response.GetResponseCode());
m_last_error = response.GetResponseCode();
// Response body will have more meaningful message about failure.
response.PrintHttpErrorMsg();
}
else
{
ReadBlobPropertiesFromResponse(response, properties);
}
m_http_status_code = response.GetResponseCode();
}
catch (const std::exception& e)
{
TRACE_ERROR("%s: Exception: %s\n", FUNCTION_NAME, e.what());
bRet = false;
}
catch (...)
{
TRACE_ERROR("%s: Unknown Exception\n", FUNCTION_NAME);
bRet = false;
}
TRACE_FUNC_END;
return bRet;
}
/*
Method : CloudPageBlob::GetProperties
Description : Makes the Get Metadata Azure REST call to the blob and fills the recieved metadata
into blob_properties structure.
Parameters : [out] metadata: Filled with blob metadata on success.
Return Code : Returns true on success, otherwize false.
The error details will be logged based on the logging level enabled.
*/
bool CloudPageBlob::GetMetadata(metadata_t& metadata)
{
TRACE_FUNC_BEGIN;
bool bRet = true;
BOOST_ASSERT(!m_blob_sas.empty());
try
{
Uri blobMetadaUri(m_blob_sas);
//Set metadata query parameter comp=metadata
blobMetadaUri.AddQueryParam(Blob::QueryParamComp, Blob::QueryValueMetadata);
HttpRequest request(blobMetadaUri.ToString());
request.AddHeader(RestHeader::X_MS_Version, HttpRestUtil::Get_X_MS_Version());
request.SetHttpMethod(AzureStorageRest::HTTP_HEAD);
HttpResponse response;
if (!m_azure_http_client->GetResponse(request, response))
{
bRet = false;
m_last_error = response.GetErrorCode();
TRACE_ERROR("%s: Could not initiate get-blob-metadata rest operation, error code %lu.\n",
FUNCTION_NAME, m_last_error);
}
else if (response.GetResponseCode() != HttpErrorCode::OK)
{
bRet = false;
TRACE_ERROR("%s: Error: get-blob-metadata rest api failed, http status code %lu.\n",
FUNCTION_NAME, response.GetResponseCode());
m_last_error = response.GetResponseCode();
// Response body will have more meaningful message about failure.
response.PrintHttpErrorMsg();
}
else
{
ReadMetadataFromResponse(response, metadata);
}
m_http_status_code = response.GetResponseCode();
}
catch (const std::exception& e)
{
TRACE_ERROR("%s: Exception: %s\n", FUNCTION_NAME, e.what());
bRet = false;
}
catch (...)
{
TRACE_ERROR("%s: Unknown Exception\n", FUNCTION_NAME);
bRet = false;
}
TRACE_FUNC_END;
return bRet;
}
/*
Method : CloudPageBlob::SetMetadata
Description : Sets or updates the metadata of the azure blob on success.
Parameters : [in] metadata: Contains the blob metadata pairs which are to be updated for the blob.
Return Code : true on successful updatete, otherwise false.
The error details will be logged based on the logging level enabled.
*/
bool CloudPageBlob::SetMetadata(const metadata_t& metadata)
{
TRACE_FUNC_BEGIN;
bool bRet = true;
BOOST_ASSERT(!m_blob_sas.empty());
try
{
Uri blobMetadaUri(m_blob_sas);
//Set metadata query parameter comp=metadata
blobMetadaUri.AddQueryParam(Blob::QueryParamComp, Blob::QueryValueMetadata);
HttpRequest request(blobMetadaUri.ToString());
if (m_timeout)
request.SetTimeout(m_timeout);
request.AddHeader(RestHeader::X_MS_Version, HttpRestUtil::Get_X_MS_Version());
AddMetadataHeadersToRequest(request, metadata);
request.SetHttpMethod(AzureStorageRest::HTTP_PUT);
HttpResponse response;
if (!m_azure_http_client->GetResponse(request, response))
{
bRet = false;
m_last_error = response.GetErrorCode();
TRACE_ERROR("%s: Could not initiate set-blob-metadata rest operation, error code %lu.\n",
FUNCTION_NAME, m_last_error);
}
else if (response.GetResponseCode() != HttpErrorCode::OK)
{
bRet = false;
TRACE_ERROR("%s: Error: set-blob-metadata rest api failed, http status code %lu.\n",
FUNCTION_NAME, response.GetResponseCode());
m_last_error = response.GetResponseCode();
// Response body will have more meaningful message about failure.
response.PrintHttpErrorMsg();
}
m_http_status_code = response.GetResponseCode();
}
catch (const std::exception& e)
{
TRACE_ERROR("%s: Exception: %s\n", FUNCTION_NAME, e.what());
bRet = false;
}
catch (...)
{
TRACE_ERROR("%s: Unknown Exception\n", FUNCTION_NAME);
bRet = false;
}
TRACE_FUNC_END;
return bRet;
}
/*
Method : CloudPageBlob::Resize
Description : Resizes the azure page blob to the specified size on success. The new size should be
multiples of 512bytes.
Parameters : [in] new_size: The new size to which the blob going to resize on success.
Return Code : true on successful updatete, otherwise false.
The error details will be logged based on the logging level enabled.
*/
bool CloudPageBlob::Resize(const blob_size_t new_size)
{
TRACE_FUNC_BEGIN;
bool bRet = true;
BOOST_ASSERT(new_size%Blob::BlobPageSize == 0);
BOOST_ASSERT(!m_blob_sas.empty());
try
{
metadata_t metadata;
if (!GetMetadata(metadata))
{
TRACE_ERROR("%s: Failed to get blob metadata. Could not resize the blog.", FUNCTION_NAME);
THROW_REST_EXCEPTION("Get Metadata error");
}
HttpRequest request(m_blob_sas);
request.AddHeader(RestHeader::X_MS_Version, HttpRestUtil::Get_X_MS_Version());
request.AddHeader(RestHeader::X_MS_BlobType, Blob::PageBlob);
request.AddHeader(RestHeader::Content_Length, boost::lexical_cast<std::string>(0));
request.AddHeader(RestHeader::X_MS_Content_Length, boost::lexical_cast<std::string>(new_size));
AddMetadataHeadersToRequest(request, metadata);
request.SetHttpMethod(AzureStorageRest::HTTP_PUT);
HttpResponse response;
if (!m_azure_http_client->GetResponse(request, response))
{
bRet = false;
m_last_error = response.GetErrorCode();
TRACE_ERROR("%s: Could not initiate put-blob rest operation, error code %lu.\n",
FUNCTION_NAME, m_last_error);
}
else if (response.GetResponseCode() != HttpErrorCode::CREATED)
{
bRet = false;
TRACE_ERROR("%s: Error: put-blob rest api failed, http status code %lu.\n",
FUNCTION_NAME, response.GetResponseCode());
m_last_error = response.GetResponseCode();
// Response body will have more meaningful message about failure.
response.PrintHttpErrorMsg();
}
m_http_status_code = response.GetResponseCode();
}
catch (const std::exception& e)
{
TRACE_ERROR("%s: Exception: %s\n", FUNCTION_NAME, e.what());
bRet = false;
}
catch (...)
{
TRACE_ERROR("%s: Unknown Exception\n", FUNCTION_NAME);
bRet = false;
}
TRACE_FUNC_END;
return bRet;
}
/*
Method : CloudPageBlob::UploadFileContent
Description : Opens the specified local file and uploads its content to the page blob. Before starting
the data upload the azure blob will be resized to match the local file size. As the azure
page blob size should be multiples of 512bytes the rounded size will be chooses if local
file size is not the multiple of 512bytes.
Parameters : [in] local_file : Valid local file path.
Return Code : Return true on success, otherwise false.
The error details will be logged based on the logging level enabled.
*/
bool CloudPageBlob::UploadFileContent(const std::string& local_file)
{
TRACE_FUNC_BEGIN;
bool bRet = true;
BOOST_ASSERT(!local_file.empty());
ACE_HANDLE hFile = ACE_INVALID_HANDLE;
do
{
try
{
//Verify file path
boost::filesystem::path file_path(local_file);
if (!boost::filesystem::exists(file_path) || !boost::filesystem::is_regular_file(file_path))
{
TRACE_ERROR("%s: File %s does not exist or it is not a regular file.\n", FUNCTION_NAME, local_file.c_str());
bRet = false;
break;
}
blob_size_t new_blob_size = boost::filesystem::file_size(file_path);
if (0 == new_blob_size)
{
TRACE_ERROR("%s: Warning: s% file size is 0. Skipping file upload\n", FUNCTION_NAME, local_file.c_str());
break;
}
//Round the size to proper Page blob size.
new_blob_size = HttpRestUtil::RoundToProperBlobSize(new_blob_size);
//Resize the blob to match with local_file size.
bRet = Resize(new_blob_size);
if (!bRet)
{
TRACE_ERROR("%s: Blob resize failed.\n", FUNCTION_NAME);
break;
}
hFile = ACE_OS::open(local_file.c_str(), O_RDONLY, ACE_DEFAULT_OPEN_PERMS);
if (ACE_INVALID_HANDLE == hFile)
{
TRACE_ERROR("%s: Could not open file %s. Open failed with error %d\n", FUNCTION_NAME, ACE_OS::last_error());
bRet = false;
break;
}
bRet = UploadFile(hFile, new_blob_size);
}
catch (const std::exception& e)
{
TRACE_ERROR("%s: Exception: %s\n", FUNCTION_NAME, e.what());
bRet = false;
}
catch (...)
{
TRACE_ERROR("%s: Unknown Exception\n", FUNCTION_NAME);
bRet = false;
}
} while (false);
if (hFile != ACE_INVALID_HANDLE)
{
ACE_OS::close(hFile);
hFile = ACE_INVALID_HANDLE;
}
TRACE_FUNC_END;
return bRet;
}
/*
Method : CloudPageBlob::Read
Description : Reads the N bytes from page blob starting at specified offset on success.
Parameters : [in] start_offset : offset in the blob where the data to be read.
[out] out_buffer : The read data will be filled to this buffer.
Caller should allocate this buffer before the call.
[in] length: number of bytes to read from start_offset. The out_buff
should be greater than or equal to the length.
Return Code : size of bytes read from the blob on success, otherwise 0.
*/
blob_size_t CloudPageBlob::Read(offset_t start_offset, blob_byte_t *out_buff, blob_size_t length)
{
TRACE_FUNC_BEGIN;
blob_properties properties;
TRACE_FUNC_END;
return Read(start_offset, out_buff, length, properties);
}
/*
Method : CloudPageBlob::Read
Description : Reads the N bytes from page blob starting at specified offset on success.
Parameters : [in] start_offset : offset in the blob where the data to be read.
[out] out_buffer : The read data will be filled to this buffer.
Caller should allocate this buffer before the call.
[in] length : number of bytes to read from start_offset.The out_buff
should be greater than or equal to the length.
[out] properties: returns the blob proerties and meta-data on success
Return Code : size of bytes read from the blob on success, otherwise 0.
*/
blob_size_t CloudPageBlob::Read(offset_t start_offset, blob_byte_t *out_buff, blob_size_t length, blob_properties &properties)
{
TRACE_FUNC_BEGIN;
blob_size_t bytes_transfered = 0;
BOOST_ASSERT(!m_blob_sas.empty());
try
{
HttpRequest request(m_blob_sas);
// Set Headers {x-ms-version, x-ms-range}
request.AddHeader(RestHeader::X_MS_Version, HttpRestUtil::Get_X_MS_Version());
request.AddHeader(RestHeader::X_MS_Range, HttpRestUtil::Get_X_MS_Range(start_offset, length));
// Set Http Method
request.SetHttpMethod(AzureStorageRest::HTTP_GET);
HttpResponse response;
if (!m_azure_http_client->GetResponse(request, response))
{
m_last_error = response.GetErrorCode();
TRACE_ERROR("%s: Could not initiate get-blob rest operation, error code %lu.\n",
FUNCTION_NAME, m_last_error);
}
else if (response.GetResponseCode() != HttpErrorCode::PARTIAL_CONTENT &&
response.GetResponseCode() != HttpErrorCode::OK)
{
TRACE_ERROR("%s: Error: get-blob rest api failed, http status code %lu.\n",
FUNCTION_NAME, response.GetResponseCode());
m_last_error = response.GetResponseCode();
// Response body will have more meaningful message about failure.
response.PrintHttpErrorMsg();
}
else
{
ReadBlobPropertiesFromResponse(response, properties);
bytes_transfered = response.GetResponseData().length() * sizeof(char);
if (bytes_transfered <= length)
{
inm_memcpy_s(out_buff, length, response.GetResponseData().c_str(), (size_t)bytes_transfered);
TRACE_INFO("%s: received %llu bytes of data with response code %lu\n",
FUNCTION_NAME, bytes_transfered, response.GetResponseCode());
}
else
{
TRACE_ERROR("%s: received %llu bytes of data with response code %lu\n",
FUNCTION_NAME, bytes_transfered, response.GetResponseCode());
}
}
m_http_status_code = response.GetResponseCode();
}
catch (const std::exception& e)
{
TRACE_ERROR("%s: Exception: %s\n", FUNCTION_NAME, e.what());
bytes_transfered = 0;
}
catch (...)
{
TRACE_ERROR("%s: Unknown Exception\n", FUNCTION_NAME);
bytes_transfered = 0;
}
TRACE_FUNC_END;
return bytes_transfered;
}
/*
Method : CloudPageBlob::List
Description : Returns a list of blobs with matching prefix on success.
Parameters : [in] prefix : A filter on result to return blob names only begining with.
[in] maxResults: Specifies the maximum number of blobs in result.
[out] listOutput : Serialized XML response string containing result of matching blob names.
Return Code : true on success, otherwise false.
*/
bool CloudPageBlob::List(const std::string& prefix, const uint32_t maxResults, std::string &listOutput)
{
TRACE_FUNC_BEGIN;
bool bRet = true;
BOOST_ASSERT(!m_blob_sas.empty());
try
{
Uri blobMetadaUri(m_blob_sas);
blobMetadaUri.AddQueryParam(Blob::QueryParamRestype, Blob::QueryValueContainer);
blobMetadaUri.AddQueryParam(Blob::QueryParamComp, Blob::QueryValueList);
blobMetadaUri.AddQueryParam(Blob::QueryParamPrefix, prefix);
blobMetadaUri.AddQueryParam(Blob::QueryParamInclude, Blob::QueryValueMetadata);
blobMetadaUri.AddQueryParam(Blob::QueryParamMaxresults, boost::lexical_cast<std::string>(maxResults));
HttpRequest request(blobMetadaUri.ToString());
// Set Headers {x-ms-version, x-ms-range}
request.AddHeader(RestHeader::X_MS_Version, HttpRestUtil::Get_X_MS_Version());
// Set Http Method
request.SetHttpMethod(AzureStorageRest::HTTP_GET);
HttpResponse response;
if (!m_azure_http_client->GetResponse(request, response))
{
bRet = false;
m_last_error = response.GetErrorCode();
TRACE_ERROR("%s: Could not initiate get-blob-metadata rest operation, error code %lu.\n",
FUNCTION_NAME, m_last_error);
}
else if (response.GetResponseCode() != HttpErrorCode::OK)
{
bRet = false;
TRACE_ERROR("%s: Error: get-blob-metadata rest api failed, http status code %lu.\n",
FUNCTION_NAME, response.GetResponseCode());
m_last_error = response.GetResponseCode();
// Response body will have more meaningful message about failure.
response.PrintHttpErrorMsg();
}
else
{
listOutput = response.GetResponseData();
}
m_http_status_code = response.GetResponseCode();
}
catch (const std::exception& e)
{
bRet = false;
TRACE_ERROR("%s: Exception: %s\n", FUNCTION_NAME, e.what());
}
catch (...)
{
bRet = false;
TRACE_ERROR("%s: Unknown Exception\n", FUNCTION_NAME);
}
TRACE_FUNC_END;
return bRet;
}
/*
Method : CloudPageBlob::Delete
Description : Delets page blob on success.
Parameters : None
Return Code : true on success, otherwise false.
*/
bool CloudPageBlob::Delete()
{
TRACE_FUNC_BEGIN;
bool bRet = true;
BOOST_ASSERT(!m_blob_sas.empty());
try
{
Uri blobMetadaUri(m_blob_sas);
HttpRequest request(blobMetadaUri.ToString());
request.AddHeader(RestHeader::X_MS_Version, HttpRestUtil::Get_X_MS_Version());
request.SetHttpMethod(AzureStorageRest::HTTP_DELETE);
HttpResponse response;
if (!m_azure_http_client->GetResponse(request, response))
{
bRet = false;
m_last_error = response.GetErrorCode();
TRACE_ERROR("%s: Could not initiate delete-blob rest operation, error code %lu.\n",
FUNCTION_NAME, m_last_error);
}
else if (response.GetResponseCode() != HttpErrorCode::ACCEPTED)
{
bRet = false;
TRACE_ERROR("%s: Error: delete-blob rest api failed, http status code %lu.\n",
FUNCTION_NAME, response.GetResponseCode());
m_last_error = response.GetResponseCode();
// Response body will have more meaningful message about failure.
response.PrintHttpErrorMsg();
}
m_http_status_code = response.GetResponseCode();
}
catch (const std::exception& e)
{
TRACE_ERROR("%s: Exception: %s\n", FUNCTION_NAME, e.what());
bRet = false;
}
catch (...)
{
TRACE_ERROR("%s: Unknown Exception\n", FUNCTION_NAME);
bRet = false;
}
TRACE_FUNC_END;
return bRet;
}
/*
Method : CloudPageBlob::Write
Description : Writes N bytes of data to the blob at the specifi
TRACE_ERROR("Boost Exception: %s\n", boost::diagnostic_infored offset.
Parameters : [in] start_offset : offset in the blob where the data has to write.
[out] out_buffer : The data to be written to the blob.
[in] length : size of the buffer.
Return Code : positive number on success, otherwise 0.
*/
blob_size_t CloudPageBlob::Write(offset_t start_offset, blob_byte_t *out_buff, blob_size_t length)
{
TRACE_FUNC_BEGIN;
blob_size_t bytes_transfered = length;
BOOST_ASSERT(!m_blob_sas.empty());
try
{
Uri blobMetadaUri(m_blob_sas);
// Put page query parameter comp=page
blobMetadaUri.AddQueryParam(Blob::QueryParamComp, Blob::QueryValuePage);
// Set Headers { x-ms-version, x-ms-range, Content-Length, x-ms-page-write: update}
HttpRequest request(blobMetadaUri.ToString());
if (m_timeout)
request.SetTimeout(m_timeout);
request.AddHeader(RestHeader::X_MS_Version, HttpRestUtil::Get_X_MS_Version());
request.AddHeader(RestHeader::X_MS_Range, HttpRestUtil::Get_X_MS_Range(start_offset, length));
request.AddHeader(RestHeader::Content_Length, boost::lexical_cast<std::string>(length));
request.AddHeader(RestHeader::X_MS_Page_Write, Blob::PageWrite_Update);
// Set Http Method
request.SetHttpMethod(AzureStorageRest::HTTP_PUT);
// Set upload/write buffer stream
request.SetRequestBody(out_buff, length);
HttpResponse response;
if (!m_azure_http_client->GetResponse(request, response))
{
bytes_transfered = 0;
m_last_error = response.GetErrorCode();
TRACE_ERROR("%s: Could not initiate put-blob rest operation, error code %lu.\n",
FUNCTION_NAME, m_last_error);
}
else if (response.GetResponseCode() != HttpErrorCode::CREATED)
{
bytes_transfered = 0;
TRACE_ERROR("%s: Error: put-blob rest api failed, http status code %lu.\n",
FUNCTION_NAME, response.GetResponseCode());
m_last_error = response.GetResponseCode();
//Response body will have more meaningful message about failure.
response.PrintHttpErrorMsg();
}
m_http_status_code = response.GetResponseCode();
}
catch (const std::exception& e)
{
TRACE_ERROR("%s: Exception: %s\n", FUNCTION_NAME, e.what());
bytes_transfered = 0;
}
catch (...)
{
TRACE_ERROR("%s: Unknown Exception\n", FUNCTION_NAME);
bytes_transfered = 0;
}
TRACE_FUNC_END;
return bytes_transfered;
}
bool CloudPageBlob::Create(blob_size_t length)
{
TRACE_FUNC_BEGIN;
bool status = true;
BOOST_ASSERT(!m_blob_sas.empty());
try
{
Uri blobMetadaUri(m_blob_sas);
// Set Headers { x-ms-version, Content-Length, x-ms-blob-type: PageBlob}
HttpRequest request(blobMetadaUri.ToString());
if (m_timeout)
request.SetTimeout(m_timeout);
request.AddHeader(RestHeader::X_MS_Version, HttpRestUtil::Get_X_MS_Version());
request.AddHeader(RestHeader::X_MS_BlobType, Blob::PageBlob);
request.AddHeader(RestHeader::X_MS_Content_Length,
boost::lexical_cast<std::string>(length));
request.AddHeader(RestHeader::Content_Length, "0");
// Set Http Method
request.SetHttpMethod(AzureStorageRest::HTTP_PUT);
HttpResponse response;
if (!m_azure_http_client->GetResponse(request, response))
{
status = false;
m_last_error = response.GetErrorCode();
TRACE_ERROR("%s: Could not initiate put-blob rest operation, error code %lu.\n",
FUNCTION_NAME, m_last_error);
}
else if (response.GetResponseCode() != HttpErrorCode::CREATED)
{
status = false;
TRACE_ERROR("%s: Error: put-blob rest api failed, http status code %lu.\n",
FUNCTION_NAME, response.GetResponseCode());
m_last_error = response.GetResponseCode();
//Response body will have more meaningful message about failure.
response.PrintHttpErrorMsg();
}
m_http_status_code = response.GetResponseCode();
m_http_response_data = response.GetResponseData();
}
catch (const std::exception& e)
{
TRACE_ERROR("%s: Exception: %s\n", FUNCTION_NAME, e.what());
status = false;
}
catch (...)
{
TRACE_ERROR("%s: Unknown Exception\n", FUNCTION_NAME);
status = false;
}
TRACE_FUNC_END;
return status;
}
/*
Method : CloudPageBlob::SetHttpProxy
Description : configures the proxy settings to be used for accessing Azure blob
Parameters : [in] proxy : HttpProxy settings.
Return Code : none.
*/
void CloudPageBlob::SetHttpProxy(const HttpProxy& proxy)
{
m_azure_http_client->SetProxy(proxy);
return;
}
/*
Method : CloudPageBlob::SetTimeout
Description : configures the timeout to be used for read/write operations on Azure blob
Parameters : [in] timeout : timeout in seconds.
Return Code : none.
*/
void CloudPageBlob::SetTimeout(const uint32_t &timeout)
{
m_timeout = timeout;
}
} // ~AzureStorageRest namespace