diff --git a/BreakingChanges.txt b/BreakingChanges.txt
index df3eacf8..deea1886 100644
--- a/BreakingChanges.txt
+++ b/BreakingChanges.txt
@@ -1,6 +1,9 @@
Azure Storage Client Library for C++
History of Breaking Changes
+Breaking Changes in v0.4:
+- Upgraded Casablanca dependency to 2.3.0
+
Breaking changes in v0.3:
- Changed namespace to azure::storage.
- The SAS token returned by the get_shared_access_signature functions does not include a question mark (?) prefix.
diff --git a/Changelog.txt b/Changelog.txt
index 1eff958e..466082e0 100644
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,6 +1,22 @@
Azure Storage Client Library for C++
History of Changes
+Changes in v0.4:
+- Now supports building on Linux
+- Added http_buffer_size request option to control the internal buffer size used in the HTTP layer when downloading data. The default size is 64KB.
+- Blob downloads that are interrupted resume automatically from where the download left off when being retried.
+- Performance improvement when uploading and downloading blobs.
+- Added const version of the operation_context::user_headers() function.
+- Fixed incorrect initialization of some members in the cloud_blob_container_properties and retry_info classes.
+- Added a default of 24 days for a maximum execution time for an operation
+- Changed the exception type if you upload a blob from a seekable stream but the stream is too short for the desired blob length.
+ - Used to throw azure::storage::storage_exception in some cases, now throws std::invalid_argument always.
+ - Now checks for this case explicitly before the upload is started.
+ - Non-seekable streams still throw std::invalid_argument as before.
+- Fixed several bugs, including incorrect uses of std::move and compile-time differences between Visual Studio and g++.
+- Added client request ID into log lines.
+- Upgraded Casablanca dependency to 2.3.0
+
Changes in v0.3:
- Changed namespace to azure::storage.
- Added support for secondary location access in Azure Storage Emulator.
diff --git a/Microsoft.WindowsAzure.Storage.autopkg b/Microsoft.WindowsAzure.Storage.autopkg
index e4f4cf40..aba167d9 100644
--- a/Microsoft.WindowsAzure.Storage.autopkg
+++ b/Microsoft.WindowsAzure.Storage.autopkg
@@ -1,23 +1,23 @@
nuget {
nuspec {
id = wastorage;
- version: 0.3.0-preview;
+ version: 0.4.0-preview;
title: Microsoft Azure Storage Client Library for C++;
authors: {Microsoft Corporation};
owners: {Microsoft Corporation};
licenseUrl: "http://go.microsoft.com/fwlink/?LinkId=235170";
projectUrl: "http://go.microsoft.com/fwlink/?LinkId=235168";
iconUrl: "http://go.microsoft.com/fwlink/?LinkID=288890";
- summary: "A client library for working with Azure storage services including blobs, tables, and queues.";
- description: @"This client library enables working with the Azure storage services which include the blob service for storing binary and text data, the table service for storing structured non-relational data, and the queue service for storing messages that may be accessed by a client.
- Azure Storage team's blog - http://blogs.msdn.com/b/windowsazurestorage/";
+ summary: "A client library for working with Microsoft Azure storage services including blobs, tables, and queues.";
+ description: @"This client library enables working with the Microsoft Azure storage services which include the blob service for storing binary and text data, the table service for storing structured non-relational data, and the queue service for storing messages that may be accessed by a client.
+ Microsoft Azure Storage team's blog - http://blogs.msdn.com/b/windowsazurestorage/";
releaseNotes: "Preview release";
tags: { Microsoft, Azure, Storage, Table, Blob, Queue, Scalable, windowsazureofficial };
}
dependencies {
packages: {
- cpprestsdk/2.0.1
+ cpprestsdk/2.3.0
};
}
diff --git a/Microsoft.WindowsAzure.Storage/CMakeLists.txt b/Microsoft.WindowsAzure.Storage/CMakeLists.txt
new file mode 100644
index 00000000..00e03c93
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/CMakeLists.txt
@@ -0,0 +1,102 @@
+set(CMAKE_LEGACY_CYGWIN_WIN32 0)
+cmake_minimum_required(VERSION 2.6)
+project(azurestorage)
+
+enable_testing()
+
+set(WARNINGS)
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+
+# Platform (not compiler) specific settings
+if(IOS)
+ set(IOS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/../Build_iOS")
+ set(Boost_FRAMEWORK "-F ${IOS_SOURCE_DIR} -framework boost")
+ set(Boost_INCLUDE_DIR "${IOS_SOURCE_DIR}/boost.framework/Headers")
+
+ set(OPENSSL_FOUND 1)
+ set(OPENSSL_INCLUDE_DIR "${IOS_SOURCE_DIR}/openssl/include")
+ set(OPENSSL_LIBRARIES
+ "${IOS_SOURCE_DIR}/openssl/lib/libcrypto.a"
+ "${IOS_SOURCE_DIR}/openssl/lib/libssl.a"
+ )
+
+ set(CASABLANCA_INCLUDE_DIRS "${IOS_SOURCE_DIR}/casablanca/include")
+ set(CASABLANCA_LIBRARIES "${IOS_SOURCE_DIR}/casablanca/lib/libcasablanca.a")
+
+ # The cxx_flags must be set here, because the ios-cmake toolchain file unfortunately sets "-headerpad_max_install_names" which is not a valid clang flag.
+ set(CMAKE_CXX_FLAGS "-fvisibility=hidden -fvisibility-inlines-hidden")
+
+ set(BUILD_SHARED_LIBS OFF)
+elseif(UNIX) # This includes OSX
+ find_package(Boost REQUIRED COMPONENTS log log_setup random system thread locale regex filesystem)
+ find_package(Threads REQUIRED)
+ find_package(OpenSSL REQUIRED)
+ find_package(LibXML++ REQUIRED)
+ find_package(UUID REQUIRED)
+ find_package(Casablanca REQUIRED)
+
+ set(UNITTEST_LIBRARY "${CMAKE_SOURCE_DIR}/tests/UnitTest++/libUnitTest++.a")
+
+ option(BUILD_SHARED_LIBS "Build shared Libraries." ON)
+elseif(WIN32)
+ option(BUILD_SHARED_LIBS "Build shared Libraries." ON)
+
+ add_definitions(-DUNICODE)
+
+ if(NOT BUILD_SHARED_LIBS)
+ # This causes cmake to not link the test libraries separately, but instead hold onto their object files.
+ set(TEST_LIBRARY_TARGET_TYPE OBJECT)
+ endif()
+
+ set(LIB lib)
+else()
+ message("-- Unsupported Build Platform.")
+endif()
+
+# Compiler (not platform) specific settings
+if(("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR IOS)
+ message("-- Setting clang options")
+
+ set(WARNINGS "-Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls")
+ set(OSX_SUPPRESSIONS "-Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder")
+ set(WARNINGS "${WARNINGS} ${OSX_SUPPRESSIONS}")
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration")
+ set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
+ set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing")
+ set(STRICT_CXX_FLAGS ${WARNINGS} "-Werror -pedantic")
+elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
+ message("-- Setting gcc options")
+
+ set(WARNINGS "-Wall -Wextra -Wunused-parameter -Wcast-align -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wunreachable-code")
+ set(LINUX_SUPPRESSIONS "-Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-unused-function -Wno-char-subscripts -Wno-switch -Wno-unused-but-set-parameter -Wno-unused-value -Wno-unused-local-typedefs -Wno-unused-parameter")
+
+ set(WARNINGS "${WARNINGS} ${LINUX_SUPPRESSIONS}")
+ set(LD_FLAGS "${LD_FLAGS} -Wl,-z,defs")
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing")
+ set(STRICT_CXX_FLAGS ${WARNINGS} "-Werror -pedantic")
+ add_definitions(-DBOOST_LOG_DYN_LINK)
+else()
+ message("-- Unknown compiler, success is doubtful.")
+endif()
+
+# Reconfigure final output directory
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
+
+set(AZURESTORAGE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/includes)
+set(AZURESTORAGE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/includes ${CASABLANCA_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${LibXML++_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS})
+
+set(AZURESTORAGE_LIBRARY azurestorage)
+set(AZURESTORAGE_LIBRARY_TEST azurestoragetest)
+set(AZURESTORAGE_LIBRARIES ${AZURESTORAGE_LIBRARY} ${CASABLANCA_LIBRARIES} ${Boost_LIBRARIES} ${Boost_FRAMEWORK} ${OPENSSL_LIBRARIES} ${LibXML++_LIBRARIES} ${UUID_LIBRARIES})
+
+include_directories(${AZURESTORAGE_INCLUDE_DIRS})
+
+add_subdirectory(src)
+add_subdirectory(tests)
diff --git a/Microsoft.WindowsAzure.Storage/Makefile b/Microsoft.WindowsAzure.Storage/Makefile
new file mode 100644
index 00000000..da6a48a5
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/Makefile
@@ -0,0 +1,28 @@
+MODE = $(shell getconf LONG_BIT)
+
+debug:
+ mkdir -vp build.debug$(MODE)
+ cd build.debug$(MODE) && CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Debug && cmake --build .
+
+release:
+ mkdir -vp build.release$(MODE)
+ cd build.release$(MODE) && CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Release && cmake --build .
+
+clean:
+ @[ -e src ] # sanity check directory
+ @find . -iname *.so -exec rm '{}' \;
+ @find . -iname *.o -exec rm '{}' \;
+ @find . -iname *.d -exec rm '{}' \;
+ @find ../Binaries -iname *.so -exec rm '{}' \;
+ @find ../Binaries -iname *.txt -exec rm '{}' \;
+ @find ../Binaries -iname *.d -exec rm '{}' \;
+ @find ../Binaries -iname SearchFile -exec rm '{}' \;
+ @find ../Binaries -iname BingRequest -exec rm '{}' \;
+ @find ../Binaries -iname syncdir -exec rm '{}' \;
+ @find ../Binaries -iname test_runner -exec rm '{}' \;
+ @rm -rf build.debug* build.release*
+
+
+all: debug release
+
+.PHONY: all clean release debug
diff --git a/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.v120.vcxproj b/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.v120.vcxproj
index 764463ce..cccc279b 100644
--- a/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.v120.vcxproj
+++ b/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.v120.vcxproj
@@ -1,6 +1,7 @@
-
+
+
Debug
@@ -103,7 +104,7 @@
WASTORAGE_DLL;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
true
- /we4100 /Zm129 %(AdditionalOptions) /bigobj
+ /we4100 /Zm150 %(AdditionalOptions) /bigobj
true
includes
@@ -121,7 +122,7 @@
WASTORAGE_DLL;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
true
- /we4100 /Zm129 %(AdditionalOptions) /bigobj
+ /we4100 /Zm150 %(AdditionalOptions) /bigobj
true
includes
@@ -142,7 +143,7 @@
true
false
true
- /we4100 /Zm122 %(AdditionalOptions) /bigobj
+ /we4100 /Zm150 %(AdditionalOptions) /bigobj
true
includes
@@ -165,7 +166,7 @@
true
false
true
- /we4100 /Zm122 %(AdditionalOptions) /bigobj
+ /we4100 /Zm150 %(AdditionalOptions) /bigobj
true
includes
@@ -193,7 +194,7 @@
-
+
@@ -208,6 +209,7 @@
+
@@ -229,8 +231,8 @@
-
-
+
+
@@ -254,7 +256,6 @@
Create
Create
-
@@ -265,7 +266,11 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.v120.vcxproj.filters b/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.v120.vcxproj.filters
index 3cb439f5..aae6c14d 100644
--- a/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.v120.vcxproj.filters
+++ b/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.v120.vcxproj.filters
@@ -33,9 +33,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -69,9 +66,6 @@
Header Files
-
- Source Files
-
Header Files
@@ -102,6 +96,9 @@
Header Files
+
+ Header Files
+
@@ -164,9 +161,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -197,9 +191,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -215,9 +206,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -230,6 +218,18 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
diff --git a/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.vcxproj b/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.vcxproj
index f51c2fc9..1bb32482 100644
--- a/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.vcxproj
+++ b/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.vcxproj
@@ -1,6 +1,7 @@
-
+
+
Debug
@@ -103,7 +104,7 @@
WASTORAGE_DLL;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
true
- /we4100 /Zm129 %(AdditionalOptions) /bigobj
+ /we4100 /Zm150 %(AdditionalOptions) /bigobj
true
includes
@@ -121,7 +122,7 @@
WASTORAGE_DLL;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
true
- /we4100 /Zm129 %(AdditionalOptions) /bigobj
+ /we4100 /Zm150 %(AdditionalOptions) /bigobj
true
includes
@@ -142,7 +143,7 @@
true
false
true
- /we4100 /Zm122 %(AdditionalOptions) /bigobj
+ /we4100 /Zm150 %(AdditionalOptions) /bigobj
true
includes
@@ -165,7 +166,7 @@
true
false
true
- /we4100 /Zm122 %(AdditionalOptions) /bigobj
+ /we4100 /Zm150 %(AdditionalOptions) /bigobj
true
includes
@@ -193,7 +194,7 @@
-
+
@@ -221,6 +222,7 @@
+
@@ -229,8 +231,8 @@
-
-
+
+
@@ -254,7 +256,6 @@
Create
Create
-
@@ -265,7 +266,11 @@
+
+
+
+
+
-
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.vcxproj.filters b/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.vcxproj.filters
index 3cb439f5..aae6c14d 100644
--- a/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.vcxproj.filters
+++ b/Microsoft.WindowsAzure.Storage/Microsoft.WindowsAzure.Storage.vcxproj.filters
@@ -33,9 +33,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -69,9 +66,6 @@
Header Files
-
- Source Files
-
Header Files
@@ -102,6 +96,9 @@
Header Files
+
+ Header Files
+
@@ -164,9 +161,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -197,9 +191,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -215,9 +206,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -230,6 +218,18 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
diff --git a/Microsoft.WindowsAzure.Storage/cmake/Modules/FindCasablanca.cmake b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindCasablanca.cmake
new file mode 100644
index 00000000..f8090d74
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindCasablanca.cmake
@@ -0,0 +1,39 @@
+# FindCasablanca package
+#
+# Tries to find the Casablanca (C++ REST SDK) library
+#
+
+find_package(PkgConfig)
+
+include(LibFindMacros)
+
+# Include dir
+find_path(CASABLANCA_INCLUDE_DIR
+ NAMES cpprest/http_client.h
+ PATHS
+ ${CASABLANCA_PKGCONF_INCLUDE_DIRS}
+ ${CASABLANCA_DIR}
+ $ENV{CASABLANCA_DIR}
+ /usr/local/include
+ /usr/include
+ PATH_SUFFIXES Release/include include
+)
+
+# Library
+find_library(CASABLANCA_LIBRARY
+ NAMES libcpprest.so
+ PATHS
+ ${CASABLANCA_PKGCONF_LIBRARY_DIRS}
+ ${CASABLANCA_DIR}
+ ${CASABLANCA_DIR}/lib
+ $ENV{CASABLANCA_DIR}/lib
+ $ENV{CASABLANCA_DIR}
+ /usr/local/lib
+ /usr/lib
+ PATH_SUFFIXES Release/build.release/Binaries/ build.release/Binaries/
+)
+
+set(CASABLANCA_PROCESS_LIBS CASABLANCA_LIBRARY)
+set(CASABLANCA_PROCESS_INCLUDES CASABLANCA_INCLUDE_DIR)
+libfind_process(CASABLANCA)
+
diff --git a/Microsoft.WindowsAzure.Storage/cmake/Modules/FindGlib.cmake b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindGlib.cmake
new file mode 100644
index 00000000..708cdc72
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindGlib.cmake
@@ -0,0 +1,40 @@
+# - Try to find Glib-2.0 (with gobject)
+# Once done, this will define
+#
+# Glib_FOUND - system has Glib
+# Glib_INCLUDE_DIRS - the Glib include directories
+# Glib_LIBRARIES - link these to use Glib
+
+include(LibFindMacros)
+
+# Use pkg-config to get hints about paths
+libfind_pkg_check_modules(Glib_PKGCONF glib-2.0)
+
+# Main include dir
+find_path(Glib_INCLUDE_DIR
+ NAMES glib.h
+ PATHS ${Glib_PKGCONF_INCLUDE_DIRS}
+ PATH_SUFFIXES glib-2.0
+)
+
+# Glib-related libraries also use a separate config header, which is in lib dir
+find_path(GlibConfig_INCLUDE_DIR
+ NAMES glibconfig.h
+ PATHS ${Glib_PKGCONF_INCLUDE_DIRS} /usr
+ PATH_SUFFIXES lib/glib-2.0/include
+)
+
+# Finally the library itself
+find_library(Glib_LIBRARY
+ NAMES glib-2.0
+ PATHS ${Glib_PKGCONF_LIBRARY_DIRS}
+)
+
+# Set the include dir variables and the libraries and let libfind_process do the rest.
+# NOTE: Singular variables for this library, plural for libraries this this lib depends on.
+set(Glib_PROCESS_INCLUDES Glib_INCLUDE_DIR GlibConfig_INCLUDE_DIR)
+set(Glib_PROCESS_LIBS Glib_LIBRARY)
+libfind_process(Glib)
+
+
+
diff --git a/Microsoft.WindowsAzure.Storage/cmake/Modules/FindGlibmm.cmake b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindGlibmm.cmake
new file mode 100644
index 00000000..375b8cdd
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindGlibmm.cmake
@@ -0,0 +1,39 @@
+# - Try to find Glibmm-2.4
+# Once done, this will define
+#
+# Glibmm_FOUND - system has Glibmm
+# Glibmm_INCLUDE_DIRS - the Glibmm include directories
+# Glibmm_LIBRARIES - link these to use Glibmm
+
+include(LibFindMacros)
+
+# Dependencies
+libfind_package(Glibmm Glib)
+libfind_package(Glibmm SigC++)
+
+# Use pkg-config to get hints about paths
+libfind_pkg_check_modules(Glibmm_PKGCONF glibmm-2.4)
+
+# Main include dir
+find_path(Glibmm_INCLUDE_DIR
+ NAMES glibmm/main.h
+ PATHS ${Glibmm_PKGCONF_INCLUDE_DIRS}
+ PATH_SUFFIXES glibmm-2.4
+)
+
+# Glib-related libraries also use a separate config header, which is in lib dir
+find_path(GlibmmConfig_INCLUDE_DIR
+ NAMES glibmmconfig.h
+ PATHS ${Glibmm_PKGCONF_INCLUDE_DIRS} /usr
+ PATH_SUFFIXES lib/glibmm-2.4/include
+)
+
+libfind_library(Glibmm glibmm 2.4)
+
+# Set the include dir variables and the libraries and let libfind_process do the rest.
+# NOTE: Singular variables for this library, plural for libraries this this lib depends on.
+set(Glibmm_PROCESS_INCLUDES Glibmm_INCLUDE_DIR GlibmmConfig_INCLUDE_DIR Glib_INCLUDE_DIRS SigC++_INCLUDE_DIRS)
+set(Glibmm_PROCESS_LIBS Glibmm_LIBRARY Glib_LIBRARIES SigC++_LIBRARIES)
+libfind_process(Glibmm)
+
+
diff --git a/Microsoft.WindowsAzure.Storage/cmake/Modules/FindLibXML++.cmake b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindLibXML++.cmake
new file mode 100644
index 00000000..d50fb442
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindLibXML++.cmake
@@ -0,0 +1,39 @@
+# find libxml++
+#
+# exports:
+#
+# LibXML++_FOUND
+# LibXML++_INCLUDE_DIRS
+# LibXML++_LIBRARIES
+#
+
+include(FindPkgConfig)
+include(FindPackageHandleStandardArgs)
+
+# Use pkg-config to get hints about paths
+pkg_check_modules(LibXML++_PKGCONF REQUIRED libxml++-2.6)
+
+# Include dir
+find_path(LibXML++_INCLUDE_DIR
+ NAMES libxml++/libxml++.h
+ PATHS ${LibXML++_PKGCONF_INCLUDE_DIRS}
+)
+
+# Finally the library itself
+find_library(LibXML++_LIBRARY
+ NAMES xml++ xml++-2.6
+ PATHS ${LibXML++_PKGCONF_LIBRARY_DIRS}
+)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXML++ DEFAULT_MSG LibXML++_LIBRARY LibXML++_INCLUDE_DIR)
+
+
+if(LibXML++_PKGCONF_FOUND)
+ set(LibXML++_LIBRARIES ${LibXML++_LIBRARY} ${LibXML++_PKGCONF_LIBRARIES})
+ set(LibXML++_INCLUDE_DIRS ${LibXML++_INCLUDE_DIR} ${LibXML++_PKGCONF_INCLUDE_DIRS})
+ set(LibXML++_FOUND yes)
+else()
+ set(LibXML++_LIBRARIES)
+ set(LibXML++_INCLUDE_DIRS)
+ set(LibXML++_FOUND no)
+endif()
diff --git a/Microsoft.WindowsAzure.Storage/cmake/Modules/FindLibXML2.cmake b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindLibXML2.cmake
new file mode 100644
index 00000000..d1413be6
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindLibXML2.cmake
@@ -0,0 +1,44 @@
+# - Try to find LibXML2 headers and libraries.
+#
+# Usage of this module as follows:
+#
+# find_package(LibXML2)
+#
+# Variables used by this module, they can change the default behaviour and need
+# to be set before calling find_package:
+#
+# LibXML2_ROOT_DIR Set this variable to the root installation of
+# LibXML2 if the module has problems finding
+# the proper installation path.
+#
+# Variables defined by this module:
+#
+# LIBXML2_FOUND System has LibXML2 libs/headers
+# LibXML2_LIBRARIES The LibXML2 libraries
+# LibXML2_INCLUDE_DIR The location of LibXML2 headers
+
+find_path(LibXML2_ROOT_DIR
+ NAMES include/libxml2/libxml/tree.h
+)
+
+find_library(LibXML2_LIBRARIES
+ NAMES xml2
+ HINTS ${LibXML2_ROOT_DIR}/lib
+)
+
+find_path(LibXML2_INCLUDE_DIR
+ NAMES libxml/tree.h
+ HINTS ${LibXML2_ROOT_DIR}/include/libxml2
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LibXML2 DEFAULT_MSG
+ LibXML2_LIBRARIES
+ LibXML2_INCLUDE_DIR
+)
+
+mark_as_advanced(
+ LibXML2_ROOT_DIR
+ LibXML2_LIBRARIES
+ LibXML2_INCLUDE_DIR
+)
diff --git a/Microsoft.WindowsAzure.Storage/cmake/Modules/FindSigC++.cmake b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindSigC++.cmake
new file mode 100644
index 00000000..27745332
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindSigC++.cmake
@@ -0,0 +1,35 @@
+# - Try to find SigC++-2.0
+# Once done, this will define
+#
+# SigC++_FOUND - system has SigC++
+# SigC++_INCLUDE_DIRS - the SigC++ include directories
+# SigC++_LIBRARIES - link these to use SigC++
+
+include(LibFindMacros)
+
+# Use pkg-config to get hints about paths
+libfind_pkg_check_modules(SigC++_PKGCONF sigc++-2.0)
+
+# Main include dir
+find_path(SigC++_INCLUDE_DIR
+ NAMES sigc++/sigc++.h
+ PATHS ${SigC++_PKGCONF_INCLUDE_DIRS}
+ PATH_SUFFIXES sigc++-2.0
+)
+
+# Glib-related libraries also use a separate config header, which is in lib dir
+find_path(SigC++Config_INCLUDE_DIR
+ NAMES sigc++config.h
+ PATHS ${SigC++_PKGCONF_INCLUDE_DIRS} /usr
+ PATH_SUFFIXES lib/sigc++-2.0/include
+)
+
+libfind_library(SigC++ sigc 2.0)
+
+# Set the include dir variables and the libraries and let libfind_process do the rest.
+# NOTE: Singular variables for this library, plural for libraries this this lib depends on.
+set(SigC++_PROCESS_INCLUDES SigC++_INCLUDE_DIR SigC++Config_INCLUDE_DIR)
+set(SigC++_PROCESS_LIBS SigC++_LIBRARY)
+libfind_process(SigC++)
+
+
diff --git a/Microsoft.WindowsAzure.Storage/cmake/Modules/FindUUID.cmake b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindUUID.cmake
new file mode 100644
index 00000000..d64618a9
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/cmake/Modules/FindUUID.cmake
@@ -0,0 +1,113 @@
+# - Try to find UUID
+# Once done this will define
+#
+# UUID_FOUND - system has UUID
+# UUID_INCLUDE_DIRS - the UUID include directory
+# UUID_LIBRARIES - Link these to use UUID
+# UUID_DEFINITIONS - Compiler switches required for using UUID
+#
+# Copyright (c) 2006 Andreas Schneider
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+
+if (UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
+ # in cache already
+ set(UUID_FOUND TRUE)
+else (UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
+ find_path(UUID_INCLUDE_DIR
+ NAMES
+ uuid/uuid.h
+ PATHS
+ ${UUID_DIR}/include
+ $ENV{UUID_DIR}/include
+ $ENV{UUID_DIR}
+ ${DELTA3D_EXT_DIR}/inc
+ $ENV{DELTA_ROOT}/ext/inc
+ $ENV{DELTA_ROOT}
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local/include
+ /usr/include
+ /usr/include/gdal
+ /sw/include # Fink
+ /opt/local/include # DarwinPorts
+ /opt/csw/include # Blastwave
+ /opt/include
+ [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/include
+ /usr/freeware/include
+
+ )
+
+ find_library(UUID_LIBRARY
+ NAMES
+ uuid
+ PATHS
+ ${UUID_DIR}/lib
+ $ENV{UUID_DIR}/lib
+ $ENV{UUID_DIR}
+ ${DELTA3D_EXT_DIR}/lib
+ $ENV{DELTA_ROOT}/ext/lib
+ $ENV{DELTA_ROOT}
+ $ENV{OSG_ROOT}/lib
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local/lib
+ /usr/lib
+ /sw/lib
+ /opt/local/lib
+ /opt/csw/lib
+ /opt/lib
+ /usr/freeware/lib64
+ )
+
+ find_library(UUID_LIBRARY_DEBUG
+ NAMES
+ uuidd
+ PATHS
+ ${UUID_DIR}/lib
+ $ENV{UUID_DIR}/lib
+ $ENV{UUID_DIR}
+ ${DELTA3D_EXT_DIR}/lib
+ $ENV{DELTA_ROOT}/ext/lib
+ $ENV{DELTA_ROOT}
+ $ENV{OSG_ROOT}/lib
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local/lib
+ /usr/lib
+ /sw/lib
+ /opt/local/lib
+ /opt/csw/lib
+ /opt/lib
+ /usr/freeware/lib64
+ )
+
+ set(UUID_INCLUDE_DIRS
+ ${UUID_INCLUDE_DIR}
+ )
+ set(UUID_LIBRARIES
+ ${UUID_LIBRARY}
+)
+
+ if (UUID_INCLUDE_DIRS AND UUID_LIBRARIES)
+ set(UUID_FOUND TRUE)
+ endif (UUID_INCLUDE_DIRS AND UUID_LIBRARIES)
+
+ if (UUID_FOUND)
+ if (NOT UUID_FIND_QUIETLY)
+ message(STATUS "Found UUID: ${UUID_LIBRARIES}")
+ endif (NOT UUID_FIND_QUIETLY)
+ else (UUID_FOUND)
+ if (UUID_FIND_REQUIRED)
+ message(FATAL_ERROR "Could not find UUID")
+ endif (UUID_FIND_REQUIRED)
+ endif (UUID_FOUND)
+
+ # show the UUID_INCLUDE_DIRS and UUID_LIBRARIES variables only in the advanced view
+ mark_as_advanced(UUID_INCLUDE_DIRS UUID_LIBRARIES)
+
+endif (UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
diff --git a/Microsoft.WindowsAzure.Storage/cmake/Modules/LibFindMacros.cmake b/Microsoft.WindowsAzure.Storage/cmake/Modules/LibFindMacros.cmake
new file mode 100644
index 00000000..3ef5844d
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/cmake/Modules/LibFindMacros.cmake
@@ -0,0 +1,266 @@
+# Version 2.2
+# Public Domain, originally written by Lasse Kärkkäinen
+# Maintained at https://github.com/Tronic/cmake-modules
+# Please send your improvements as pull requests on Github.
+
+# Find another package and make it a dependency of the current package.
+# This also automatically forwards the "REQUIRED" argument.
+# Usage: libfind_package( [extra args to find_package])
+macro (libfind_package PREFIX PKG)
+ set(${PREFIX}_args ${PKG} ${ARGN})
+ if (${PREFIX}_FIND_REQUIRED)
+ set(${PREFIX}_args ${${PREFIX}_args} REQUIRED)
+ endif()
+ find_package(${${PREFIX}_args})
+ set(${PREFIX}_DEPENDENCIES ${${PREFIX}_DEPENDENCIES};${PKG})
+ unset(${PREFIX}_args)
+endmacro()
+
+# A simple wrapper to make pkg-config searches a bit easier.
+# Works the same as CMake's internal pkg_check_modules but is always quiet.
+macro (libfind_pkg_check_modules)
+ find_package(PkgConfig QUIET)
+ if (PKG_CONFIG_FOUND)
+ pkg_check_modules(${ARGN} QUIET)
+ endif()
+endmacro()
+
+# Avoid useless copy&pasta by doing what most simple libraries do anyway:
+# pkg-config, find headers, find library.
+# Usage: libfind_pkg_detect( FIND_PATH [other args] FIND_LIBRARY [other args])
+# E.g. libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h PATH_SUFFIXES SDL2 FIND_LIBRARY SDL2)
+function (libfind_pkg_detect PREFIX)
+ # Parse arguments
+ set(argname pkgargs)
+ foreach (i ${ARGN})
+ if ("${i}" STREQUAL "FIND_PATH")
+ set(argname pathargs)
+ elseif ("${i}" STREQUAL "FIND_LIBRARY")
+ set(argname libraryargs)
+ else()
+ set(${argname} ${${argname}} ${i})
+ endif()
+ endforeach()
+ if (NOT pkgargs)
+ message(FATAL_ERROR "libfind_pkg_detect requires at least a pkg_config package name to be passed.")
+ endif()
+ # Find library
+ libfind_pkg_check_modules(${PREFIX}_PKGCONF ${pkgargs})
+ if (pathargs)
+ find_path(${PREFIX}_INCLUDE_DIR NAMES ${pathargs} HINTS ${${PREFIX}_PKGCONF_INCLUDE_DIRS})
+ endif()
+ if (libraryargs)
+ find_library(${PREFIX}_LIBRARY NAMES ${libraryargs} HINTS ${${PREFIX}_PKGCONF_LIBRARY_DIRS})
+ endif()
+endfunction()
+
+# Extracts a version #define from a version.h file, output stored to _VERSION.
+# Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR)
+# Fourth argument "QUIET" may be used for silently testing different define names.
+# This function does nothing if the version variable is already defined.
+function (libfind_version_header PREFIX VERSION_H DEFINE_NAME)
+ # Skip processing if we already have a version or if the include dir was not found
+ if (${PREFIX}_VERSION OR NOT ${PREFIX}_INCLUDE_DIR)
+ return()
+ endif()
+ set(quiet ${${PREFIX}_FIND_QUIETLY})
+ # Process optional arguments
+ foreach(arg ${ARGN})
+ if (arg STREQUAL "QUIET")
+ set(quiet TRUE)
+ else()
+ message(AUTHOR_WARNING "Unknown argument ${arg} to libfind_version_header ignored.")
+ endif()
+ endforeach()
+ # Read the header and parse for version number
+ set(filename "${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+ if (NOT EXISTS ${filename})
+ if (NOT quiet)
+ message(AUTHOR_WARNING "Unable to find ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+ endif()
+ return()
+ endif()
+ file(READ "${filename}" header)
+ string(REGEX REPLACE ".*#[ \t]*define[ \t]*${DEFINE_NAME}[ \t]*\"([^\n]*)\".*" "\\1" match "${header}")
+ # No regex match?
+ if (match STREQUAL header)
+ if (NOT quiet)
+ message(AUTHOR_WARNING "Unable to find \#define ${DEFINE_NAME} \"\" from ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+ endif()
+ return()
+ endif()
+ # Export the version string
+ set(${PREFIX}_VERSION "${match}" PARENT_SCOPE)
+endfunction()
+
+# Do the final processing once the paths have been detected.
+# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
+# all the variables, each of which contain one include directory.
+# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
+# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
+# Also handles errors in case library detection was required, etc.
+function (libfind_process PREFIX)
+ # Skip processing if already processed during this configuration run
+ if (${PREFIX}_FOUND)
+ return()
+ endif()
+
+ set(found TRUE) # Start with the assumption that the package was found
+
+ # Did we find any files? Did we miss includes? These are for formatting better error messages.
+ set(some_files FALSE)
+ set(missing_headers FALSE)
+
+ # Shorthands for some variables that we need often
+ set(quiet ${${PREFIX}_FIND_QUIETLY})
+ set(required ${${PREFIX}_FIND_REQUIRED})
+ set(exactver ${${PREFIX}_FIND_VERSION_EXACT})
+ set(findver "${${PREFIX}_FIND_VERSION}")
+ set(version "${${PREFIX}_VERSION}")
+
+ # Lists of config option names (all, includes, libs)
+ unset(configopts)
+ set(includeopts ${${PREFIX}_PROCESS_INCLUDES})
+ set(libraryopts ${${PREFIX}_PROCESS_LIBS})
+
+ # Process deps to add to
+ foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES})
+ if (DEFINED ${i}_INCLUDE_OPTS OR DEFINED ${i}_LIBRARY_OPTS)
+ # The package seems to export option lists that we can use, woohoo!
+ list(APPEND includeopts ${${i}_INCLUDE_OPTS})
+ list(APPEND libraryopts ${${i}_LIBRARY_OPTS})
+ else()
+ # If plural forms don't exist or they equal singular forms
+ if ((NOT DEFINED ${i}_INCLUDE_DIRS AND NOT DEFINED ${i}_LIBRARIES) OR
+ ({i}_INCLUDE_DIR STREQUAL ${i}_INCLUDE_DIRS AND ${i}_LIBRARY STREQUAL ${i}_LIBRARIES))
+ # Singular forms can be used
+ if (DEFINED ${i}_INCLUDE_DIR)
+ list(APPEND includeopts ${i}_INCLUDE_DIR)
+ endif()
+ if (DEFINED ${i}_LIBRARY)
+ list(APPEND libraryopts ${i}_LIBRARY)
+ endif()
+ else()
+ # Oh no, we don't know the option names
+ message(FATAL_ERROR "We couldn't determine config variable names for ${i} includes and libs. Aieeh!")
+ endif()
+ endif()
+ endforeach()
+
+ if (includeopts)
+ list(REMOVE_DUPLICATES includeopts)
+ endif()
+
+ if (libraryopts)
+ list(REMOVE_DUPLICATES libraryopts)
+ endif()
+
+ string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}")
+ if (NOT tmp STREQUAL "${includeopts} ${libraryopts}")
+ message(AUTHOR_WARNING "Plural form ${tmp} found in config options of ${PREFIX}. This works as before but is now deprecated. Please only use singular forms INCLUDE_DIR and LIBRARY, and update your find scripts for LibFindMacros > 2.0 automatic dependency system (most often you can simply remove the PROCESS variables entirely).")
+ endif()
+
+ # Include/library names separated by spaces (notice: not CMake lists)
+ unset(includes)
+ unset(libs)
+
+ # Process all includes and set found false if any are missing
+ foreach (i ${includeopts})
+ list(APPEND configopts ${i})
+ if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
+ list(APPEND includes "${${i}}")
+ else()
+ set(found FALSE)
+ set(missing_headers TRUE)
+ endif()
+ endforeach()
+
+ # Process all libraries and set found false if any are missing
+ foreach (i ${libraryopts})
+ list(APPEND configopts ${i})
+ if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
+ list(APPEND libs "${${i}}")
+ else()
+ set (found FALSE)
+ endif()
+ endforeach()
+
+ # Version checks
+ if (found AND findver)
+ if (NOT version)
+ message(WARNING "The find module for ${PREFIX} does not provide version information, so we'll just assume that it is OK. Please fix the module or remove package version requirements to get rid of this warning.")
+ elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver))
+ set(found FALSE)
+ set(version_unsuitable TRUE)
+ endif()
+ endif()
+
+ # If all-OK, hide all config options, export variables, print status and exit
+ if (found)
+ foreach (i ${configopts})
+ mark_as_advanced(${i})
+ endforeach()
+ if (NOT quiet)
+ message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
+ if (LIBFIND_DEBUG)
+ message(STATUS " ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}")
+ message(STATUS " ${PREFIX}_INCLUDE_OPTS=${includeopts}")
+ message(STATUS " ${PREFIX}_INCLUDE_DIRS=${includes}")
+ message(STATUS " ${PREFIX}_LIBRARY_OPTS=${libraryopts}")
+ message(STATUS " ${PREFIX}_LIBRARIES=${libs}")
+ endif()
+ set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE)
+ set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE)
+ set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE)
+ set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE)
+ set (${PREFIX}_FOUND TRUE PARENT_SCOPE)
+ endif()
+ return()
+ endif()
+
+ # Format messages for debug info and the type of error
+ set(vars "Relevant CMake configuration variables:\n")
+ foreach (i ${configopts})
+ mark_as_advanced(CLEAR ${i})
+ set(val ${${i}})
+ if ("${val}" STREQUAL "${i}-NOTFOUND")
+ set (val "")
+ elseif (val AND NOT EXISTS ${val})
+ set (val "${val} (does not exist)")
+ else()
+ set(some_files TRUE)
+ endif()
+ set(vars "${vars} ${i}=${val}\n")
+ endforeach()
+ set(vars "${vars}You may use CMake GUI, cmake -D or ccmake to modify the values. Delete CMakeCache.txt to discard all values and force full re-detection if necessary.\n")
+ if (version_unsuitable)
+ set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but")
+ if (exactver)
+ set(msg "${msg} only version ${findver} is acceptable.")
+ else()
+ set(msg "${msg} version ${findver} is the minimum requirement.")
+ endif()
+ else()
+ if (missing_headers)
+ set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?")
+ elseif (some_files)
+ set(msg "We only found some files of ${PREFIX}, not all of them. Perhaps your installation is incomplete or maybe we just didn't look in the right place?")
+ if(findver)
+ set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).")
+ endif()
+ else()
+ set(msg "We were unable to find package ${PREFIX}.")
+ endif()
+ endif()
+
+ # Fatal error out if REQUIRED
+ if (required)
+ set(msg "REQUIRED PACKAGE NOT FOUND\n${msg} This package is REQUIRED and you need to install it or adjust CMake configuration in order to continue building ${CMAKE_PROJECT_NAME}.")
+ message(FATAL_ERROR "${msg}\n${vars}")
+ endif()
+ # Otherwise just print a nasty warning
+ if (NOT quiet)
+ message(WARNING "WARNING: MISSING PACKAGE\n${msg} This package is NOT REQUIRED and you may ignore this warning but by doing so you may miss some functionality of ${CMAKE_PROJECT_NAME}. \n${vars}")
+ endif()
+endfunction()
+
diff --git a/Microsoft.WindowsAzure.Storage/includes/targetver.h b/Microsoft.WindowsAzure.Storage/includes/targetver.h
index 9a67c656..0f73f169 100644
--- a/Microsoft.WindowsAzure.Storage/includes/targetver.h
+++ b/Microsoft.WindowsAzure.Storage/includes/targetver.h
@@ -22,4 +22,6 @@
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+#ifdef WIN32
#include
+#endif
diff --git a/Microsoft.WindowsAzure.Storage/includes/was/blob.h b/Microsoft.WindowsAzure.Storage/includes/was/blob.h
index 0e36533f..8beaf537 100644
--- a/Microsoft.WindowsAzure.Storage/includes/was/blob.h
+++ b/Microsoft.WindowsAzure.Storage/includes/was/blob.h
@@ -254,7 +254,7 @@ namespace azure { namespace storage {
enum class delete_snapshots_option
{
///
- /// Delete blobs but not snapshots.
+ /// Delete the blob only. If the blob has snapshots, this option will result in an error from the service.
///
none,
@@ -997,21 +997,44 @@ namespace azure { namespace storage {
///
cloud_blob_properties()
: m_type(blob_type::unspecified), m_page_blob_sequence_number(0),
- m_lease_state(lease_state::unspecified), m_lease_status(lease_status::unspecified),
- m_lease_duration(lease_duration::unspecified), m_size(0)
+ m_lease_state(azure::storage::lease_state::unspecified), m_lease_status(azure::storage::lease_status::unspecified),
+ m_lease_duration(azure::storage::lease_duration::unspecified), m_size(0)
{
}
+ cloud_blob_properties(const cloud_blob_properties& other)
+ {
+ *this = other;
+ }
+
///
/// Initializes a new instance of the class.
///
/// A reference to a set of on which to base the new instance.
cloud_blob_properties(cloud_blob_properties&& other)
{
- // TODO: Double check that the following std::move call is needed
*this = std::move(other);
}
+ cloud_blob_properties& operator=(const cloud_blob_properties& other)
+ {
+ m_size = other.m_size;
+ m_etag = other.m_etag;
+ m_last_modified = other.m_last_modified;
+ m_type = other.m_type;
+ m_lease_duration = other.m_lease_duration;
+ m_lease_state = other.m_lease_state;
+ m_lease_status = other.m_lease_status;
+ m_page_blob_sequence_number = other.m_page_blob_sequence_number;
+ m_cache_control = other.m_cache_control;
+ m_content_disposition = other.m_content_disposition;
+ m_content_encoding = other.m_content_encoding;
+ m_content_language = other.m_content_language;
+ m_content_md5 = other.m_content_md5;
+ m_content_type = other.m_content_type;
+ return *this;
+ }
+
///
/// Returns a reference to a object.
///
@@ -1603,7 +1626,7 @@ namespace azure { namespace storage {
///
/// The block name.
/// A value that indicates which block lists to search for the block.
- block_list_item(utility::string_t& id, block_mode mode)
+ block_list_item(utility::string_t id, block_mode mode)
: m_id(std::move(id)), m_size(std::numeric_limits::max()), m_mode(mode)
{
}
@@ -1784,9 +1807,8 @@ namespace azure { namespace storage {
private:
sequence_number(sequence_number_action action, int64_t value)
+ : m_action(action), m_value(value)
{
- m_action = action;
- m_value = value;
}
sequence_number_action m_action;
@@ -1802,7 +1824,11 @@ namespace azure { namespace storage {
///
/// Initializes a new instance of the class.
///
- cloud_blob_container_properties() {}
+ cloud_blob_container_properties()
+ : m_lease_status(azure::storage::lease_status::unspecified), m_lease_state(azure::storage::lease_state::unspecified),
+ m_lease_duration(azure::storage::lease_duration::unspecified)
+ {
+ }
///
/// Initializes a new instance of the class.
@@ -2237,7 +2263,7 @@ namespace azure { namespace storage {
void initialize()
{
- set_authentication_scheme(authentication_scheme::shared_key);
+ set_authentication_scheme(azure::storage::authentication_scheme::shared_key);
m_directory_delimiter = protocol::directory_delimiter;
}
diff --git a/Microsoft.WindowsAzure.Storage/includes/was/common.h b/Microsoft.WindowsAzure.Storage/includes/was/common.h
index d7dfee44..d1b402b4 100644
--- a/Microsoft.WindowsAzure.Storage/includes/was/common.h
+++ b/Microsoft.WindowsAzure.Storage/includes/was/common.h
@@ -22,6 +22,12 @@
#include "core.h"
#include "retry_policies.h"
+#ifndef WIN32
+#include
+#include
+#include
+#endif
+
namespace azure { namespace storage {
namespace protocol
@@ -150,7 +156,7 @@ namespace azure { namespace storage {
/// Gets the continuation token used to retrieve the next segment of results.
///
/// The continuation token.
- const continuation_token& continuation_token() const
+ const azure::storage::continuation_token& continuation_token() const
{
return m_continuation_token;
}
@@ -1052,6 +1058,15 @@ namespace azure { namespace storage {
return m_user_headers;
}
+ ///
+ /// Gets the user headers provided for the request.
+ ///
+ /// A object containing user headers.
+ const web::http::http_headers& user_headers() const
+ {
+ return m_user_headers;
+ }
+
///
/// Gets the results of the request.
///
@@ -1111,6 +1126,35 @@ namespace azure { namespace storage {
m_response_received = value;
}
+#ifndef WIN32
+ ///
+ /// Gets the logger object on this op_context.
+ ///
+ /// The logger object used by this op_context.
+ boost::log::sources::severity_logger& logger()
+ {
+ return m_logger;
+ }
+
+ ///
+ /// Gets the logger object on this op_context.
+ ///
+ /// The logger object used by this op_context.
+ const boost::log::sources::severity_logger& logger() const
+ {
+ return m_logger;
+ }
+
+ ///
+ /// Sets the logger object on this op_context.
+ ///
+ /// The logger object to use for requests made by this op_context.
+ void set_logger(boost::log::sources::severity_logger logger)
+ {
+ m_logger = std::move(logger);
+ }
+#endif
+
private:
std::function m_sending_request;
@@ -1122,6 +1166,9 @@ namespace azure { namespace storage {
client_log_level m_log_level;
std::vector m_request_results;
pplx::extensibility::critical_section_t m_request_results_lock;
+#ifndef WIN32
+ boost::log::sources::severity_logger m_logger;
+#endif
};
///
@@ -1249,6 +1296,15 @@ namespace azure { namespace storage {
return m_impl->user_headers();
}
+ ///
+ /// Gets or sets additional headers on the request, for example, for proxy or logging information.
+ ///
+ /// A reference containing additional header information.
+ const web::http::http_headers& user_headers() const
+ {
+ return m_impl->user_headers();
+ }
+
///
/// Gets the set of request results that the current operation has created.
///
@@ -1278,6 +1334,35 @@ namespace azure { namespace storage {
m_impl->set_response_received(value);
}
+#ifndef WIN32
+ ///
+ /// Gets the logger object on this op_context.
+ ///
+ /// The logger object used by this op_context.
+ boost::log::sources::severity_logger& logger()
+ {
+ return m_impl->logger();
+ }
+
+ ///
+ /// Gets the logger object on this op_context.
+ ///
+ /// The logger object used by this op_context.
+ const boost::log::sources::severity_logger& logger() const
+ {
+ return m_impl->logger();
+ }
+
+ ///
+ /// Sets the logger object on this op_context.
+ ///
+ /// The logger object to use for requests made by this op_context.
+ void set_logger(boost::log::sources::severity_logger logger)
+ {
+ m_impl->set_logger(std::move(logger));
+ }
+#endif
+
std::shared_ptr<_operation_context> _get_impl() const
{
return m_impl;
@@ -1632,6 +1717,30 @@ namespace azure { namespace storage {
m_location_mode = location_mode;
}
+ ///
+ /// Gets the number of bytes to buffer when reading from and writing to a network stream.
+ ///
+ /// The number of bytes to buffer when reading from and writing to a network stream.
+ ///
+ /// Using a larger buffer size is more efficient when downloading and uploading larger blobs because it will reduce CPU usage.
+ ///
+ size_t http_buffer_size() const
+ {
+ return m_http_buffer_size;
+ }
+
+ ///
+ /// Sets the number of bytes to buffer when reading from and writing to a network stream.
+ ///
+ /// The number of bytes to buffer when reading from and writing to a network stream.
+ ///
+ /// Using a larger buffer size is more efficient when downloading and uploading larger blobs because it will reduce CPU usage.
+ ///
+ void set_http_buffer_size(size_t http_buffer_size)
+ {
+ m_http_buffer_size = http_buffer_size;
+ }
+
///
/// Gets the expiry time across all potential retries for the request.
///
@@ -1646,11 +1755,7 @@ namespace azure { namespace storage {
///
/// Initializes a new instance of the class.
///
- request_options()
- : m_location_mode(location_mode::primary_only),
- m_retry_policy(exponential_retry_policy())
- {
- }
+ WASTORAGE_API request_options();
///
/// Applies the default set of request options.
@@ -1668,6 +1773,7 @@ namespace azure { namespace storage {
m_server_timeout.merge(other.m_server_timeout);
m_maximum_execution_time.merge(other.m_maximum_execution_time);
m_location_mode.merge(other.m_location_mode);
+ m_http_buffer_size.merge(other.m_http_buffer_size);
if (apply_expiry)
{
@@ -1690,6 +1796,7 @@ namespace azure { namespace storage {
option_with_default m_server_timeout;
option_with_default m_maximum_execution_time;
option_with_default m_location_mode;
+ option_with_default m_http_buffer_size;
};
}} // namespace azure::storage
diff --git a/Microsoft.WindowsAzure.Storage/includes/was/core.h b/Microsoft.WindowsAzure.Storage/includes/was/core.h
index 8301ac20..c557bda8 100644
--- a/Microsoft.WindowsAzure.Storage/includes/was/core.h
+++ b/Microsoft.WindowsAzure.Storage/includes/was/core.h
@@ -355,7 +355,7 @@ namespace azure { namespace storage {
/// The fallback value.
void merge(const option_with_default& value, const T& fallback_value)
{
- merge(value.m_has_value ? value : fallback_value);
+ merge(value.m_has_value ? (const T&)value : fallback_value);
}
private:
@@ -437,7 +437,8 @@ namespace azure { namespace storage {
request_result()
: m_is_response_available(false),
m_target_location(storage_location::unspecified),
- m_http_status_code(0)
+ m_http_status_code(0),
+ m_content_length(-1)
{
}
@@ -451,7 +452,8 @@ namespace azure { namespace storage {
m_start_time(start_time),
m_target_location(target_location),
m_end_time(utility::datetime::utc_now()),
- m_http_status_code(0)
+ m_http_status_code(0),
+ m_content_length(-1)
{
}
@@ -547,9 +549,18 @@ namespace azure { namespace storage {
}
///
- /// Gets the content-MD5 hash for the request.
+ /// Gets the content length for the request.
///
- /// The content-MD5 hash for the request.
+ /// The content length for the request.
+ utility::size64_t content_length() const
+ {
+ return m_content_length;
+ }
+
+ ///
+ /// Gets the content MD5 hash for the request.
+ ///
+ /// The content MD5 hash for the request.
const utility::string_t& content_md5() const
{
return m_content_md5;
@@ -594,6 +605,7 @@ namespace azure { namespace storage {
web::http::status_code m_http_status_code;
utility::string_t m_service_request_id;
utility::datetime m_request_date;
+ utility::size64_t m_content_length;
utility::string_t m_content_md5;
utility::string_t m_etag;
storage_extended_error m_extended_error;
@@ -670,47 +682,47 @@ namespace azure { namespace storage {
}
///
- /// Gets the target location for the next retry.
+ /// Gets the number of retries for the given operation.
///
- /// The target location for the next retry.
- storage_location next_location() const
+ /// The number of retries for the given operation.
+ int current_retry_count() const
{
- return m_next_location;
+ return m_current_retry_count;
}
///
- /// Gets the location mode for subsequent retries.
+ /// Gets the results of the last request.
///
- /// The location mode for subsequent retries.
- location_mode current_location_mode() const
+ /// A object that represents the results of the last request.
+ const request_result& last_request_result() const
{
- return m_current_location_mode;
+ return m_last_request_result;
}
///
- /// Gets the number of retries for the given operation.
+ /// Gets the target location for the next retry.
///
- /// The number of retries for the given operation.
- int current_retry_count() const
+ /// The target location for the next retry.
+ storage_location next_location() const
{
- return m_current_retry_count;
+ return m_next_location;
}
///
- /// Gets the results of the last request.
+ /// Gets the location mode for subsequent retries.
///
- /// A object that represents the results of the last request.
- const request_result& last_request_result() const
+ /// The location mode for subsequent retries.
+ location_mode current_location_mode() const
{
- return m_last_request_result;
+ return m_current_location_mode;
}
private:
- storage_location m_next_location;
- location_mode m_current_location_mode;
int m_current_retry_count;
request_result m_last_request_result;
+ storage_location m_next_location;
+ location_mode m_current_location_mode;
};
///
@@ -724,7 +736,8 @@ namespace azure { namespace storage {
/// Initializes a new instance of the class.
///
retry_info()
- : m_should_retry(false)
+ : m_should_retry(false), m_target_location(storage_location::unspecified),
+ m_updated_location_mode(location_mode::unspecified), m_retry_interval()
{
}
@@ -733,13 +746,20 @@ namespace azure { namespace storage {
///
/// The object that was passed in to the retry policy.
explicit retry_info(const retry_context& context)
- : m_should_retry(true),
- m_target_location(context.next_location()),
- m_updated_location_mode(context.current_location_mode()),
- m_retry_interval(protocol::default_retry_interval)
+ : m_should_retry(true), m_target_location(context.next_location()),
+ m_updated_location_mode(context.current_location_mode()), m_retry_interval(protocol::default_retry_interval)
{
}
+ ///
+ /// Indicates that the request should be retried.
+ ///
+ /// true if the request should be retried.
+ bool should_retry() const
+ {
+ return m_should_retry;
+ }
+
///
/// Gets the target location for the next retry.
///
@@ -794,21 +814,12 @@ namespace azure { namespace storage {
m_retry_interval = value;
}
- ///
- /// Indicates that the request should be retried.
- ///
- /// true if the request should be retried.
- bool should_retry() const
- {
- return m_should_retry;
- }
-
private:
bool m_should_retry;
- std::chrono::milliseconds m_retry_interval;
storage_location m_target_location;
location_mode m_updated_location_mode;
+ std::chrono::milliseconds m_retry_interval;
};
class retry_policy;
@@ -885,3 +896,7 @@ namespace azure { namespace storage {
};
}} // namespace azure::storage
+
+#ifndef WIN32
+#define UNREFERENCED_PARAMETER(P) (P)
+#endif
diff --git a/Microsoft.WindowsAzure.Storage/includes/was/queue.h b/Microsoft.WindowsAzure.Storage/includes/was/queue.h
index 09cfe305..2c3be2eb 100644
--- a/Microsoft.WindowsAzure.Storage/includes/was/queue.h
+++ b/Microsoft.WindowsAzure.Storage/includes/was/queue.h
@@ -707,7 +707,7 @@ namespace azure { namespace storage {
void initialize()
{
- set_authentication_scheme(authentication_scheme::shared_key);
+ set_authentication_scheme(azure::storage::authentication_scheme::shared_key);
}
queue_request_options get_modified_options(const queue_request_options& options) const;
diff --git a/Microsoft.WindowsAzure.Storage/includes/was/retry_policies.h b/Microsoft.WindowsAzure.Storage/includes/was/retry_policies.h
index e3d106fb..d3fe4434 100644
--- a/Microsoft.WindowsAzure.Storage/includes/was/retry_policies.h
+++ b/Microsoft.WindowsAzure.Storage/includes/was/retry_policies.h
@@ -179,7 +179,7 @@ namespace azure { namespace storage {
/// The maximum number of retries to attempt.
basic_exponential_retry_policy(std::chrono::seconds delta_backoff, int max_attempts)
: basic_common_retry_policy(max_attempts), m_delta_backoff(delta_backoff),
- m_rand_distribution(delta_backoff.count() * 0.8, delta_backoff.count() * 1.2)
+ m_rand_distribution(static_cast(delta_backoff.count()) * 0.8, static_cast(delta_backoff.count()) * 1.2)
{
}
diff --git a/Microsoft.WindowsAzure.Storage/includes/was/service_client.h b/Microsoft.WindowsAzure.Storage/includes/was/service_client.h
index a1322771..ea6820e1 100644
--- a/Microsoft.WindowsAzure.Storage/includes/was/service_client.h
+++ b/Microsoft.WindowsAzure.Storage/includes/was/service_client.h
@@ -81,6 +81,7 @@ namespace azure { namespace storage {
/// Initializes a new instance of the service client class using the specified service endpoint.
///
cloud_client()
+ : m_authentication_scheme(azure::storage::authentication_scheme::shared_key)
{
}
@@ -89,7 +90,7 @@ namespace azure { namespace storage {
///
/// A object containing the service endpoint for all locations.
explicit cloud_client(storage_uri base_uri)
- : m_base_uri(std::move(base_uri))
+ : m_base_uri(std::move(base_uri)), m_authentication_scheme(azure::storage::authentication_scheme::shared_key)
{
}
@@ -99,7 +100,7 @@ namespace azure { namespace storage {
/// A object containing the service endpoint for all locations.
/// The to use.
cloud_client(storage_uri base_uri, azure::storage::storage_credentials credentials)
- : m_base_uri(std::move(base_uri)), m_credentials(std::move(credentials))
+ : m_base_uri(std::move(base_uri)), m_credentials(std::move(credentials)), m_authentication_scheme(azure::storage::authentication_scheme::shared_key)
{
}
diff --git a/Microsoft.WindowsAzure.Storage/includes/was/table.h b/Microsoft.WindowsAzure.Storage/includes/was/table.h
index c815e78c..0be976e9 100644
--- a/Microsoft.WindowsAzure.Storage/includes/was/table.h
+++ b/Microsoft.WindowsAzure.Storage/includes/was/table.h
@@ -1054,17 +1054,17 @@ namespace azure { namespace storage {
///
/// Represents the And operator.
///
- WASTORAGE_API const static utility::string_t and;
+ WASTORAGE_API const static utility::string_t op_and;
///
/// Represents the Not operator.
///
- WASTORAGE_API const static utility::string_t not;
+ WASTORAGE_API const static utility::string_t op_not;
///
/// Represents the Or operator.
///
- WASTORAGE_API const static utility::string_t or;
+ WASTORAGE_API const static utility::string_t op_or;
};
///
@@ -1794,7 +1794,7 @@ namespace azure { namespace storage {
void initialize()
{
- set_authentication_scheme(authentication_scheme::shared_key);
+ set_authentication_scheme(azure::storage::authentication_scheme::shared_key);
}
table_request_options get_modified_options(const table_request_options& options) const;
diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/basic_types.h b/Microsoft.WindowsAzure.Storage/includes/wascore/basic_types.h
index 2f7adde4..c345e254 100644
--- a/Microsoft.WindowsAzure.Storage/includes/wascore/basic_types.h
+++ b/Microsoft.WindowsAzure.Storage/includes/wascore/basic_types.h
@@ -53,7 +53,10 @@ namespace utility {
#ifdef WIN32
typedef UUID uuid;
#else
- typedef uuid_t uuid;
+ typedef struct
+ {
+ uuid_t data;
+ } uuid;
#endif
///
diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/blobstreams.h b/Microsoft.WindowsAzure.Storage/includes/wascore/blobstreams.h
index a76701f4..148500ad 100644
--- a/Microsoft.WindowsAzure.Storage/includes/wascore/blobstreams.h
+++ b/Microsoft.WindowsAzure.Storage/includes/wascore/blobstreams.h
@@ -37,7 +37,7 @@ namespace azure { namespace storage { namespace core {
{
if (!options.disable_content_md5_validation() && !m_blob->properties().content_md5().empty())
{
- m_blob_hash = hash_md5_streambuf();
+ m_blob_hash_provider = hash_provider::create_md5_hash_provider();
}
}
@@ -156,7 +156,7 @@ namespace azure { namespace storage { namespace core {
access_condition m_condition;
blob_request_options m_options;
operation_context m_context;
- hash_streambuf m_blob_hash;
+ hash_provider m_blob_hash_provider;
off_type m_current_blob_offset;
off_type m_next_blob_offset;
size_t m_buffer_size;
@@ -185,12 +185,12 @@ namespace azure { namespace storage { namespace core {
{
if (options.use_transactional_md5())
{
- m_block_hash = hash_md5_streambuf();
+ m_block_hash_provider = hash_provider::create_md5_hash_provider();
}
if (options.store_blob_content_md5())
{
- m_blob_hash = hash_md5_streambuf();
+ m_blob_hash_provider = hash_provider::create_md5_hash_provider();
}
}
@@ -307,15 +307,17 @@ namespace azure { namespace storage { namespace core {
private:
- concurrency::streams::istream m_stream;
+ // Note: m_size must be initialized before m_stream, and thus must be listed first in this list.
+ // This is because we use std::move to initialize m_stream, but we need to get the size first.
utility::size64_t m_size;
utility::string_t m_content_md5;
+ concurrency::streams::istream m_stream;
};
concurrency::streams::container_buffer> m_buffer;
pos_type m_current_streambuf_offset;
- hash_streambuf m_blob_hash;
- hash_streambuf m_block_hash;
+ hash_provider m_blob_hash_provider;
+ hash_provider m_block_hash_provider;
access_condition m_condition;
blob_request_options m_options;
operation_context m_context;
diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/constants.h b/Microsoft.WindowsAzure.Storage/includes/wascore/constants.h
index 6c575e9c..76ba5baa 100644
--- a/Microsoft.WindowsAzure.Storage/includes/wascore/constants.h
+++ b/Microsoft.WindowsAzure.Storage/includes/wascore/constants.h
@@ -35,6 +35,13 @@ namespace azure { namespace storage { namespace protocol {
// duration constants
const std::chrono::seconds default_retry_interval(3);
+ // The following value must be less than 2147482, which is the highest
+ // that Casablanca 2.2.0 on Linux can accept, which is derived from
+ // the maximum value for a signed long on g++, divided by 1000.
+ // Choosing to set it to 24 days to align with .NET.
+ const std::chrono::seconds default_maximum_execution_time(24 * 24 * 60 * 60);
+ // For the following value, "0" means "don't send a timeout to the service"
+ const std::chrono::seconds default_server_timeout(0);
// uri query parameters
const utility::string_t uri_query_timeout(U("timeout"));
@@ -298,9 +305,9 @@ namespace azure { namespace storage { namespace protocol {
// user agent
#if defined(WIN32)
- const utility::string_t header_value_user_agent(U("Azure-Storage/0.3.0 (Native; Windows)"));
+ const utility::string_t header_value_user_agent(U("Azure-Storage/0.4.0 (Native; Windows)"));
#else
- const utility::string_t header_value_user_agent(U("Azure-Storage/0.3.0 (Native)"));
+ const utility::string_t header_value_user_agent(U("Azure-Storage/0.4.0 (Native)"));
#endif
}}} // namespace azure::storage::protocol
diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/executor.h b/Microsoft.WindowsAzure.Storage/includes/wascore/executor.h
index 29ac3da2..26418da1 100644
--- a/Microsoft.WindowsAzure.Storage/includes/wascore/executor.h
+++ b/Microsoft.WindowsAzure.Storage/includes/wascore/executor.h
@@ -24,6 +24,7 @@
#include "util.h"
#include "streams.h"
#include "was/auth.h"
+#include "wascore/resources.h"
namespace azure { namespace storage { namespace core {
@@ -48,32 +49,23 @@ namespace azure { namespace storage { namespace core {
return pplx::task_from_result(istream_descriptor(stream, length, utility::string_t()));
}
+ hash_provider provider = calculate_md5 ? core::hash_provider::create_md5_hash_provider() : core::hash_provider();
concurrency::streams::container_buffer> temp_buffer;
concurrency::streams::ostream temp_stream;
- hash_streambuf hash_buffer;
if (calculate_md5)
{
- // If MD5 is needed, a splitter_streambuf will act as a proxy to forward incoming data to
- // a hash_md5_streambuf and the in-memory container_buffer
- hash_buffer = hash_md5_streambuf();
- temp_stream = splitter_streambuf(temp_buffer, hash_buffer).create_ostream();
+ temp_stream = hash_wrapper_streambuf(temp_buffer, provider).create_ostream();
}
else
{
temp_stream = temp_buffer.create_ostream();
}
- return stream_copy_async(stream, temp_stream, length).then([temp_buffer, hash_buffer] (pplx::task buffer_task) mutable -> istream_descriptor
+ return stream_copy_async(stream, temp_stream, length).then([temp_buffer, provider] (pplx::task buffer_task) mutable -> istream_descriptor
{
- utility::string_t md5;
- if (hash_buffer)
- {
- hash_buffer.close().wait();
- md5 = utility::conversions::to_base64(hash_buffer.hash());
- }
-
- return istream_descriptor(concurrency::streams::container_stream>::open_istream(temp_buffer.collection()), buffer_task.get(), md5);
+ provider.close();
+ return istream_descriptor(concurrency::streams::container_stream>::open_istream(temp_buffer.collection()), buffer_task.get(), provider.hash());
});
}
@@ -185,12 +177,12 @@ namespace azure { namespace storage { namespace core {
m_calculate_response_body_md5 = value;
}
- void set_build_request(std::function value)
+ void set_build_request(std::function value)
{
m_build_request = value;
}
- void set_custom_sign_request(std::function value)
+ void set_custom_sign_request(std::function value)
{
m_sign_request = value;
}
@@ -200,17 +192,17 @@ namespace azure { namespace storage { namespace core {
set_custom_sign_request(std::bind(&protocol::authentication_handler::sign_request, handler, std::placeholders::_1, std::placeholders::_2));
}
- void set_recover_request(std::function value)
+ void set_recover_request(std::function value)
{
m_recover_request = value;
}
- void set_preprocess_response(std::function value)
+ void set_preprocess_response(std::function value)
{
m_preprocess_response = value;
}
- void set_postprocess_response(std::function (const web::http::http_response &, const request_result&, const ostream_descriptor&, operation_context)> value)
+ void set_postprocess_response(std::function(const web::http::http_response &, const request_result&, const ostream_descriptor&, operation_context)> value)
{
m_postprocess_response = value;
}
@@ -252,10 +244,10 @@ namespace azure { namespace storage { namespace core {
command_location_mode m_location_mode;
std::function m_build_request;
- std::function m_sign_request;
- std::function m_recover_request;
- std::function m_preprocess_response;
- std::function (const web::http::http_response &, const request_result&, const ostream_descriptor&, operation_context)> m_postprocess_response;
+ std::function m_sign_request;
+ std::function m_recover_request;
+ std::function m_preprocess_response;
+ std::function (const web::http::http_response&, const request_result&, const ostream_descriptor&, operation_context)> m_postprocess_response;
friend class executor;
};
@@ -266,8 +258,8 @@ namespace azure { namespace storage { namespace core {
public:
executor(std::shared_ptr> command, const request_options& options, operation_context context)
- : m_command(command), m_request_options(options), m_context(context),
- m_retry_count(0), m_current_location(get_first_location(options.location_mode())),
+ : m_command(command), m_request_options(options), m_context(context), m_is_hashing_started(false),
+ m_total_downloaded(0), m_retry_count(0), m_current_location(get_first_location(options.location_mode())),
m_current_location_mode(options.location_mode()), m_retry_policy(options.retry_policy().clone())
{
}
@@ -283,7 +275,7 @@ namespace azure { namespace storage { namespace core {
// TODO: Reduce usage of auto variable types
auto instance = std::make_shared>(command, options, context);
- return pplx::details::do_while([instance] () -> pplx::task
+ return pplx::details::do_while([instance]() -> pplx::task
{
// 0. Begin request
instance->validate_location_mode();
@@ -320,24 +312,34 @@ namespace azure { namespace storage { namespace core {
instance->m_command->m_request_body.rewind();
instance->m_request.set_body(instance->m_command->m_request_body.stream(), instance->m_command->m_request_body.length(), utility::string_t());
}
+ else
+ {
+ // TODO: Remove the following when we can take a dependency on Casablanca 2.3. This line fo code is a workaround for a bug in 2.2.
+ if ((((utility::string_t)instance->m_request.method()) == U("HEAD")) || (((utility::string_t)instance->m_request.method()) == U("DELETE")) || (((utility::string_t)instance->m_request.method()) == U("GET")))
+ {
+ instance->m_request.headers().add(protocol::xml_content_length, 0);
+ }
+ }
// If the command wants to copy the response body to a stream, set it
// on the http_request object
if (instance->m_command->m_destination_stream)
{
- // If MD5 is needed, a splitter_streambuf will act as a proxy to forward incoming data to
- // a hash_md5_streambuf and the destination stream provided by the command
- if (instance->m_command->m_calculate_response_body_md5)
+ // Calculate the length and MD5 hash if needed as the incoming data is read
+ if (!instance->m_is_hashing_started)
{
- instance->m_hash_streambuf = hash_md5_streambuf();
- instance->m_response_streambuf = splitter_streambuf(instance->m_command->m_destination_stream.streambuf(), instance->m_hash_streambuf);
- }
- else
- {
- instance->m_hash_streambuf = hash_streambuf();
- instance->m_response_streambuf = splitter_streambuf(instance->m_command->m_destination_stream.streambuf(), null_streambuf());
+ if (instance->m_command->m_calculate_response_body_md5)
+ {
+ instance->m_hash_provider = hash_provider::create_md5_hash_provider();
+ }
+
+ instance->m_total_downloaded = 0;
+ instance->m_is_hashing_started = true;
+
+ // TODO: Consider using hash_provider::is_enabled instead of m_is_hashing_started to signal when the hash provider has been closed
}
+ instance->m_response_streambuf = hash_wrapper_streambuf(instance->m_command->m_destination_stream.streambuf(), instance->m_hash_provider);
instance->m_request.set_response_stream(instance->m_response_streambuf.create_ostream());
}
@@ -351,13 +353,27 @@ namespace azure { namespace storage { namespace core {
// 3. Sign Request
instance->m_command->m_sign_request(instance->m_request, instance->m_context);
- // 4. Set timeout
+ // 4. Set HTTP client configuration
web::http::client::http_client_config config;
config.set_timeout(instance->remaining_time());
+ // TODO: Remove the following when we can take a dependency on Casablanca 2.3. This line fo code is a workaround for a bug in 2.2.
+#ifndef WIN32
+ if (config.timeout() < std::chrono::seconds(1))
+ {
+ config.set_timeout(std::chrono::seconds(1));
+ }
+#endif
+
+ size_t http_buffer_size = instance->m_request_options.http_buffer_size();
+ if (http_buffer_size > 0)
+ {
+ config.set_chunksize(http_buffer_size);
+ }
+
// 5-6. Potentially upload data and get response
web::http::client::http_client client(instance->m_request.request_uri().authority(), config);
- return client.request(instance->m_request).then([instance] (pplx::task get_headers_task) -> pplx::task
+ return client.request(instance->m_request).then([instance](pplx::task get_headers_task) -> pplx::task
{
// Headers are ready. It should be noted that http_client will
// continue to download the response body in parallel.
@@ -382,8 +398,8 @@ namespace azure { namespace storage { namespace core {
// 7. Do Response parsing (headers etc, no stream available here)
// This is when the status code will be checked and m_preprocess_response
// will throw a storage_exception if it is not expected.
- instance->m_result = instance->m_command->m_preprocess_response(response, instance->m_context);
instance->m_request_result = request_result(instance->m_start_time, instance->m_current_location, response, false);
+ instance->m_result = instance->m_command->m_preprocess_response(response, instance->m_request_result, instance->m_context);
if (logger::instance().should_log(instance->m_context, client_log_level::log_level_informational))
{
@@ -407,7 +423,7 @@ namespace azure { namespace storage { namespace core {
// is seekable and thus it cannot be read back to parse the error.
if (!instance->m_command->m_destination_stream)
{
- return response.content_ready().then([instance] (pplx::task get_error_body_task) -> web::http::http_response
+ return response.content_ready().then([instance](pplx::task get_error_body_task) -> web::http::http_response
{
auto response = get_error_body_task.get();
instance->m_request_result = request_result(instance->m_start_time, instance->m_current_location, response, true);
@@ -424,11 +440,22 @@ namespace azure { namespace storage { namespace core {
// In the worst case, storage_exception will just contain the HTTP error message
throw storage_exception(utility::conversions::to_utf8string(response.reason_phrase()));
}
- }).then([instance] (pplx::task get_body_task) -> pplx::task
+ }).then([instance](pplx::task get_body_task) -> pplx::task
{
// 9. Evaluate response & parse results
auto response = get_body_task.get();
+ if (instance->m_command->m_destination_stream)
+ {
+ utility::size64_t current_total_downloaded = instance->m_response_streambuf.total_written();
+ utility::size64_t content_length = instance->m_request_result.content_length();
+ if (content_length != -1 && current_total_downloaded != content_length)
+ {
+ // The download was interrupted before it could complete
+ throw storage_exception(protocol::error_incorrect_length);
+ }
+ }
+
// If the command asked for post-processing, it is now time to call m_postprocess_response
if (instance->m_command->m_postprocess_response)
{
@@ -437,22 +464,18 @@ namespace azure { namespace storage { namespace core {
logger::instance().log(instance->m_context, client_log_level::log_level_informational, U("Processing response body"));
}
- // Get the MD5 hash if MD5 was calculated.
- utility::string_t md5;
- if (instance->m_hash_streambuf)
- {
- // It is ok to wait this call, as all hash_streambuf implementations are synchronous anyway.
- instance->m_hash_streambuf.close().wait();
- md5 = utility::conversions::to_base64(instance->m_hash_streambuf.hash());
- }
+ // Finish the MD5 hash if MD5 was being calculated
+ instance->m_hash_provider.close();
+ instance->m_is_hashing_started = false;
ostream_descriptor descriptor;
if (instance->m_response_streambuf)
{
- descriptor = ostream_descriptor(instance->m_response_streambuf.total_written(), md5);
+ utility::size64_t total_downloaded = instance->m_total_downloaded + instance->m_response_streambuf.total_written();
+ descriptor = ostream_descriptor(total_downloaded, instance->m_hash_provider.hash());
}
- return instance->m_command->m_postprocess_response(response, instance->m_request_result, descriptor, instance->m_context).then([instance] (pplx::task result_task)
+ return instance->m_command->m_postprocess_response(response, instance->m_request_result, descriptor, instance->m_context).then([instance](pplx::task result_task)
{
try
{
@@ -475,7 +498,7 @@ namespace azure { namespace storage { namespace core {
{
return pplx::task_from_result();
}
- }).then([instance] (pplx::task final_task) -> pplx::task
+ }).then([instance](pplx::task final_task) -> pplx::task
{
bool retryable_exception = true;
instance->m_context._get_impl()->add_request_result(instance->m_request_result);
@@ -525,10 +548,15 @@ namespace azure { namespace storage { namespace core {
instance->m_current_location = retry.target_location();
instance->m_current_location_mode = retry.updated_location_mode();
+ if (instance->m_response_streambuf)
+ {
+ instance->m_total_downloaded += instance->m_response_streambuf.total_written();
+ }
+
// Try to recover the request. If it cannot be recovered, it cannot be retried
// even if the retry policy allowed for a retry.
if (instance->m_command->m_recover_request &&
- !instance->m_command->m_recover_request(instance->m_context))
+ !instance->m_command->m_recover_request(instance->m_total_downloaded, instance->m_context))
{
if (logger::instance().should_log(instance->m_context, client_log_level::log_level_error))
{
@@ -545,7 +573,7 @@ namespace azure { namespace storage { namespace core {
logger::instance().log(instance->m_context, client_log_level::log_level_informational, str.str());
}
- return complete_after(retry.retry_interval()).then([] () -> bool
+ return complete_after(retry.retry_interval()).then([]() -> bool
{
// Returning true here will tell the outer do_while loop to loop one more time.
return true;
@@ -555,7 +583,7 @@ namespace azure { namespace storage { namespace core {
// Returning false here will cause do_while to exit.
return pplx::task_from_result(false);
});
- }).then([instance] (pplx::task loop_task) -> T
+ }).then([instance](pplx::task loop_task) -> T
{
instance->m_context.set_end_time(utility::datetime::utc_now());
loop_task.wait();
@@ -690,8 +718,10 @@ namespace azure { namespace storage { namespace core {
web::http::uri_builder m_uri_builder;
web::http::http_request m_request;
request_result m_request_result;
- hash_streambuf m_hash_streambuf;
- splitter_streambuf m_response_streambuf;
+ bool m_is_hashing_started;
+ hash_provider m_hash_provider;
+ hash_wrapper_streambuf m_response_streambuf;
+ utility::size64_t m_total_downloaded;
retry_policy m_retry_policy;
int m_retry_count;
storage_location m_current_location;
@@ -712,11 +742,11 @@ namespace azure { namespace storage { namespace core {
{
}
- void set_preprocess_response(std::function value)
+ void set_preprocess_response(std::function value)
{
- storage_command::set_preprocess_response([value] (const web::http::http_response& response, operation_context context) -> void_command_type
+ storage_command::set_preprocess_response([value] (const web::http::http_response& response, const request_result& result, operation_context context) -> void_command_type
{
- value(response, context);
+ value(response, result, context);
return VOID_COMMAND_RESULT;
});
}
diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/hashing.h b/Microsoft.WindowsAzure.Storage/includes/wascore/hashing.h
new file mode 100644
index 00000000..5463942c
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/includes/wascore/hashing.h
@@ -0,0 +1,268 @@
+// -----------------------------------------------------------------------------------------
+//
+// Copyright 2013 Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------------------
+
+#pragma once
+
+#include "cpprest/streams.h"
+
+#include "wascore/basic_types.h"
+#include "was/core.h"
+
+#ifdef WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#endif
+#define NOMINMAX
+#include
+#include
+#include
+#else
+#include
+#include
+#include
+#endif
+
+namespace azure { namespace storage { namespace core {
+
+ class hash_provider_impl
+ {
+ public:
+ virtual ~hash_provider_impl()
+ {
+ }
+
+ virtual bool is_enabled() const = 0;
+ virtual void write(const uint8_t* data, size_t count) = 0;
+ virtual void close() = 0;
+ virtual utility::string_t hash() const = 0;
+ };
+
+#ifdef WIN32
+
+ class cryptography_hash_algorithm
+ {
+ public:
+ ~cryptography_hash_algorithm();
+
+ operator BCRYPT_ALG_HANDLE() const
+ {
+ return m_algorithm_handle;
+ }
+
+ protected:
+ cryptography_hash_algorithm(LPCWSTR algorithm_id, ULONG flags);
+
+ private:
+ BCRYPT_ALG_HANDLE m_algorithm_handle;
+ };
+
+ class hmac_sha256_hash_algorithm : public cryptography_hash_algorithm
+ {
+ public:
+ static const hmac_sha256_hash_algorithm& instance()
+ {
+ return m_instance;
+ }
+
+ private:
+ hmac_sha256_hash_algorithm()
+ : cryptography_hash_algorithm(BCRYPT_SHA256_ALGORITHM, BCRYPT_ALG_HANDLE_HMAC_FLAG)
+ {
+ }
+
+ static hmac_sha256_hash_algorithm m_instance;
+ };
+
+ class md5_hash_algorithm : public cryptography_hash_algorithm
+ {
+ public:
+ static const md5_hash_algorithm& instance()
+ {
+ return m_instance;
+ }
+
+ private:
+ md5_hash_algorithm()
+ : cryptography_hash_algorithm(BCRYPT_MD5_ALGORITHM, 0)
+ {
+ }
+
+ static md5_hash_algorithm m_instance;
+ };
+
+ class cryptography_hash_provider_impl : public hash_provider_impl
+ {
+ public:
+ cryptography_hash_provider_impl(const cryptography_hash_algorithm& algorithm, const std::vector& key);
+ ~cryptography_hash_provider_impl() override;
+
+ bool is_enabled() const override
+ {
+ return true;
+ }
+
+ void write(const uint8_t* data, size_t count) override;
+ void close() override;
+
+ utility::string_t hash() const override
+ {
+ return utility::conversions::to_base64(m_hash);
+ }
+
+ private:
+ std::vector m_hash_object;
+ BCRYPT_HASH_HANDLE m_hash_handle;
+ std::vector m_hash;
+ };
+
+ class hmac_sha256_hash_provider_impl : public cryptography_hash_provider_impl
+ {
+ public:
+ hmac_sha256_hash_provider_impl(const std::vector& key);
+ };
+
+ class md5_hash_provider_impl : public cryptography_hash_provider_impl
+ {
+ public:
+ md5_hash_provider_impl();
+ };
+
+#else // Linux
+
+ class cryptography_hash_provider_impl : public hash_provider_impl
+ {
+ public:
+ ~cryptography_hash_provider_impl() override
+ {
+ }
+
+ bool is_enabled() const override
+ {
+ return true;
+ }
+
+ utility::string_t hash() const override
+ {
+ return utility::conversions::to_base64(m_hash);
+ }
+
+ protected:
+ std::vector m_hash;
+ };
+
+ class hmac_sha256_hash_provider_impl : public cryptography_hash_provider_impl
+ {
+ public:
+ hmac_sha256_hash_provider_impl(const std::vector& key);
+
+ void write(const uint8_t* data, size_t count) override;
+ void close() override;
+
+ private:
+ HMAC_CTX m_hash_context;
+ };
+
+ class md5_hash_provider_impl : public cryptography_hash_provider_impl
+ {
+ public:
+ md5_hash_provider_impl();
+
+ void write(const uint8_t* data, size_t count) override;
+ void close() override;
+
+ private:
+ MD5_CTX m_hash_context;
+ };
+
+#endif
+
+ class null_hash_provider_impl : public hash_provider_impl
+ {
+ public:
+ bool is_enabled() const override
+ {
+ return false;
+ }
+
+ void write(const uint8_t* data, size_t count) override
+ {
+ // no-op
+ UNREFERENCED_PARAMETER(data);
+ UNREFERENCED_PARAMETER(count);
+ }
+
+ void close() override
+ {
+ // no-op
+ }
+
+ utility::string_t hash() const override
+ {
+ return utility::string_t();
+ }
+ };
+
+ class hash_provider
+ {
+ public:
+ hash_provider()
+ : m_implementation(std::make_shared())
+ {
+ }
+
+ bool is_enabled() const
+ {
+ return m_implementation->is_enabled();
+ }
+
+ void write(const uint8_t* data, size_t count)
+ {
+ m_implementation->write(data, count);
+ }
+
+ void close()
+ {
+ m_implementation->close();
+ }
+
+ utility::string_t hash() const
+ {
+ return m_implementation->hash();
+ }
+
+ static hash_provider create_hmac_sha256_hash_provider(const std::vector& key)
+ {
+ return hash_provider(std::make_shared(key));
+ }
+
+ static hash_provider create_md5_hash_provider()
+ {
+ return hash_provider(std::make_shared());
+ }
+
+ private:
+ explicit hash_provider(std::shared_ptr implementation)
+ : m_implementation(implementation)
+ {
+ }
+
+ // The hash provider implementation is in a separate object so the hash_provider object can be copied yet maintain the
+ // same shared state for the hashing progress, and so different implementations can store different state on the heap.
+ std::shared_ptr m_implementation;
+ };
+
+}}} // namespace azure::storage::core
diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/logging.h b/Microsoft.WindowsAzure.Storage/includes/wascore/logging.h
index 2975e506..f0a82224 100644
--- a/Microsoft.WindowsAzure.Storage/includes/wascore/logging.h
+++ b/Microsoft.WindowsAzure.Storage/includes/wascore/logging.h
@@ -34,7 +34,10 @@ namespace azure { namespace storage { namespace core {
~logger();
void log(azure::storage::operation_context context, client_log_level level, const std::string& message) const;
+
+#ifdef WIN32
void log(azure::storage::operation_context context, client_log_level level, const std::wstring& message) const;
+#endif
bool should_log(azure::storage::operation_context context, client_log_level level) const;
private:
diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/protocol.h b/Microsoft.WindowsAzure.Storage/includes/wascore/protocol.h
index 7ff7c1c5..2c80ee3e 100644
--- a/Microsoft.WindowsAzure.Storage/includes/wascore/protocol.h
+++ b/Microsoft.WindowsAzure.Storage/includes/wascore/protocol.h
@@ -106,7 +106,7 @@ namespace azure { namespace storage { namespace protocol {
// Common response parsers
template
- T preprocess_response(T return_value, const web::http::http_response& response, operation_context context)
+ T preprocess_response(T return_value, const web::http::http_response& response, const request_result&, operation_context)
{
switch (response.status_code())
{
@@ -126,8 +126,7 @@ namespace azure { namespace storage { namespace protocol {
return return_value;
}
- void preprocess_response(const web::http::http_response& response, operation_context context);
- void check_stream_length_and_md5(utility::size64_t length, const utility::string_t& content_md5, const core::ostream_descriptor& descriptor);
+ void preprocess_response_void(const web::http::http_response& response, const request_result& result, operation_context context);
utility::datetime parse_last_modified(const utility::string_t& value);
utility::string_t parse_lease_id(const utility::string_t& value);
diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/protocol_xml.h b/Microsoft.WindowsAzure.Storage/includes/wascore/protocol_xml.h
index c16eb5a4..c6e24d58 100644
--- a/Microsoft.WindowsAzure.Storage/includes/wascore/protocol_xml.h
+++ b/Microsoft.WindowsAzure.Storage/includes/wascore/protocol_xml.h
@@ -33,13 +33,13 @@ namespace azure { namespace storage { namespace protocol {
{
}
- utility::string_t extract_error_code()
+ utility::string_t move_error_code()
{
parse();
return std::move(m_error_code);
}
- utility::string_t extract_error_message()
+ utility::string_t move_error_message()
{
parse();
return std::move(m_error_message);
@@ -62,22 +62,22 @@ namespace azure { namespace storage { namespace protocol {
{
}
- web::http::uri uri()
+ web::http::uri move_uri()
{
return std::move(m_uri);
}
- utility::string_t name()
+ utility::string_t move_name()
{
return std::move(m_name);
}
- cloud_metadata metadata()
+ cloud_metadata move_metadata()
{
return std::move(m_metadata);
}
- cloud_blob_container_properties properties()
+ cloud_blob_container_properties move_properties()
{
return std::move(m_properties);
}
@@ -99,13 +99,13 @@ namespace azure { namespace storage { namespace protocol {
{
}
- std::vector extract_items()
+ std::vector move_items()
{
parse();
return std::move(m_items);
}
- utility::string_t extract_next_marker()
+ utility::string_t move_next_marker()
{
parse();
return std::move(m_next_marker);
@@ -136,32 +136,32 @@ namespace azure { namespace storage { namespace protocol {
{
}
- web::http::uri uri()
+ web::http::uri move_uri()
{
return std::move(m_uri);
}
- utility::string_t name()
+ utility::string_t move_name()
{
return std::move(m_name);
}
- utility::string_t snapshot_time()
+ utility::string_t move_snapshot_time()
{
return std::move(m_snapshot_time);
}
- cloud_metadata metadata()
+ cloud_metadata move_metadata()
{
return std::move(m_metadata);
}
- cloud_blob_properties properties()
+ cloud_blob_properties move_properties()
{
return std::move(m_properties);
}
- copy_state copy_state()
+ copy_state move_copy_state()
{
return std::move(m_copy_state);
}
@@ -185,12 +185,12 @@ namespace azure { namespace storage { namespace protocol {
{
}
- web::http::uri uri()
+ web::http::uri move_uri()
{
return std::move(m_uri);
}
- utility::string_t name()
+ utility::string_t move_name()
{
return std::move(m_name);
}
@@ -210,19 +210,19 @@ namespace azure { namespace storage { namespace protocol {
{
}
- std::vector extract_blob_items()
+ std::vector move_blob_items()
{
parse();
return std::move(m_blob_items);
}
- std::vector extract_blob_prefix_items()
+ std::vector move_blob_prefix_items()
{
parse();
return std::move(m_blob_prefix_items);
}
- utility::string_t extract_next_marker()
+ utility::string_t move_next_marker()
{
parse();
return std::move(m_next_marker);
@@ -257,7 +257,7 @@ namespace azure { namespace storage { namespace protocol {
}
// Extracts the result. This method can only be called once on this reader
- std::vector extract_result()
+ std::vector move_result()
{
parse();
return std::move(m_page_list);
@@ -283,7 +283,7 @@ namespace azure { namespace storage { namespace protocol {
}
// Extracts the result. This method can only be called once on this reader
- std::vector extract_result()
+ std::vector move_result()
{
parse();
return std::move(m_block_list);
@@ -325,7 +325,7 @@ namespace azure { namespace storage { namespace protocol {
{
}
- shared_access_policies extract_policies()
+ shared_access_policies move_policies()
{
parse();
return std::move(m_policies);
@@ -427,12 +427,12 @@ namespace azure { namespace storage { namespace protocol {
{
}
- utility::string_t name()
+ utility::string_t move_name()
{
return std::move(m_name);
}
- cloud_metadata metadata()
+ cloud_metadata move_metadata()
{
return std::move(m_metadata);
}
@@ -452,13 +452,13 @@ namespace azure { namespace storage { namespace protocol {
{
}
- std::vector extract_items()
+ std::vector move_items()
{
parse();
return std::move(m_items);
}
- utility::string_t extract_next_marker()
+ utility::string_t move_next_marker()
{
parse();
return std::move(m_next_marker);
@@ -466,7 +466,6 @@ namespace azure { namespace storage { namespace protocol {
protected:
- virtual void handle_begin_element(const utility::string_t& element_name);
virtual void handle_element(const utility::string_t& element_name);
virtual void handle_end_element(const utility::string_t& element_name);
@@ -486,17 +485,17 @@ namespace azure { namespace storage { namespace protocol {
{
}
- utility::string_t content()
+ utility::string_t move_content()
{
return std::move(m_content);
}
- utility::string_t id()
+ utility::string_t move_id()
{
return std::move(m_id);
}
- utility::string_t pop_receipt()
+ utility::string_t move_pop_receipt()
{
return std::move(m_pop_receipt);
}
@@ -537,11 +536,11 @@ namespace azure { namespace storage { namespace protocol {
public:
explicit message_reader(concurrency::streams::istream stream)
- : xml_reader(stream)
+ : xml_reader(stream), m_dequeue_count(0)
{
}
- std::vector extract_items()
+ std::vector move_items()
{
parse();
return std::move(m_items);
@@ -549,7 +548,6 @@ namespace azure { namespace storage { namespace protocol {
protected:
- virtual void handle_begin_element(const utility::string_t& element_name);
virtual void handle_element(const utility::string_t& element_name);
virtual void handle_end_element(const utility::string_t& element_name);
@@ -580,11 +578,11 @@ namespace azure { namespace storage { namespace protocol {
public:
explicit service_properties_reader(concurrency::streams::istream stream)
- : xml_reader(stream), m_current_retention_policy_days(0)
+ : xml_reader(stream), m_current_retention_policy_days(0), m_current_retention_policy_enabled(false)
{
}
- service_properties extract_properties()
+ service_properties move_properties()
{
parse();
return std::move(m_service_properties);
@@ -634,7 +632,7 @@ namespace azure { namespace storage { namespace protocol {
{
}
- service_stats extract_stats()
+ service_stats move_stats()
{
parse();
return std::move(m_service_stats);
diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/streambuf.h b/Microsoft.WindowsAzure.Storage/includes/wascore/streambuf.h
index 05d9657b..b3cb4796 100644
--- a/Microsoft.WindowsAzure.Storage/includes/wascore/streambuf.h
+++ b/Microsoft.WindowsAzure.Storage/includes/wascore/streambuf.h
@@ -20,7 +20,7 @@
#include "cpprest/streams.h"
#include "wascore/basic_types.h"
-#include "resources.h"
+#include "hashing.h"
namespace azure { namespace storage { namespace core {
@@ -28,6 +28,10 @@ namespace azure { namespace storage { namespace core {
class basic_istreambuf : public concurrency::streams::details::streambuf_state_manager<_CharType>
{
public:
+ typedef typename concurrency::streams::details::streambuf_state_manager<_CharType>::traits traits;
+ typedef typename concurrency::streams::details::streambuf_state_manager<_CharType>::int_type int_type;
+ typedef typename concurrency::streams::details::streambuf_state_manager<_CharType>::pos_type pos_type;
+ typedef typename concurrency::streams::details::streambuf_state_manager<_CharType>::off_type off_type;
basic_istreambuf()
: concurrency::streams::details::streambuf_state_manager<_CharType>(std::ios_base::in)
@@ -68,6 +72,10 @@ namespace azure { namespace storage { namespace core {
class basic_ostreambuf : public concurrency::streams::details::streambuf_state_manager<_CharType>
{
public:
+ typedef typename concurrency::streams::details::streambuf_state_manager<_CharType>::traits traits;
+ typedef typename concurrency::streams::details::streambuf_state_manager<_CharType>::int_type int_type;
+ typedef typename concurrency::streams::details::streambuf_state_manager<_CharType>::pos_type pos_type;
+ typedef typename concurrency::streams::details::streambuf_state_manager<_CharType>::off_type off_type;
basic_ostreambuf()
: concurrency::streams::details::streambuf_state_manager<_CharType>(std::ios_base::out)
@@ -138,12 +146,17 @@ namespace azure { namespace storage { namespace core {
};
template
- class basic_splitter_streambuf : public basic_ostreambuf<_CharType>
+ class basic_hash_wrapper_streambuf : public basic_ostreambuf<_CharType>
{
public:
+ typedef _CharType char_type;
+ typedef typename basic_ostreambuf<_CharType>::traits traits;
+ typedef typename basic_ostreambuf<_CharType>::int_type int_type;
+ typedef typename basic_ostreambuf<_CharType>::pos_type pos_type;
+ typedef typename basic_ostreambuf<_CharType>::off_type off_type;
- basic_splitter_streambuf(concurrency::streams::streambuf<_CharType> streambuf1, concurrency::streams::streambuf<_CharType> streambuf2)
- : basic_ostreambuf<_CharType>(), m_streambuf1(streambuf1), m_streambuf2(streambuf2), m_total_written(0)
+ basic_hash_wrapper_streambuf(concurrency::streams::streambuf<_CharType> inner_streambuf, hash_provider provider)
+ : basic_ostreambuf<_CharType>(), m_inner_streambuf(inner_streambuf), m_hash_provider(provider), m_total_written(0)
{
}
@@ -209,259 +222,51 @@ namespace azure { namespace storage { namespace core {
pplx::task _sync()
{
- auto streambuf2 = m_streambuf2;
- return m_streambuf1.sync().then([streambuf2] () mutable -> pplx::task
+ return m_inner_streambuf.sync().then([]() -> bool
{
- return streambuf2.sync().then([] () -> bool
- {
- return true;
- });
+ return true;
});
}
pplx::task _close_write()
{
- basic_ostreambuf<_CharType>::_close_write();
- auto streambuf2 = m_streambuf2;
- return m_streambuf1.close(std::ios_base::out).then([streambuf2] () mutable -> pplx::task
- {
- return streambuf2.close(std::ios_base::out);
- });
+ m_hash_provider.close();
+ return m_inner_streambuf.close(std::ios_base::out);
}
pplx::task _putc(char_type ch)
{
- m_total_written++;
- auto streambuf2 = m_streambuf2;
- return m_streambuf1.putc(ch).then([streambuf2, ch] (int_type result1) mutable -> pplx::task
- {
- return streambuf2.putc(ch).then([result1] (int_type result2) -> int_type
- {
- if (result1 != result2)
- {
- throw;
- }
-
- return result1;
- });
- });
- }
-
- pplx::task _putn(const char_type* ptr, size_t count)
- {
- m_total_written += count;
- auto streambuf2 = m_streambuf2;
- return m_streambuf1.putn(ptr, count).then([streambuf2, ptr, count] (size_t result1) mutable -> pplx::task
- {
- return streambuf2.putn(ptr, count).then([result1] (size_t result2) -> size_t
- {
- if (result1 != result2)
- {
- throw;
- }
-
- return result1;
- });
- });
- }
-
- utility::size64_t total_written() const
- {
- return m_total_written;
- }
-
- private:
-
- concurrency::streams::streambuf<_CharType> m_streambuf1;
- concurrency::streams::streambuf<_CharType> m_streambuf2;
- utility::size64_t m_total_written;
- };
-
- template
- class basic_null_streambuf : public basic_ostreambuf<_CharType>
- {
- public:
-
- basic_null_streambuf()
- : basic_ostreambuf<_CharType>()
- {
- }
-
- bool can_seek() const
- {
- return false;
- }
-
- bool has_size() const
- {
- return false;
- }
-
- utility::size64_t size() const
- {
- return (utility::size64_t)0;
- }
-
- size_t buffer_size(std::ios_base::openmode direction) const
- {
- UNREFERENCED_PARAMETER(direction);
- return (size_t)0;
- }
-
- void set_buffer_size(size_t size, std::ios_base::openmode direction)
- {
- UNREFERENCED_PARAMETER(size);
- UNREFERENCED_PARAMETER(direction);
- }
-
- pos_type getpos(std::ios_base::openmode direction) const
- {
- UNREFERENCED_PARAMETER(direction);
- return (pos_type)traits::eof();
- }
-
- pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode direction)
- {
- UNREFERENCED_PARAMETER(offset);
- UNREFERENCED_PARAMETER(way);
- UNREFERENCED_PARAMETER(direction);
- return (pos_type)traits::eof();
- }
-
- pos_type seekpos(pos_type pos, std::ios_base::openmode direction)
- {
- UNREFERENCED_PARAMETER(pos);
- UNREFERENCED_PARAMETER(direction);
- return (pos_type)traits::eof();
- }
-
- char_type* _alloc(_In_ size_t count)
- {
- UNREFERENCED_PARAMETER(count);
- return nullptr;
- }
-
- void _commit(_In_ size_t count)
- {
- UNREFERENCED_PARAMETER(count);
- // no-op, as hash streams do not support alloc/commit
- }
-
- pplx::task _sync()
- {
- return pplx::task_from_result(true);
- }
+ // TODO: Consider updating the length and MD5 hash only after writing the data in case writing fails (in a task continuation)
+ ++m_total_written;
+ m_hash_provider.write(&ch, 1);
- pplx::task _close_write()
- {
- return basic_ostreambuf<_CharType>::_close_write();
- }
-
- pplx::task _putc(char_type ch)
- {
- return pplx::task_from_result((int_type)ch);
+ return m_inner_streambuf.putc(ch);
}
pplx::task _putn(const char_type* ptr, size_t count)
{
- UNREFERENCED_PARAMETER(ptr);
- return pplx::task_from_result(count);
- }
- };
-
- class basic_hash_streambuf : public basic_ostreambuf
- {
- public:
-
- basic_hash_streambuf()
- : basic_ostreambuf()
- {
- }
-
- bool can_seek() const
- {
- return false;
- }
-
- bool has_size() const
- {
- return false;
- }
-
- utility::size64_t size() const
- {
- return (utility::size64_t)0;
- }
-
- size_t buffer_size(std::ios_base::openmode direction) const
- {
- UNREFERENCED_PARAMETER(direction);
- return (size_t)0;
- }
-
- void set_buffer_size(size_t size, std::ios_base::openmode direction)
- {
- UNREFERENCED_PARAMETER(size);
- UNREFERENCED_PARAMETER(direction);
- }
-
- pos_type getpos(std::ios_base::openmode direction) const
- {
- UNREFERENCED_PARAMETER(direction);
- return (pos_type)traits::eof();
- }
-
- pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode direction)
- {
- UNREFERENCED_PARAMETER(offset);
- UNREFERENCED_PARAMETER(way);
- UNREFERENCED_PARAMETER(direction);
- return (pos_type)traits::eof();
- }
-
- pos_type seekpos(pos_type pos, std::ios_base::openmode direction)
- {
- UNREFERENCED_PARAMETER(pos);
- UNREFERENCED_PARAMETER(direction);
- return (pos_type)traits::eof();
- }
+ // TODO: Consider updating the length and MD5 hash only after writing the data in case writing fails (in a task continuation)
+ m_total_written += count;
+ m_hash_provider.write(ptr, count);
- char_type* _alloc(_In_ size_t count)
- {
- UNREFERENCED_PARAMETER(count);
- return nullptr;
+ return m_inner_streambuf.putn(ptr, count);
}
- void _commit(_In_ size_t count)
+ utility::string_t hash() const
{
- UNREFERENCED_PARAMETER(count);
- // no-op, as hash streams do not support alloc/commit
+ return m_hash_provider.hash();
}
- pplx::task _sync()
- {
- return pplx::task_from_result(true);
- }
-
- const std::vector& hash() const
+ utility::size64_t total_written() const
{
- if (is_open())
- {
- throw std::logic_error(protocol::error_hash_on_closed_streambuf);
- }
-
- return m_hash;
+ return m_total_written;
}
- protected:
+ private:
- void store_and_throw(std::exception_ptr e)
- {
- m_currentException = e;
- std::rethrow_exception(e);
- }
-
- std::vector m_hash;
+ concurrency::streams::streambuf<_CharType> m_inner_streambuf;
+ hash_provider m_hash_provider;
+ utility::size64_t m_total_written;
};
}}} // namespace azure::storage::core
diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/streams.h b/Microsoft.WindowsAzure.Storage/includes/wascore/streams.h
index 351d1698..c3b8b50a 100644
--- a/Microsoft.WindowsAzure.Storage/includes/wascore/streams.h
+++ b/Microsoft.WindowsAzure.Storage/includes/wascore/streams.h
@@ -20,85 +20,33 @@
#include "wascore/basic_types.h"
#include "streambuf.h"
-#ifdef WIN32
-#include "hash_windows.h"
-#else
-#include "hash_linux.h"
-#endif
-
namespace azure { namespace storage { namespace core {
template
- class splitter_streambuf : public concurrency::streams::streambuf<_CharType>
+ class hash_wrapper_streambuf : public concurrency::streams::streambuf<_CharType>
{
public:
- splitter_streambuf()
+ hash_wrapper_streambuf()
: concurrency::streams::streambuf<_CharType>()
{
}
- splitter_streambuf(concurrency::streams::streambuf<_CharType> streambuf1, concurrency::streams::streambuf<_CharType> streambuf2)
- : concurrency::streams::streambuf<_CharType>(std::make_shared>(streambuf1, streambuf2))
+ hash_wrapper_streambuf(concurrency::streams::streambuf<_CharType> inner_streambuf, hash_provider provider)
+ : concurrency::streams::streambuf<_CharType>(std::make_shared>(inner_streambuf, provider))
{
}
utility::size64_t total_written() const
{
- auto base = static_cast*>(get_base().get());
+ const basic_hash_wrapper_streambuf<_CharType>* base = static_cast*>(Concurrency::streams::streambuf<_CharType>::get_base().get());
return base->total_written();
}
- };
- template
- class null_streambuf : public concurrency::streams::streambuf<_CharType>
- {
- public:
-
- null_streambuf()
- : concurrency::streams::streambuf<_CharType>(std::make_shared>())
+ utility::string_t hash() const
{
- }
- };
-
- class hash_streambuf : public concurrency::streams::streambuf
- {
- public:
-
- hash_streambuf()
- : concurrency::streams::streambuf()
- {
- }
-
- explicit hash_streambuf(const std::shared_ptr &ptr)
- : concurrency::streams::streambuf(ptr)
- {
- }
-
- const std::vector& hash() const
- {
- auto base = static_cast(get_base().get());
+ const basic_hash_wrapper_streambuf<_CharType>* base = static_cast*>(Concurrency::streams::streambuf<_CharType>::get_base().get());
return base->hash();
}
};
- class hash_hmac_sha256_streambuf : public hash_streambuf
- {
- public:
-
- explicit hash_hmac_sha256_streambuf(std::vector key)
- : hash_streambuf(std::make_shared(std::move(key)))
- {
- }
- };
-
- class hash_md5_streambuf : public hash_streambuf
- {
- public:
-
- hash_md5_streambuf()
- : hash_streambuf(std::make_shared())
- {
- }
- };
-
}}} // namespace azure::storage::core
diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/xmlhelpers.h b/Microsoft.WindowsAzure.Storage/includes/wascore/xmlhelpers.h
index 10accbc4..aad0fe7a 100644
--- a/Microsoft.WindowsAzure.Storage/includes/wascore/xmlhelpers.h
+++ b/Microsoft.WindowsAzure.Storage/includes/wascore/xmlhelpers.h
@@ -54,6 +54,7 @@
#include
#include "cpprest/basic_types.h"
+#include "was/core.h"
namespace azure { namespace storage { namespace core { namespace xml {
diff --git a/Microsoft.WindowsAzure.Storage/packages.config b/Microsoft.WindowsAzure.Storage/packages.config
index a7574f84..9e4930c4 100644
--- a/Microsoft.WindowsAzure.Storage/packages.config
+++ b/Microsoft.WindowsAzure.Storage/packages.config
@@ -1,4 +1,8 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Application.cpp b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Application.cpp
index 15560df0..92b0dd59 100644
--- a/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Application.cpp
+++ b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Application.cpp
@@ -40,7 +40,9 @@ namespace azure { namespace storage { namespace samples {
// Create a blob container
azure::storage::cloud_blob_client blob_client = storage_account.create_cloud_blob_client();
azure::storage::cloud_blob_container container = blob_client.get_container_reference(U("my-sample-container"));
- bool created = container.create_if_not_exists();
+
+ // Return value is true if the container did not exist and was successfully created.
+ container.create_if_not_exists();
// Make the blob container publicly accessible
azure::storage::blob_container_permissions permissions;
@@ -96,7 +98,8 @@ namespace azure { namespace storage { namespace samples {
blob3.delete_blob();
// Delete the blob container
- bool deleted = container.delete_container_if_exists();
+ // Return value is true if the container did exist and was successfully deleted.
+ container.delete_container_if_exists();
}
catch (const azure::storage::storage_exception& e)
{
@@ -117,7 +120,7 @@ namespace azure { namespace storage { namespace samples {
}}} // namespace azure::storage::samples
-int _tmain(int argc, _TCHAR *argv[])
+int main(int argc, const char *argv[])
{
azure::storage::samples::blobs_getting_started_sample();
return 0;
diff --git a/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/CMakeLists.txt b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/CMakeLists.txt
new file mode 100644
index 00000000..6b8f6b1f
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/CMakeLists.txt
@@ -0,0 +1,57 @@
+include_directories(../../includes ${CASABLANCA_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${LibXML++_INCLUDE_DIRS})
+
+# THE ORDER OF FILES IS VERY /VERY/ IMPORTANT
+if(UNIX)
+ set(SOURCES
+ Application.cpp
+ stdafx.cpp
+ )
+ if(APPLE)
+ # set(SOURCES ${SOURCES} apple.cpp)
+ find_library(COREFOUNDATION CoreFoundation "/")
+ set(EXTRALINKS ${COREFOUNDATION})
+ else()
+ # set(SOURCES ${SOURCES} linux.cpp)
+ endif()
+elseif(WIN32)
+ set(SOURCES
+ Application.cpp
+ stdafx.cpp
+ )
+ add_definitions(
+ -D_ASYNCRT_EXPORT
+ -DAZURESTORAGESERVICES_EXPORTS
+ -D_PPLX_EXPORT
+ -DWIN32
+ -D_MBCS
+ -D_USRDLL
+ )
+ set(EXTRALINKS Httpapi.lib Winhttp.dll)
+endif()
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} -Werror -pedantic")
+
+add_executable(${AZURESTORAGESAMPLES_BLOBS} ${SOURCES})
+
+target_link_libraries(${AZURESTORAGESAMPLES_BLOBS}
+ ${AZURESTORAGESAMPLES_COMMON}
+ ${AZURE_STORAGE_LIBRARY}
+ ${UUID_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${CASABLANCA_LIBRARY}
+ ${Boost_LIBRARIES}
+ ${Boost_FRAMEWORK}
+ ${LibXML++_LIBRARIES}
+ ${COREFOUNDATION}
+ ${EXTRALINKS}
+ )
+
+# Portions specific to cpprest binary versioning.
+if(WIN32)
+ set_target_properties(${AZURESTORAGESAMPLES_BLOBS} PROPERTIES
+ OUTPUT_NAME "${AZURESTORAGESAMPLES_BLOBS}")
+else()
+ set_target_properties(${AZURESTORAGESAMPLES_BLOBS} PROPERTIES
+ SOVERSION ${AZURESTORAGE_VERSION_MAJOR}.${AZURESTORAGE_VERSION_MINOR})
+endif()
+
diff --git a/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Microsoft.WindowsAzure.Storage.BlobsGettingStarted.v120.vcxproj b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Microsoft.WindowsAzure.Storage.BlobsGettingStarted.v120.vcxproj
index 5da77117..8d618a22 100644
--- a/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Microsoft.WindowsAzure.Storage.BlobsGettingStarted.v120.vcxproj
+++ b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Microsoft.WindowsAzure.Storage.BlobsGettingStarted.v120.vcxproj
@@ -1,6 +1,7 @@
-
+
+
Debug
@@ -115,6 +116,10 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Microsoft.WindowsAzure.Storage.BlobsGettingStarted.vcxproj b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Microsoft.WindowsAzure.Storage.BlobsGettingStarted.vcxproj
index fabd34c2..e7021fe1 100644
--- a/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Microsoft.WindowsAzure.Storage.BlobsGettingStarted.vcxproj
+++ b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/Microsoft.WindowsAzure.Storage.BlobsGettingStarted.vcxproj
@@ -1,6 +1,7 @@
-
+
+
Debug
@@ -115,6 +116,10 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/packages.config b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/packages.config
index a7574f84..9e4930c4 100644
--- a/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/packages.config
+++ b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/packages.config
@@ -1,4 +1,8 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/stdafx.h b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/stdafx.h
index 8ee7a2c9..e52a6520 100644
--- a/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/stdafx.h
+++ b/Microsoft.WindowsAzure.Storage/samples/BlobsGettingStarted/stdafx.h
@@ -24,7 +24,5 @@
#include "targetver.h"
-#include
-
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
diff --git a/Microsoft.WindowsAzure.Storage/samples/CMakeLists.txt b/Microsoft.WindowsAzure.Storage/samples/CMakeLists.txt
new file mode 100644
index 00000000..f63ad50a
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/samples/CMakeLists.txt
@@ -0,0 +1,110 @@
+set(CMAKE_LEGACY_CYGWIN_WIN32 0)
+cmake_minimum_required(VERSION 2.6)
+project(azurestoragesamples)
+
+enable_testing()
+
+set(WARNINGS)
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/../cmake/Modules/")
+
+# Platform (not compiler) specific settings
+if(IOS)
+ set(IOS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/../../Build_iOS")
+ set(Boost_FRAMEWORK "-F ${IOS_SOURCE_DIR} -framework boost")
+ set(Boost_INCLUDE_DIR "${IOS_SOURCE_DIR}/boost.framework/Headers")
+
+ set(OPENSSL_FOUND 1)
+ set(OPENSSL_INCLUDE_DIR "${IOS_SOURCE_DIR}/openssl/include")
+ set(OPENSSL_LIBRARIES
+ "${IOS_SOURCE_DIR}/openssl/lib/libcrypto.a"
+ "${IOS_SOURCE_DIR}/openssl/lib/libssl.a"
+ )
+
+ set(CASABLANCA_INCLUDE_DIR "${IOS_SOURCE_DIR}/casablanca/include")
+ set(CASABLANCA_LIBRARY "${IOS_SOURCE_DIR}/casablanca/lib/libcasablanca.a")
+
+ # The cxx_flags must be set here, because the ios-cmake toolchain file unfortunately sets "-headerpad_max_install_names" which is not a valid clang flag.
+ set(CMAKE_CXX_FLAGS "-fvisibility=hidden -fvisibility-inlines-hidden")
+
+ set(BUILD_SHARED_LIBS OFF)
+elseif(UNIX) # This includes OSX
+ find_package(Boost REQUIRED COMPONENTS log log_setup random system thread locale regex filesystem)
+ find_package(Threads REQUIRED)
+ find_package(OpenSSL REQUIRED)
+ find_package(LibXML++ REQUIRED)
+ find_package(UUID REQUIRED)
+ find_package(Casablanca REQUIRED)
+
+ set(AZURE_STORAGE_SOURCE_DIR "${CMAKE_SOURCE_DIR}/..")
+ set(AZURE_STORAGE_INCLUDE_DIR "${AZURE_STORAGE_SOURCE_DIR}/includes")
+ set(AZURE_STORAGE_LIBRARY "${AZURE_STORAGE_SOURCE_DIR}/build.release/Binaries/libazurestorage.so")
+
+ option(BUILD_SHARED_LIBS "Build shared Libraries." ON)
+elseif(WIN32)
+ option(BUILD_SHARED_LIBS "Build shared Libraries." ON)
+
+ add_definitions(-DUNICODE)
+
+ if(NOT BUILD_SHARED_LIBS)
+ # This causes cmake to not link the test libraries separately, but instead hold onto their object files.
+ set(TEST_LIBRARY_TARGET_TYPE OBJECT)
+ endif()
+
+ set(LIB lib)
+else()
+ message("-- Unsupported Build Platform.")
+endif()
+
+# Compiler (not platform) specific settings
+if(("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR IOS)
+ message("-- Setting clang options")
+
+ set(WARNINGS "-Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls")
+ set(OSX_SUPPRESSIONS "-Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder")
+ set(WARNINGS "${WARNINGS} ${OSX_SUPPRESSIONS}")
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration")
+ set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
+ set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing")
+ set(STRICT_CXX_FLAGS ${WARNINGS} "-Werror -pedantic")
+elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
+ message("-- Setting gcc options")
+
+ set(WARNINGS "-Wall -Wextra -Wunused-parameter -Wcast-align -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wunreachable-code")
+ set(LINUX_SUPPRESSIONS "-Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-unused-function -Wno-char-subscripts -Wno-switch -Wno-unused-but-set-parameter -Wno-unused-value -Wno-unused-local-typedefs -Wno-unused-parameter")
+
+ set(WARNINGS "${WARNINGS} ${LINUX_SUPPRESSIONS}")
+ set(LD_FLAGS "${LD_FLAGS} -Wl,-z,defs")
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing")
+ set(STRICT_CXX_FLAGS ${WARNINGS} "-Werror -pedantic")
+ add_definitions(-DBOOST_LOG_DYN_LINK)
+else()
+ message("-- Unknown compiler, success is doubtful.")
+endif()
+
+# Reconfigure final output directory
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
+
+set(AZURESTORAGESAMPLES_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/SamplesCommon)
+set(AZURESTORAGESAMPLES_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/SamplesCommon ${AZURE_STORAGE_INCLUDE_DIR} ${CASABLANCA_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${LibXML++_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS})
+
+set(AZURESTORAGESAMPLES_COMMON samplescommon)
+set(AZURESTORAGESAMPLES_BLOBS samplesblobs)
+set(AZURESTORAGESAMPLES_JSON samplesjson)
+set(AZURESTORAGESAMPLES_TABLES samplestables)
+set(AZURESTORAGESAMPLES_QUEUES samplesqueues)
+set(AZURESTORAGESAMPLES_LIBRARIES ${AZURESTORAGESAMPLES_COMMON} ${AZURESTORAGE_LIBRARY} ${CASABLANCA_LIBRARY} ${Boost_LIBRARIES} ${Boost_FRAMEWORK} ${OPENSSL_LIBRARIES} ${LibXML++_LIBRARIES} ${UUID_LIBRARIES})
+
+include_directories(${AZURESTORAGESAMPLES_INCLUDE_DIRS})
+
+add_subdirectory(SamplesCommon)
+add_subdirectory(BlobsGettingStarted)
+add_subdirectory(JsonPayloadFormat)
+add_subdirectory(QueuesGettingStarted)
+add_subdirectory(TablesGettingStarted)
diff --git a/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Application.cpp b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Application.cpp
index a89db644..1a978c77 100644
--- a/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Application.cpp
+++ b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Application.cpp
@@ -33,7 +33,9 @@ namespace azure { namespace storage { namespace samples {
// Create a table
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
azure::storage::cloud_table table = table_client.get_table_reference(U("MySampleTable"));
- bool created = table.create_if_not_exists();
+
+ // Return value is true if the table did not exist and was successfully created.
+ table.create_if_not_exists();
// Insert some table entities
azure::storage::table_batch_operation batch_operation;
@@ -47,7 +49,7 @@ namespace azure { namespace storage { namespace samples {
properties[U("DateTimeProperty")] = azure::storage::entity_property(utility::datetime::utc_now());
properties[U("GuidProperty")] = azure::storage::entity_property(utility::new_uuid());
properties[U("Int32Property")] = azure::storage::entity_property(1234567890);
- properties[U("Int64Property")] = azure::storage::entity_property(1234567890123456789LL);
+ properties[U("Int64Property")] = azure::storage::entity_property((int64_t) 1234567890123456789LL);
properties[U("DoubleProperty")] = azure::storage::entity_property(9.1234567890123456789);
properties[U("BooleanProperty")] = azure::storage::entity_property(true);
properties[U("BinaryProperty")] = azure::storage::entity_property(std::vector(10, 'X'));
@@ -87,7 +89,8 @@ namespace azure { namespace storage { namespace samples {
}
// Delete the table
- bool deleted = table.delete_table_if_exists();
+ // Return value is true if the table did exist and was successfully deleted.
+ table.delete_table_if_exists();
}
catch (const azure::storage::storage_exception& e)
{
@@ -108,7 +111,7 @@ namespace azure { namespace storage { namespace samples {
}}} // namespace azure::storage::samples
-int _tmain(int argc, _TCHAR *argv[])
+int main(int argc, const char *argv[])
{
azure::storage::samples::tables_getting_started_sample();
return 0;
diff --git a/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/CMakeLists.txt b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/CMakeLists.txt
new file mode 100644
index 00000000..0bd64a3f
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/CMakeLists.txt
@@ -0,0 +1,57 @@
+include_directories(../../includes ${CASABLANCA_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${LibXML++_INCLUDE_DIRS})
+
+# THE ORDER OF FILES IS VERY /VERY/ IMPORTANT
+if(UNIX)
+ set(SOURCES
+ Application.cpp
+ stdafx.cpp
+ )
+ if(APPLE)
+ # set(SOURCES ${SOURCES} apple.cpp)
+ find_library(COREFOUNDATION CoreFoundation "/")
+ set(EXTRALINKS ${COREFOUNDATION})
+ else()
+ # set(SOURCES ${SOURCES} linux.cpp)
+ endif()
+elseif(WIN32)
+ set(SOURCES
+ Application.cpp
+ stdafx.cpp
+ )
+ add_definitions(
+ -D_ASYNCRT_EXPORT
+ -DAZURESTORAGESERVICES_EXPORTS
+ -D_PPLX_EXPORT
+ -DWIN32
+ -D_MBCS
+ -D_USRDLL
+ )
+ set(EXTRALINKS Httpapi.lib Winhttp.dll)
+endif()
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} -Werror -pedantic")
+
+add_executable(${AZURESTORAGESAMPLES_JSON} ${SOURCES})
+
+target_link_libraries(${AZURESTORAGESAMPLES_JSON}
+ ${AZURESTORAGESAMPLES_COMMON}
+ ${AZURE_STORAGE_LIBRARY}
+ ${UUID_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${CASABLANCA_LIBRARY}
+ ${Boost_LIBRARIES}
+ ${Boost_FRAMEWORK}
+ ${LibXML++_LIBRARIES}
+ ${COREFOUNDATION}
+ ${EXTRALINKS}
+ )
+
+# Portions specific to cpprest binary versioning.
+if(WIN32)
+ set_target_properties(${AZURESTORAGESAMPLES_JSON} PROPERTIES
+ OUTPUT_NAME "${AZURESTORAGESAMPLES_JSON}")
+else()
+ set_target_properties(${AZURESTORAGESAMPLES_JSON} PROPERTIES
+ SOVERSION ${AZURESTORAGE_VERSION_MAJOR}.${AZURESTORAGE_VERSION_MINOR})
+endif()
+
diff --git a/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Microsoft.WindowsAzure.Storage.JsonPayloadFormat.v120.vcxproj b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Microsoft.WindowsAzure.Storage.JsonPayloadFormat.v120.vcxproj
index 5007e730..935a6bbd 100644
--- a/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Microsoft.WindowsAzure.Storage.JsonPayloadFormat.v120.vcxproj
+++ b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Microsoft.WindowsAzure.Storage.JsonPayloadFormat.v120.vcxproj
@@ -1,6 +1,7 @@
-
+
+
Debug
@@ -110,6 +111,10 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Microsoft.WindowsAzure.Storage.JsonPayloadFormat.vcxproj b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Microsoft.WindowsAzure.Storage.JsonPayloadFormat.vcxproj
index bcd4069b..3c2c1b2d 100644
--- a/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Microsoft.WindowsAzure.Storage.JsonPayloadFormat.vcxproj
+++ b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/Microsoft.WindowsAzure.Storage.JsonPayloadFormat.vcxproj
@@ -1,6 +1,7 @@
-
+
+
Debug
@@ -110,6 +111,10 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/packages.config b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/packages.config
index a7574f84..9e4930c4 100644
--- a/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/packages.config
+++ b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/packages.config
@@ -1,4 +1,8 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/stdafx.h b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/stdafx.h
index 8ee7a2c9..e52a6520 100644
--- a/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/stdafx.h
+++ b/Microsoft.WindowsAzure.Storage/samples/JsonPayloadFormat/stdafx.h
@@ -24,7 +24,5 @@
#include "targetver.h"
-#include
-
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
diff --git a/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Application.cpp b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Application.cpp
index e4d954c8..4e2cdbe1 100644
--- a/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Application.cpp
+++ b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Application.cpp
@@ -33,7 +33,9 @@ namespace azure { namespace storage { namespace samples {
// Create a queue
azure::storage::cloud_queue_client queue_client = storage_account.create_cloud_queue_client();
azure::storage::cloud_queue queue = queue_client.get_queue_reference(U("my-sample-queue"));
- bool created = queue.create_if_not_exists();
+
+ // Return value is true if the queue did not exist and was successfully created.
+ queue.create_if_not_exists();
// Insert some queue messages
azure::storage::cloud_queue_message message1(U("some message"));
@@ -76,10 +78,11 @@ namespace azure { namespace storage { namespace samples {
// Get the approximate queue size
queue.download_attributes();
- int message_count = queue.approximate_message_count();
+ ucout << U("Approximate message count: ") << queue.approximate_message_count() << std::endl;
// Delete the queue
- bool deleted = queue.delete_queue_if_exists();
+ // Return value is true if the queue did exist and was succesfully deleted.
+ queue.delete_queue_if_exists();
}
catch (const azure::storage::storage_exception& e)
{
@@ -100,7 +103,7 @@ namespace azure { namespace storage { namespace samples {
}}} // namespace azure::storage::samples
-int _tmain(int argc, _TCHAR *argv[])
+int main(int argc, const char *argv[])
{
azure::storage::samples::queues_getting_started_sample();
return 0;
diff --git a/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/CMakeLists.txt b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/CMakeLists.txt
new file mode 100644
index 00000000..5be9734f
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/CMakeLists.txt
@@ -0,0 +1,57 @@
+include_directories(../../includes ${CASABLANCA_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${LibXML++_INCLUDE_DIRS})
+
+# THE ORDER OF FILES IS VERY /VERY/ IMPORTANT
+if(UNIX)
+ set(SOURCES
+ Application.cpp
+ stdafx.cpp
+ )
+ if(APPLE)
+ # set(SOURCES ${SOURCES} apple.cpp)
+ find_library(COREFOUNDATION CoreFoundation "/")
+ set(EXTRALINKS ${COREFOUNDATION})
+ else()
+ # set(SOURCES ${SOURCES} linux.cpp)
+ endif()
+elseif(WIN32)
+ set(SOURCES
+ Application.cpp
+ stdafx.cpp
+ )
+ add_definitions(
+ -D_ASYNCRT_EXPORT
+ -DAZURESTORAGESERVICES_EXPORTS
+ -D_PPLX_EXPORT
+ -DWIN32
+ -D_MBCS
+ -D_USRDLL
+ )
+ set(EXTRALINKS Httpapi.lib Winhttp.dll)
+endif()
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} -Werror -pedantic")
+
+add_executable(${AZURESTORAGESAMPLES_QUEUES} ${SOURCES})
+
+target_link_libraries(${AZURESTORAGESAMPLES_QUEUES}
+ ${AZURESTORAGESAMPLES_COMMON}
+ ${AZURE_STORAGE_LIBRARY}
+ ${UUID_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${CASABLANCA_LIBRARY}
+ ${Boost_LIBRARIES}
+ ${Boost_FRAMEWORK}
+ ${LibXML++_LIBRARIES}
+ ${COREFOUNDATION}
+ ${EXTRALINKS}
+ )
+
+# Portions specific to cpprest binary versioning.
+if(WIN32)
+ set_target_properties(${AZURESTORAGESAMPLES_QUEUES} PROPERTIES
+ OUTPUT_NAME "${AZURESTORAGESAMPLES_QUEUES}")
+else()
+ set_target_properties(${AZURESTORAGESAMPLES_QUEUES} PROPERTIES
+ SOVERSION ${AZURESTORAGE_VERSION_MAJOR}.${AZURESTORAGE_VERSION_MINOR})
+endif()
+
diff --git a/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Microsoft.WindowsAzure.Storage.QueuesGettingStarted.v120.vcxproj b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Microsoft.WindowsAzure.Storage.QueuesGettingStarted.v120.vcxproj
index d5d7718f..66201b26 100644
--- a/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Microsoft.WindowsAzure.Storage.QueuesGettingStarted.v120.vcxproj
+++ b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Microsoft.WindowsAzure.Storage.QueuesGettingStarted.v120.vcxproj
@@ -1,6 +1,7 @@
-
+
+
Debug
@@ -110,6 +111,10 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Microsoft.WindowsAzure.Storage.QueuesGettingStarted.vcxproj b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Microsoft.WindowsAzure.Storage.QueuesGettingStarted.vcxproj
index d305e8c5..9faff45a 100644
--- a/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Microsoft.WindowsAzure.Storage.QueuesGettingStarted.vcxproj
+++ b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/Microsoft.WindowsAzure.Storage.QueuesGettingStarted.vcxproj
@@ -1,6 +1,7 @@
-
+
+
Debug
@@ -110,6 +111,10 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/packages.config b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/packages.config
index a7574f84..9e4930c4 100644
--- a/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/packages.config
+++ b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/packages.config
@@ -1,4 +1,8 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/stdafx.h b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/stdafx.h
index 8ee7a2c9..e52a6520 100644
--- a/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/stdafx.h
+++ b/Microsoft.WindowsAzure.Storage/samples/QueuesGettingStarted/stdafx.h
@@ -24,7 +24,5 @@
#include "targetver.h"
-#include
-
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
diff --git a/Microsoft.WindowsAzure.Storage/samples/SamplesCommon/CMakeLists.txt b/Microsoft.WindowsAzure.Storage/samples/SamplesCommon/CMakeLists.txt
new file mode 100644
index 00000000..143ef44b
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/samples/SamplesCommon/CMakeLists.txt
@@ -0,0 +1,56 @@
+include_directories(../../includes ${CASABLANCA_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${LibXML++_INCLUDE_DIRS})
+
+# THE ORDER OF FILES IS VERY /VERY/ IMPORTANT
+if(UNIX)
+ set(SOURCES
+ stdafx.cpp
+ )
+ if(APPLE)
+ # set(SOURCES ${SOURCES} apple.cpp)
+ find_library(COREFOUNDATION CoreFoundation "/")
+ set(EXTRALINKS ${COREFOUNDATION})
+ else()
+ # set(SOURCES ${SOURCES} linux.cpp)
+ endif()
+elseif(WIN32)
+ set(SOURCES
+ stdafx.cpp
+ )
+ add_definitions(
+ -D_ASYNCRT_EXPORT
+ -DAZURESTORAGESERVICES_EXPORTS
+ -D_PPLX_EXPORT
+ -DWIN32
+ -D_MBCS
+ -D_USRDLL
+ )
+ set(EXTRALINKS Httpapi.lib Winhttp.dll)
+endif()
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} -Werror -pedantic")
+
+add_library(${AZURESTORAGESAMPLES_COMMON} ${SOURCES})
+
+target_link_libraries(${AZURESTORAGESAMPLES_COMMON}
+ ${AZURE_STORAGE_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${CASABLANCA_LIBRARY}
+ ${Boost_LIBRARIES}
+ ${Boost_FRAMEWORK}
+ ${LibXML++_LIBRARIES}
+ ${COREFOUNDATION}
+ ${EXTRALINKS}
+ )
+
+# Portions specific to cpprest binary versioning.
+set (AZURESTORAGESAMPLES_VERSION_MAJOR 0)
+set (AZURESTORAGESAMPLES_VERSION_MINOR 4)
+set (AZURESTORAGESAMPLES_VERSION_REVISION 0)
+if(WIN32)
+ set_target_properties(${AZURESTORAGESAMPLES_COMMON} PROPERTIES
+ OUTPUT_NAME "${AZURESTORAGESAMPLES_COMMON}_${AZURESTORAGESAMPLES_VERSION_MAJOR}_${AZURESTORAGESAMPLES_VERSION_MINOR}")
+else()
+ set_target_properties(${AZURESTORAGESAMPLES_COMMON} PROPERTIES
+ SOVERSION ${AZURESTORAGESAMPLES_VERSION_MAJOR}.${AZURESTORAGESAMPLES_VERSION_MINOR})
+endif()
+
diff --git a/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Application.cpp b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Application.cpp
index 8e649fc8..25e44d57 100644
--- a/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Application.cpp
+++ b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Application.cpp
@@ -33,7 +33,9 @@ namespace azure { namespace storage { namespace samples {
// Create a table
azure::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
azure::storage::cloud_table table = table_client.get_table_reference(U("MySampleTable"));
- bool created = table.create_if_not_exists();
+
+ // Return value is true if the table did not exist and was successfully created.
+ table.create_if_not_exists();
// Insert a table entity
azure::storage::table_entity entity(U("MyPartitionKey"), U("MyRowKey"));
@@ -43,7 +45,7 @@ namespace azure { namespace storage { namespace samples {
properties[U("DateTimeProperty")] = azure::storage::entity_property(utility::datetime::utc_now());
properties[U("GuidProperty")] = azure::storage::entity_property(utility::new_uuid());
properties[U("Int32Property")] = azure::storage::entity_property(1234567890);
- properties[U("Int64Property")] = azure::storage::entity_property(1234567890123456789LL);
+ properties[U("Int64Property")] = azure::storage::entity_property((int64_t) 1234567890123456789LL);
properties[U("DoubleProperty")] = azure::storage::entity_property(9.1234567890123456789);
properties[U("BooleanProperty")] = azure::storage::entity_property(true);
properties[U("BinaryProperty")] = azure::storage::entity_property(std::vector(10, 'X'));
@@ -75,7 +77,7 @@ namespace azure { namespace storage { namespace samples {
azure::storage::table_query query;
query.set_filter_string(azure::storage::table_query::combine_filter_conditions(
azure::storage::table_query::generate_filter_condition(U("PartitionKey"), azure::storage::query_comparison_operator::equal, U("MyPartitionKey")),
- azure::storage::query_logical_operator::and,
+ azure::storage::query_logical_operator::op_and,
azure::storage::table_query::generate_filter_condition(U("RowKey"), azure::storage::query_comparison_operator::greater_than_or_equal, U("MyRowKey5"))));
std::vector entities = table.execute_query(query);
for (std::vector::const_iterator it = entities.cbegin(); it != entities.cend(); ++it)
@@ -89,7 +91,8 @@ namespace azure { namespace storage { namespace samples {
azure::storage::table_result delete_result = table.execute(delete_operation);
// Delete the table
- bool deleted = table.delete_table_if_exists();
+ // Return value is true if the table did exist and was successfully deleted.
+ table.delete_table_if_exists();
}
catch (const azure::storage::storage_exception& e)
{
@@ -110,7 +113,7 @@ namespace azure { namespace storage { namespace samples {
}}} // namespace azure::storage::samples
-int _tmain(int argc, _TCHAR *argv[])
+int main(int argc, const char *argv[])
{
azure::storage::samples::tables_getting_started_sample();
return 0;
diff --git a/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/CMakeLists.txt b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/CMakeLists.txt
new file mode 100644
index 00000000..cf71b96d
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/CMakeLists.txt
@@ -0,0 +1,57 @@
+include_directories(../../includes ${CASABLANCA_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${LibXML++_INCLUDE_DIRS})
+
+# THE ORDER OF FILES IS VERY /VERY/ IMPORTANT
+if(UNIX)
+ set(SOURCES
+ Application.cpp
+ stdafx.cpp
+ )
+ if(APPLE)
+ # set(SOURCES ${SOURCES} apple.cpp)
+ find_library(COREFOUNDATION CoreFoundation "/")
+ set(EXTRALINKS ${COREFOUNDATION})
+ else()
+ # set(SOURCES ${SOURCES} linux.cpp)
+ endif()
+elseif(WIN32)
+ set(SOURCES
+ Application.cpp
+ stdafx.cpp
+ )
+ add_definitions(
+ -D_ASYNCRT_EXPORT
+ -DAZURESTORAGESERVICES_EXPORTS
+ -D_PPLX_EXPORT
+ -DWIN32
+ -D_MBCS
+ -D_USRDLL
+ )
+ set(EXTRALINKS Httpapi.lib Winhttp.dll)
+endif()
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} -Werror -pedantic")
+
+add_executable(${AZURESTORAGESAMPLES_TABLES} ${SOURCES})
+
+target_link_libraries(${AZURESTORAGESAMPLES_TABLES}
+ ${AZURESTORAGESAMPLES_COMMON}
+ ${AZURE_STORAGE_LIBRARY}
+ ${UUID_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${CASABLANCA_LIBRARY}
+ ${Boost_LIBRARIES}
+ ${Boost_FRAMEWORK}
+ ${LibXML++_LIBRARIES}
+ ${COREFOUNDATION}
+ ${EXTRALINKS}
+ )
+
+# Portions specific to cpprest binary versioning.
+if(WIN32)
+ set_target_properties(${AZURESTORAGESAMPLES_TABLES} PROPERTIES
+ OUTPUT_NAME "${AZURESTORAGESAMPLES_TABLES}")
+else()
+ set_target_properties(${AZURESTORAGESAMPLES_TABLES} PROPERTIES
+ SOVERSION ${AZURESTORAGE_VERSION_MAJOR}.${AZURESTORAGE_VERSION_MINOR})
+endif()
+
diff --git a/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Microsoft.WindowsAzure.Storage.TablesGettingStarted.v120.vcxproj b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Microsoft.WindowsAzure.Storage.TablesGettingStarted.v120.vcxproj
index 62e2d068..a0d2011e 100644
--- a/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Microsoft.WindowsAzure.Storage.TablesGettingStarted.v120.vcxproj
+++ b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Microsoft.WindowsAzure.Storage.TablesGettingStarted.v120.vcxproj
@@ -1,6 +1,7 @@
-
+
+
Debug
@@ -110,6 +111,10 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Microsoft.WindowsAzure.Storage.TablesGettingStarted.vcxproj b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Microsoft.WindowsAzure.Storage.TablesGettingStarted.vcxproj
index 55b56a53..6cbed763 100644
--- a/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Microsoft.WindowsAzure.Storage.TablesGettingStarted.vcxproj
+++ b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/Microsoft.WindowsAzure.Storage.TablesGettingStarted.vcxproj
@@ -1,6 +1,7 @@
-
+
+
Debug
@@ -110,6 +111,10 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/packages.config b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/packages.config
index a7574f84..9e4930c4 100644
--- a/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/packages.config
+++ b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/packages.config
@@ -1,4 +1,8 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/stdafx.h b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/stdafx.h
index 8ee7a2c9..e52a6520 100644
--- a/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/stdafx.h
+++ b/Microsoft.WindowsAzure.Storage/samples/TablesGettingStarted/stdafx.h
@@ -24,7 +24,5 @@
#include "targetver.h"
-#include
-
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
diff --git a/Microsoft.WindowsAzure.Storage/src/CMakeLists.txt b/Microsoft.WindowsAzure.Storage/src/CMakeLists.txt
new file mode 100644
index 00000000..00feb409
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/src/CMakeLists.txt
@@ -0,0 +1,135 @@
+include_directories(../includes ${CASABLANCA_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${LibXML++_INCLUDE_DIRS})
+
+# THE ORDER OF FILES IS VERY /VERY/ IMPORTANT
+if(UNIX)
+ set(SOURCES
+ xmlhelpers.cpp
+ response_parsers.cpp
+ request_result.cpp
+ request_factory.cpp
+ protocol_xml.cpp
+ navigation.cpp
+ async_semaphore.cpp
+ util.cpp
+ table_request_factory.cpp
+ table_response_parsers.cpp
+ table_query.cpp
+ entity_property.cpp
+ shared_access_signature.cpp
+ retry_policies.cpp
+ queue_request_factory.cpp
+ protocol_json.cpp
+ operation_context.cpp
+ mime_multipart_helper.cpp
+ logging.cpp
+ hashing.cpp
+ cloud_table_client.cpp
+ cloud_table.cpp
+ cloud_storage_account.cpp
+ cloud_queue_message.cpp
+ cloud_queue_client.cpp
+ cloud_queue.cpp
+ cloud_page_blob.cpp
+ cloud_core.cpp
+ cloud_client.cpp
+ cloud_block_blob.cpp
+ cloud_blob_directory.cpp
+ cloud_blob_container.cpp
+ cloud_blob_shared.cpp
+ cloud_blob_ostreambuf.cpp
+ cloud_blob_istreambuf.cpp
+ cloud_blob_client.cpp
+ cloud_blob.cpp
+ blob_response_parsers.cpp
+ blob_request_factory.cpp
+ basic_types.cpp
+ authentication.cpp
+ cloud_common.cpp
+ )
+ if(APPLE)
+ # set(SOURCES ${SOURCES} apple.cpp)
+ find_library(COREFOUNDATION CoreFoundation "/")
+ set(EXTRALINKS ${COREFOUNDATION})
+ else()
+ # set(SOURCES ${SOURCES} linux.cpp)
+ endif()
+elseif(WIN32)
+ set(SOURCES
+ xmlhelpers.cpp
+ response_parsers.cpp
+ request_result.cpp
+ request_factory.cpp
+ protocol_xml.cpp
+ navigation.cpp
+ async_semaphore.cpp
+ util.cpp
+ table_request_factory.cpp
+ table_response_parsers.cpp
+ table_query.cpp
+ entity_property.cpp
+ shared_access_signature.cpp
+ retry_policies.cpp
+ queue_request_factory.cpp
+ protocol_json.cpp
+ operation_context.cpp
+ mime_multipart_helper.cpp
+ cloud_table_client.cpp
+ cloud_table.cpp
+ cloud_storage_account.cpp
+ cloud_queue_message.cpp
+ cloud_queue_client.cpp
+ cloud_queue.cpp
+ cloud_page_blob.cpp
+ cloud_core.cpp
+ cloud_client.cpp
+ cloud_block_blob.cpp
+ cloud_blob_directory.cpp
+ cloud_blob_container.cpp
+ cloud_blob_shared.cpp
+ cloud_blob_ostreambuf.cpp
+ cloud_blob_istreambuf.cpp
+ cloud_blob_client.cpp
+ cloud_blob.cpp
+ blob_response_parsers.cpp
+ blob_request_factory.cpp
+ basic_types.cpp
+ authentication.cpp
+ cloud_common.cpp
+ )
+ add_definitions(
+ -D_ASYNCRT_EXPORT
+ -DAZURESTORAGESERVICES_EXPORTS
+ -D_PPLX_EXPORT
+ -DWIN32
+ -D_MBCS
+ -D_USRDLL
+ )
+ set(EXTRALINKS Httpapi.lib Winhttp.dll)
+endif()
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} -Werror -pedantic")
+
+add_library(${AZURESTORAGE_LIBRARY} ${SOURCES})
+
+target_link_libraries(${AZURESTORAGE_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${CASABLANCA_LIBRARY}
+ ${Boost_LIBRARIES}
+ ${Boost_FRAMEWORK}
+ ${LibXML++_LIBRARIES}
+ ${COREFOUNDATION}
+ ${EXTRALINKS}
+ )
+
+# Portions specific to cpprest binary versioning.
+set (AZURESTORAGE_VERSION_MAJOR 0)
+set (AZURESTORAGE_VERSION_MINOR 4)
+set (AZURESTORAGE_VERSION_REVISION 0)
+if(WIN32)
+ set_target_properties(${AZURESTORAGE_LIBRARY} PROPERTIES
+ OUTPUT_NAME "${AZURESTORAGE_LIBRARY}_${AZURESTORAGE_VERSION_MAJOR}_${AZURESTORAGE_VERSION_MINOR}")
+else()
+ set_target_properties(${AZURESTORAGE_LIBRARY} PROPERTIES
+ SOVERSION ${AZURESTORAGE_VERSION_MAJOR}.${AZURESTORAGE_VERSION_MINOR})
+endif()
+
diff --git a/Microsoft.WindowsAzure.Storage/src/Makefile b/Microsoft.WindowsAzure.Storage/src/Makefile
new file mode 100644
index 00000000..481f1504
--- /dev/null
+++ b/Microsoft.WindowsAzure.Storage/src/Makefile
@@ -0,0 +1,146 @@
+LIBRARY=azurestorage.so
+
+SOURCES = \
+ xmlhelpers.cpp \
+ util_windows.cpp \
+ response_parsers.cpp \
+ request_result.cpp \
+ request_factory.cpp \
+ protocol_xml.cpp \
+ navigation.cpp \
+ async_semaphore.cpp \
+ util.cpp \
+ table_request_factory.cpp \
+ table_response_parsers.cpp \
+ table_query.cpp \
+ entity_property.cpp \
+ shared_access_signature.cpp \
+ retry_policies.cpp \
+ queue_request_factory.cpp \
+ protocol_json.cpp \
+ operation_context.cpp \
+ mime_multipart_helper.cpp \
+ logging_windows.cpp \
+ hash_windows.cpp \
+ cloud_table_client.cpp \
+ cloud_table.cpp \
+ cloud_storage_account.cpp \
+ cloud_queue_message.cpp \
+ cloud_queue_client.cpp \
+ cloud_queue.cpp \
+ cloud_page_blob.cpp \
+ cloud_core.cpp \
+ cloud_client.cpp \
+ cloud_block_blob.cpp \
+ cloud_blob_directory.cpp \
+ cloud_blob_container.cpp \
+ cloud_blob_shared.cpp \
+ cloud_blob_ostreambuf.cpp \
+ cloud_blob_istreambuf.cpp \
+ cloud_blob_client.cpp \
+ cloud_blob.cpp \
+ blob_response_parsers.cpp \
+ blob_request_factory.cpp \
+ basic_types.cpp \
+ authentication.cpp \
+ cloud_common.cpp
+
+ifeq ($(UNAME),APPLE)
+ # SOURCES += apple.cpp
+else
+ # SOURCES += linux.cpp
+endif
+
+
+HEADERS = \
+ ../includes/wascore/async_semaphore.h \
+ ../includes/wascore/basic_types.h \
+ ../includes/wascore/blobstreams.h \
+ ../includes/wascore/constants.h \
+ ../includes/wascore/executor.h \
+ ../includes/wascore/hash_linux.h \
+ ../includes/wascore/logging.h \
+ ../includes/wascore/protocol_json.h \
+ ../includes/wascore/protocol_xml.h \
+ ../includes/wascore/protocol.h \
+ ../includes/wascore/resources.h \
+ ../includes/wascore/streambuf.h \
+ ../includes/wascore/streams.h \
+ ../includes/wascore/util.h \
+ ../includes/wascore/xmlhelpers.h \
+ ../includes/wascore/xmlstream.h \
+ ../includes/was/auth.h \
+ ../includes/was/blob.h \
+ ../includes/was/common.h \
+ ../includes/was/core.h \
+ ../includes/was/queue.h \
+ ../includes/was/retry_policies.h \
+ ../includes/was/service_client.h \
+ ../includes/was/storage_account.h \
+ ../includes/was/table.h \
+ ../includes/targetver.h \
+ ../includes/stdafx.h
+
+ifeq ($(UNAME),APPLE)
+ # HEADERS += ../include/compat/apple_compat.h
+else
+ # HEADERS += ../include/compat/linux_compat.h
+endif
+
+PCH = ../includes/stdafx.h
+
+PRECOMPILED_HEADERS = $(addsuffix .gch, $(PCH))
+OBJECTS = $(addsuffix .$(MODE).o, $(basename $(SOURCES)))
+CPP_DEPENDENCIES = $(addsuffix .d, $(basename $(SOURCES)))
+
+# flags for the C++ compiler
+
+ifeq ($(UNAME),LINUX)
+PKGCONFIG_CFLAGS = $(shell pkg-config libxml++-2.6 --cflags)
+PKGCONFIG_LIBS = $(shell pkg-config libxml++-2.6 --libs) $(shell pkg-config libssl --libs)
+endif
+
+ifeq ($(UNAME),APPLE)
+PLATFORM_FLAGS = -framework CoreFoundation
+endif
+ifeq ($(UNAME),LINUX)
+PLATFORM_FLAGS = -pthread
+endif
+
+#-fpch-deps -MMD not useful with a single monolithic PCH
+
+CXXFLAGS = -fPIC -std=c++11 $(STRICT_BASE_CXXFLAGS) -I../includes -I./pch $(WARNINGS) $(PKGCONFIG_CFLAGS)
+LIBS = $(PKGCONFIG_LIBS) $(PLATFORM_FLAGS) -l$(BOOST_SYSTEM) -l$(BOOST_THREAD) -l$(BOOST_LOCALE) -l$(BOOST_REGEX) -lstdc++ -lm # these are explicit for clang
+LDFLAGS = $(BASE_LDFLAGS)
+
+ifeq ($(OUTPUT_DIR),)
+ LIBRARY_DST=$(MODE)/$(LIBRARY)
+else
+ LIBRARY_DST=$(OUTPUT_DIR)/$(LIBRARY)
+endif
+
+all: $(LIBRARY_DST)
+
+%.h.gch: %.h
+ @echo "Building precompiled header $(@)"
+ @$(CXX) -x c++-header $(CXXFLAGS) -c $< -o $@
+
+-include $(CPP_DEPENDENCIES)
+
+%.$(MODE).o: %.cpp
+ @echo "Compiling $< -> $@"
+ @$(CXX) -MMD -MF $*.d $(CXXFLAGS) -c $< -o $@
+
+$(PRECOMPILED_HEADERS): $(HEADERS)
+
+$(LIBRARY_DST): $(OBJECTS)
+ @echo "Building library $@"
+ @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $^ -o $@ $(LIBS)
+
+#DEPS := $(OBJECTS:.o=.d)
+#-include $(DEPS)
+
+clean:
+ rm $(OBJECTS) $(PRECOMPILED_HEADERS) $(LIBRARY) $(CPP_DEPENDENCIES)
+
+.SILENT:clean
\ No newline at end of file
diff --git a/Microsoft.WindowsAzure.Storage/src/authentication.cpp b/Microsoft.WindowsAzure.Storage/src/authentication.cpp
index 98771a13..7fdc81d7 100644
--- a/Microsoft.WindowsAzure.Storage/src/authentication.cpp
+++ b/Microsoft.WindowsAzure.Storage/src/authentication.cpp
@@ -26,11 +26,11 @@ namespace azure { namespace storage { namespace protocol {
utility::string_t calculate_hmac_sha256_hash(const utility::string_t& string_to_hash, const storage_credentials& credentials)
{
- auto utf8_string_to_hash = utility::conversions::to_utf8string(string_to_hash);
- auto hash_streambuf = core::hash_hmac_sha256_streambuf(credentials.account_key());
- hash_streambuf.putn(reinterpret_cast(utf8_string_to_hash.data()), utf8_string_to_hash.size()).wait();
- hash_streambuf.close().wait();
- return utility::conversions::to_base64(hash_streambuf.hash());
+ std::string utf8_string_to_hash = utility::conversions::to_utf8string(string_to_hash);
+ core::hash_provider provider = core::hash_provider::create_hmac_sha256_hash_provider(credentials.account_key());
+ provider.write(reinterpret_cast(utf8_string_to_hash.data()), utf8_string_to_hash.size());
+ provider.close();
+ return provider.hash();
}
void sas_authentication_handler::sign_request(web::http::http_request& request, operation_context context) const
diff --git a/Microsoft.WindowsAzure.Storage/src/basic_types.cpp b/Microsoft.WindowsAzure.Storage/src/basic_types.cpp
index e5939f0c..0b67d480 100644
--- a/Microsoft.WindowsAzure.Storage/src/basic_types.cpp
+++ b/Microsoft.WindowsAzure.Storage/src/basic_types.cpp
@@ -23,21 +23,21 @@ namespace utility {
utility::uuid __cdecl new_uuid()
{
+ uuid result;
+
#ifdef WIN32
RPC_STATUS status;
- UUID uuid;
- status = UuidCreate(&uuid);
+ status = UuidCreate(&result);
if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY && status != RPC_S_UUID_NO_ADDRESS)
{
throw std::runtime_error(azure::storage::protocol::error_create_uuid);
}
#else
- uuid_t uuid;
- uuid_generate_random(uuid);
+ uuid_generate_random(result.data);
#endif
- return uuid;
+ return result;
}
utility::string_t __cdecl uuid_to_string(const utility::uuid& value)
@@ -61,9 +61,9 @@ namespace utility {
}
#else
char uuid_string[37];
- uuid_unparse_upper(value, uuid_string);
+ uuid_unparse_upper(value.data, uuid_string);
- std::string result(&uuid_string);
+ std::string result(uuid_string);
#endif
return result;
@@ -71,20 +71,20 @@ namespace utility {
utility::uuid __cdecl string_to_uuid(const utility::string_t& value)
{
+ uuid result;
+
#ifdef WIN32
RPC_STATUS status;
RPC_WSTR rpc_string = reinterpret_cast(const_cast(value.c_str()));
- UUID result;
status = UuidFromStringW(rpc_string, &result);
if (status != RPC_S_OK)
{
throw std::runtime_error(azure::storage::protocol::error_parse_uuid);
}
#else
- uuid_t result;
- int status_code = uuid_parse(value.c_str(), result);
+ int status_code = uuid_parse(value.c_str(), result.data);
if (status_code != 0)
{
throw std::runtime_error(azure::storage::protocol::error_parse_uuid);
@@ -99,7 +99,7 @@ namespace utility {
#ifdef WIN32
return value1 == value2;
#else
- return uuid_compare(value1, value2) == 0;
+ return uuid_compare(value1.data, value2.data) == 0;
#endif
}
diff --git a/Microsoft.WindowsAzure.Storage/src/cloud_blob.cpp b/Microsoft.WindowsAzure.Storage/src/cloud_blob.cpp
index ccab507f..f6f05638 100644
--- a/Microsoft.WindowsAzure.Storage/src/cloud_blob.cpp
+++ b/Microsoft.WindowsAzure.Storage/src/cloud_blob.cpp
@@ -143,9 +143,9 @@ namespace azure { namespace storage {
command->set_build_request(std::bind(protocol::get_blob_properties, snapshot_time(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
command->set_location_mode(core::command_location_mode::primary_or_secondary);
- command->set_preprocess_response([properties, metadata, copy_state] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([properties, metadata, copy_state] (const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_all(protocol::blob_response_parsers::parse_blob_properties(response), false);
*metadata = protocol::parse_metadata(response);
*copy_state = protocol::blob_response_parsers::parse_copy_state(response);
@@ -164,9 +164,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::set_blob_metadata, metadata(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_properties(response));
});
return core::executor::execute_async(command, modified_options, context);
@@ -183,9 +183,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::set_blob_properties, *properties, metadata(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
auto parsed_properties = protocol::blob_response_parsers::parse_blob_properties(response);
properties->update_etag_and_last_modified(parsed_properties);
@@ -202,7 +202,7 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::delete_blob, snapshots_option, snapshot_time(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response(std::bind(protocol::preprocess_response, std::placeholders::_1, std::placeholders::_2));
+ command->set_preprocess_response(std::bind(protocol::preprocess_response_void, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
return core::executor::execute_async(command, modified_options, context);
}
@@ -257,9 +257,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::lease_blob, protocol::header_value_lease_acquire, proposed_lease_id, duration, lease_break_period(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context) -> utility::string_t
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context) -> utility::string_t
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_properties(response));
return protocol::parse_lease_id(response);
});
@@ -282,9 +282,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::lease_blob, protocol::header_value_lease_renew, utility::string_t(), lease_time(), lease_break_period(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_properties(response));
});
return core::executor::execute_async(command, modified_options, context);
@@ -306,9 +306,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::lease_blob, protocol::header_value_lease_change, proposed_lease_id, lease_time(), lease_break_period(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context) -> utility::string_t
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context) -> utility::string_t
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_properties(response));
return protocol::parse_lease_id(response);
});
@@ -331,9 +331,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::lease_blob, protocol::header_value_lease_release, utility::string_t(), lease_time(), lease_break_period(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_properties(response));
});
return core::executor::execute_async(command, modified_options, context);
@@ -350,15 +350,26 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::lease_blob, protocol::header_value_lease_break, utility::string_t(), lease_time(), break_period, condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context) -> std::chrono::seconds
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context) -> std::chrono::seconds
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_properties(response));
return protocol::parse_lease_time(response);
});
return core::executor::execute_async(command, modified_options, context);
}
+ struct blob_download_info
+ {
+ bool m_are_properties_populated;
+ utility::size64_t m_total_written_to_destination_stream;
+ utility::size64_t m_response_length;
+ utility::string_t m_response_md5;
+ utility::string_t m_locked_etag;
+ bool m_reset_target;
+ concurrency::streams::ostream::pos_type m_target_offset;
+ };
+
pplx::task cloud_blob::download_range_to_stream_async(concurrency::streams::ostream target, utility::size64_t offset, utility::size64_t length, const access_condition& condition, const blob_request_options& options, operation_context context)
{
blob_request_options modified_options(options);
@@ -367,48 +378,132 @@ namespace azure { namespace storage {
auto properties = m_properties;
auto metadata = m_metadata;
auto copy_state = m_copy_state;
- auto target_offset = target.can_seek() ? target.tell() : 0;
- auto response_md5 = std::make_shared();
- auto response_length = std::make_shared(std::numeric_limits::max());
+ const utility::string_t& current_snapshot_time = snapshot_time();
+
+ std::shared_ptr download_info = std::make_shared();
+ download_info->m_are_properties_populated = false;
+ download_info->m_total_written_to_destination_stream = 0;
+ download_info->m_response_length = std::numeric_limits::max();
+ download_info->m_reset_target = false;
+ download_info->m_target_offset = target.can_seek() ? target.tell() : (Concurrency::streams::basic_ostream::pos_type)0;
+
+ std::shared_ptr> command = std::make_shared>(uri());
+ std::weak_ptr> weak_command(command);
+ command->set_build_request([offset, length, modified_options, condition, current_snapshot_time, download_info](web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) -> web::http::http_request
+ {
+ utility::size64_t current_offset = offset;
+ utility::size64_t current_length = length;
+ if (download_info->m_total_written_to_destination_stream > 0)
+ {
+ if (offset == std::numeric_limits::max())
+ {
+ current_offset = 0;
+ }
- auto command = std::make_shared>(uri());
- command->set_build_request(std::bind(protocol::get_blob, offset, length, modified_options.use_transactional_md5(), snapshot_time(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+ current_offset += download_info->m_total_written_to_destination_stream;
+
+ if (length > 0)
+ {
+ current_length -= download_info->m_total_written_to_destination_stream;
+
+ if (current_length <= 0)
+ {
+ // The entire blob has already been downloaded
+ throw std::invalid_argument("offset");
+ }
+ }
+ }
+
+ access_condition current_condition;
+ if (download_info->m_are_properties_populated && !download_info->m_locked_etag.empty())
+ {
+ current_condition.set_if_match_etag(download_info->m_locked_etag);
+
+ if (!condition.lease_id().empty())
+ {
+ current_condition.set_lease_id(condition.lease_id());
+ }
+ }
+ else
+ {
+ current_condition = condition;
+ }
+
+ return protocol::get_blob(current_offset, current_length, modified_options.use_transactional_md5() && !download_info->m_are_properties_populated, current_snapshot_time, current_condition, uri_builder, timeout, context);
+ });
command->set_authentication_handler(service_client().authentication_handler());
command->set_location_mode(core::command_location_mode::primary_or_secondary);
command->set_destination_stream(target);
command->set_calculate_response_body_md5(!modified_options.disable_content_md5_validation());
- command->set_recover_request([target, target_offset] (operation_context context) -> bool
+ command->set_recover_request([target, download_info](utility::size64_t total_written_to_destination_stream, operation_context context) -> bool
{
- // TODO support resume
- if (target.can_seek())
+ if (download_info->m_reset_target)
{
- target.seek(target_offset);
- return true;
+ download_info->m_total_written_to_destination_stream = 0;
+
+ if (total_written_to_destination_stream > 0)
+ {
+ if (!target.can_seek())
+ {
+ return false;
+ }
+
+ target.seek(download_info->m_target_offset);
+ }
+
+ download_info->m_reset_target = false;
}
else
{
- return false;
+ download_info->m_total_written_to_destination_stream = total_written_to_destination_stream;
}
+
+ return true;
});
- command->set_preprocess_response([modified_options, properties, metadata, copy_state, offset, response_md5, response_length] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([weak_command, offset, modified_options, properties, metadata, copy_state, download_info](const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
- properties->update_all(protocol::blob_response_parsers::parse_blob_properties(response), offset < std::numeric_limits::max());
- *metadata = protocol::parse_metadata(response);
- *copy_state = protocol::blob_response_parsers::parse_copy_state(response);
-
- *response_md5 = protocol::get_header_value(response, web::http::header_names::content_md5);
-
- if (modified_options.use_transactional_md5() && !modified_options.disable_content_md5_validation() && response_md5->empty())
+ std::shared_ptr> command(weak_command);
+
+ protocol::preprocess_response_void(response, result, context);
+
+ if (!download_info->m_are_properties_populated)
{
- throw storage_exception(protocol::error_missing_md5);
- }
+ properties->update_all(protocol::blob_response_parsers::parse_blob_properties(response), offset != std::numeric_limits::max());
+ *metadata = protocol::parse_metadata(response);
+ *copy_state = protocol::blob_response_parsers::parse_copy_state(response);
+
+ download_info->m_response_length = result.content_length();
+ download_info->m_response_md5 = result.content_md5();
+
+ if (modified_options.use_transactional_md5() && !modified_options.disable_content_md5_validation() && download_info->m_response_md5.empty())
+ {
+ throw storage_exception(protocol::error_missing_md5);
+ }
+
+ // Lock to the current storage location when resuming a failed download. This is locked
+ // early before the retry policy has the opportunity to change the storage location.
+ command->set_location_mode(core::command_location_mode::primary_or_secondary, result.target_location());
- *response_length = response.headers().content_length();
+ download_info->m_locked_etag = properties->etag();
+ download_info->m_are_properties_populated = true;
+ }
});
- command->set_postprocess_response([response_md5, response_length] (const web::http::http_response&, const request_result&, const core::ostream_descriptor& descriptor, operation_context context) -> pplx::task
+ command->set_postprocess_response([weak_command, download_info](const web::http::http_response&, const request_result&, const core::ostream_descriptor& descriptor, operation_context context) -> pplx::task
{
- protocol::check_stream_length_and_md5(*response_length, *response_md5, descriptor);
+ std::shared_ptr> command(weak_command);
+
+ // Start the download over from the beginning if a retry is needed again because the last
+ // response was successfully downloaded and the MD5 hash has already been calculated
+ download_info->m_reset_target = true;
+ download_info->m_are_properties_populated = false;
+
+ command->set_location_mode(core::command_location_mode::primary_or_secondary);
+
+ if (!download_info->m_response_md5.empty() && !descriptor.content_md5().empty() && download_info->m_response_md5 != descriptor.content_md5())
+ {
+ throw storage_exception(protocol::error_md5_mismatch);
+ }
+
return pplx::task_from_result();
});
return core::executor::execute_async(command, modified_options, context);
@@ -442,14 +537,14 @@ namespace azure { namespace storage {
command->set_build_request(std::bind(protocol::get_blob_properties, snapshot_time(), access_condition(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
command->set_location_mode(primary_only ? core::command_location_mode::primary_only : core::command_location_mode::primary_or_secondary);
- command->set_preprocess_response([properties, metadata, copy_state] (const web::http::http_response& response, operation_context context) -> bool
+ command->set_preprocess_response([properties, metadata, copy_state] (const web::http::http_response& response, const request_result& result, operation_context context) -> bool
{
if (response.status_code() == web::http::status_codes::NotFound)
{
return false;
}
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_all(protocol::blob_response_parsers::parse_blob_properties(response), false);
*metadata = protocol::parse_metadata(response);
*copy_state = protocol::blob_response_parsers::parse_copy_state(response);
@@ -470,9 +565,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::copy_blob, source, source_condition, metadata(), destination_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties, copy_state] (const web::http::http_response& response, operation_context context) -> utility::string_t
+ command->set_preprocess_response([properties, copy_state] (const web::http::http_response& response, const request_result& result, operation_context context) -> utility::string_t
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_properties(response));
auto new_state = protocol::blob_response_parsers::parse_copy_state(response);
*copy_state = new_state;
@@ -498,7 +593,7 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::abort_copy_blob, copy_id, condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response(std::bind(protocol::preprocess_response, std::placeholders::_1, std::placeholders::_2));
+ command->set_preprocess_response(std::bind(protocol::preprocess_response_void, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
return core::executor::execute_async(command, modified_options, context);
}
@@ -517,9 +612,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::snapshot_blob, *snapshot_metadata, condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([snapshot_name, snapshot_container, resulting_metadata, properties] (const web::http::http_response& response, operation_context context) -> cloud_blob
+ command->set_preprocess_response([snapshot_name, snapshot_container, resulting_metadata, properties] (const web::http::http_response& response, const request_result& result, operation_context context) -> cloud_blob
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
auto snapshot_time = protocol::get_header_value(response, protocol::ms_header_snapshot);
cloud_blob snapshot(snapshot_name, snapshot_time, snapshot_container);
*snapshot.m_metadata = *resulting_metadata;
diff --git a/Microsoft.WindowsAzure.Storage/src/cloud_blob_client.cpp b/Microsoft.WindowsAzure.Storage/src/cloud_blob_client.cpp
index 580b3eda..6d62c56b 100644
--- a/Microsoft.WindowsAzure.Storage/src/cloud_blob_client.cpp
+++ b/Microsoft.WindowsAzure.Storage/src/cloud_blob_client.cpp
@@ -33,21 +33,21 @@ namespace azure { namespace storage {
command->set_build_request(std::bind(protocol::list_containers, prefix, includes, max_results, token, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(authentication_handler());
command->set_location_mode(core::command_location_mode::primary_or_secondary, token.target_location());
- command->set_preprocess_response(std::bind(protocol::preprocess_response, container_result_segment(), std::placeholders::_1, std::placeholders::_2));
+ command->set_preprocess_response(std::bind(protocol::preprocess_response, container_result_segment(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_postprocess_response([client] (const web::http::http_response& response, const request_result& result, const core::ostream_descriptor&, operation_context context) -> pplx::task
{
protocol::list_containers_reader reader(response.body());
// TODO: Initialize a reasonable capacity for container objects throughout the codebase
- std::vector items(reader.extract_items());
+ std::vector items(reader.move_items());
std::vector results;
for (std::vector::iterator iter = items.begin(); iter != items.end(); ++iter)
{
- results.push_back(cloud_blob_container(iter->name(), client, iter->properties(), iter->metadata()));
+ results.push_back(cloud_blob_container(iter->move_name(), client, iter->move_properties(), iter->move_metadata()));
}
- continuation_token next_token(reader.extract_next_marker());
+ continuation_token next_token(reader.move_next_marker());
next_token.set_target_location(result.target_location());
return pplx::task_from_result(container_result_segment(std::move(results), next_token));
});
diff --git a/Microsoft.WindowsAzure.Storage/src/cloud_blob_container.cpp b/Microsoft.WindowsAzure.Storage/src/cloud_blob_container.cpp
index 3b93c674..a956eeda 100644
--- a/Microsoft.WindowsAzure.Storage/src/cloud_blob_container.cpp
+++ b/Microsoft.WindowsAzure.Storage/src/cloud_blob_container.cpp
@@ -122,9 +122,9 @@ namespace azure { namespace storage {
command->set_build_request(std::bind(protocol::get_blob_container_properties, condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
command->set_location_mode(core::command_location_mode::primary_or_secondary);
- command->set_preprocess_response([properties, metadata] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([properties, metadata] (const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
*properties = protocol::blob_response_parsers::parse_blob_container_properties(response);
*metadata = protocol::parse_metadata(response);
});
@@ -141,9 +141,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::set_blob_container_metadata, metadata(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_container_properties(response));
});
return core::executor::execute_async(command, modified_options, context);
@@ -159,9 +159,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::lease_blob_container, protocol::header_value_lease_acquire, proposed_lease_id, duration, lease_break_period(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context) -> utility::string_t
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context) -> utility::string_t
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_container_properties(response));
return protocol::parse_lease_id(response);
});
@@ -183,9 +183,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::lease_blob_container, protocol::header_value_lease_renew, utility::string_t(), lease_time(), lease_break_period(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_container_properties(response));
});
return core::executor::execute_async(command, modified_options, context);
@@ -206,9 +206,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::lease_blob_container, protocol::header_value_lease_change, proposed_lease_id, lease_time(), lease_break_period(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context) -> utility::string_t
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context) -> utility::string_t
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_container_properties(response));
return protocol::parse_lease_id(response);
});
@@ -230,9 +230,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::lease_blob_container, protocol::header_value_lease_release, utility::string_t(), lease_time(), lease_break_period(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_container_properties(response));
});
return core::executor::execute_async(command, modified_options, context);
@@ -248,9 +248,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::lease_blob_container, protocol::header_value_lease_break, utility::string_t(), lease_time(), break_period, condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context) -> std::chrono::seconds
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context) -> std::chrono::seconds
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_container_properties(response));
return protocol::parse_lease_time(response);
});
@@ -267,9 +267,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::create_blob_container, public_access, metadata(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_container_properties(response));
});
return core::executor::execute_async(command, modified_options, context);
@@ -323,7 +323,7 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::delete_blob_container, condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response(std::bind(protocol::preprocess_response, std::placeholders::_1, std::placeholders::_2));
+ command->set_preprocess_response(std::bind(protocol::preprocess_response_void, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
return core::executor::execute_async(command, modified_options, context);
}
@@ -389,26 +389,26 @@ namespace azure { namespace storage {
command->set_build_request(std::bind(protocol::list_blobs, prefix, delimiter, includes, max_results, token, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
command->set_location_mode(core::command_location_mode::primary_or_secondary, token.target_location());
- command->set_preprocess_response(std::bind(protocol::preprocess_response, blob_result_segment(), std::placeholders::_1, std::placeholders::_2));
+ command->set_preprocess_response(std::bind(protocol::preprocess_response, blob_result_segment(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_postprocess_response([container, delimiter] (const web::http::http_response& response, const request_result& result, const core::ostream_descriptor&, operation_context context) -> pplx::task
{
protocol::list_blobs_reader reader(response.body());
- std::vector blob_items(reader.extract_blob_items());
+ std::vector blob_items(reader.move_blob_items());
std::vector blobs;
for (std::vector::iterator iter = blob_items.begin(); iter != blob_items.end(); ++iter)
{
- blobs.push_back(cloud_blob(iter->name(), iter->snapshot_time(), container, iter->properties(), iter->metadata(), iter->copy_state()));
+ blobs.push_back(cloud_blob(iter->move_name(), iter->move_snapshot_time(), container, iter->move_properties(), iter->move_metadata(), iter->move_copy_state()));
}
- std::vector blob_prefix_items(reader.extract_blob_prefix_items());
+ std::vector blob_prefix_items(reader.move_blob_prefix_items());
std::vector directories;
for (auto iter = blob_prefix_items.begin(); iter != blob_prefix_items.end(); ++iter)
{
- directories.push_back(cloud_blob_directory(iter->name(), container));
+ directories.push_back(cloud_blob_directory(iter->move_name(), container));
}
- continuation_token next_token(reader.extract_next_marker());
+ continuation_token next_token(reader.move_next_marker());
next_token.set_target_location(result.target_location());
return pplx::task_from_result(blob_result_segment(std::move(blobs), std::move(directories), next_token));
});
@@ -428,9 +428,9 @@ namespace azure { namespace storage {
auto command = std::make_shared>(uri());
command->set_build_request(std::bind(protocol::set_blob_container_acl, permissions.public_access(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context)
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context)
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_container_properties(response));
});
return core::istream_descriptor::create(stream).then([command, context, modified_options] (core::istream_descriptor request_body) -> pplx::task
@@ -451,9 +451,9 @@ namespace azure { namespace storage {
command->set_build_request(std::bind(protocol::get_blob_container_acl, condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
command->set_location_mode(core::command_location_mode::primary_or_secondary);
- command->set_preprocess_response([properties] (const web::http::http_response& response, operation_context context) -> blob_container_permissions
+ command->set_preprocess_response([properties] (const web::http::http_response& response, const request_result& result, operation_context context) -> blob_container_permissions
{
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
properties->update_etag_and_last_modified(protocol::blob_response_parsers::parse_blob_container_properties(response));
return blob_container_permissions();
});
@@ -461,7 +461,7 @@ namespace azure { namespace storage {
{
blob_container_permissions permissions;
protocol::access_policy_reader reader(response.body());
- permissions.set_policies(reader.extract_policies());
+ permissions.set_policies(reader.move_policies());
permissions.set_public_access(protocol::blob_response_parsers::parse_public_access_type(response));
return pplx::task_from_result(permissions);
});
@@ -480,14 +480,14 @@ namespace azure { namespace storage {
command->set_build_request(std::bind(protocol::get_blob_container_properties, access_condition(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
command->set_authentication_handler(service_client().authentication_handler());
command->set_location_mode(primary_only ? core::command_location_mode::primary_only : core::command_location_mode::primary_or_secondary);
- command->set_preprocess_response([properties, metadata] (const web::http::http_response& response, operation_context context) -> bool
+ command->set_preprocess_response([properties, metadata] (const web::http::http_response& response, const request_result& result, operation_context context) -> bool
{
if (response.status_code() == web::http::status_codes::NotFound)
{
return false;
}
- protocol::preprocess_response(response, context);
+ protocol::preprocess_response_void(response, result, context);
*properties = protocol::blob_response_parsers::parse_blob_container_properties(response);
*metadata = protocol::parse_metadata(response);
return true;
diff --git a/Microsoft.WindowsAzure.Storage/src/cloud_blob_istreambuf.cpp b/Microsoft.WindowsAzure.Storage/src/cloud_blob_istreambuf.cpp
index 43d2b999..3de90478 100644
--- a/Microsoft.WindowsAzure.Storage/src/cloud_blob_istreambuf.cpp
+++ b/Microsoft.WindowsAzure.Storage/src/cloud_blob_istreambuf.cpp
@@ -17,6 +17,7 @@
#include "stdafx.h"
#include "wascore/blobstreams.h"
+#include "wascore/resources.h"
namespace azure { namespace storage { namespace core {
@@ -36,7 +37,7 @@ namespace azure { namespace storage { namespace core {
m_current_blob_offset = pos;
m_next_blob_offset = m_current_blob_offset;
m_buffer = concurrency::streams::container_buffer>(std::ios_base::in);
- m_blob_hash = hash_streambuf();
+ m_blob_hash_provider = hash_provider();
return pos;
}
}
@@ -146,27 +147,23 @@ namespace azure { namespace storage { namespace core {
this_pointer->m_buffer = concurrency::streams::container_buffer>(std::move(temp_buffer.collection()), std::ios_base::in);
this_pointer->m_buffer.seekpos(0, std::ios_base::in);
- if (this_pointer->m_blob_hash && this_pointer->m_blob_hash.is_open())
+ // Validate the blob's content MD5 hash
+ if (this_pointer->m_blob_hash_provider.is_enabled())
{
- return this_pointer->m_buffer.create_istream().read_to_end(this_pointer->m_blob_hash).then([this_pointer] (size_t) -> bool
+ std::vector& result_buffer = this_pointer->m_buffer.collection();
+ this_pointer->m_blob_hash_provider.write(result_buffer.data(), result_buffer.size());
+
+ if (((utility::size64_t) this_pointer->m_next_blob_offset) == this_pointer->size())
{
- if (((utility::size64_t) this_pointer->m_next_blob_offset) == this_pointer->size())
+ this_pointer->m_blob_hash_provider.close();
+ if (this_pointer->m_blob->properties().content_md5() != this_pointer->m_blob_hash_provider.hash())
{
- this_pointer->m_blob_hash.close().wait();
- if (this_pointer->m_blob->properties().content_md5() != utility::conversions::to_base64(this_pointer->m_blob_hash.hash()))
- {
- throw storage_exception(protocol::error_md5_mismatch);
- }
+ throw storage_exception(protocol::error_md5_mismatch);
}
-
- this_pointer->m_buffer.seekpos(0, std::ios_base::in);
- return true;
- });
- }
- else
- {
- return pplx::task_from_result(true);
+ }
}
+
+ return pplx::task_from_result(true);
}
catch (const std::exception&)
{
diff --git a/Microsoft.WindowsAzure.Storage/src/cloud_blob_ostreambuf.cpp b/Microsoft.WindowsAzure.Storage/src/cloud_blob_ostreambuf.cpp
index 0556265e..a6c22544 100644
--- a/Microsoft.WindowsAzure.Storage/src/cloud_blob_ostreambuf.cpp
+++ b/Microsoft.WindowsAzure.Storage/src/cloud_blob_ostreambuf.cpp
@@ -17,6 +17,7 @@
#include "stdafx.h"
#include "wascore/blobstreams.h"
+#include "wascore/resources.h"
namespace azure { namespace storage { namespace core {
@@ -30,9 +31,9 @@ namespace azure { namespace storage { namespace core {
m_committed = true;
basic_ostreambuf::_close_write().wait();
- if (m_blob_hash)
+ if (m_blob_hash_provider.is_enabled())
{
- m_blob_hash.close().wait();
+ m_blob_hash_provider.close();
}
return commit_blob();
@@ -59,11 +60,11 @@ namespace azure { namespace storage { namespace core {
std::shared_ptr basic_cloud_blob_ostreambuf::prepare_buffer()
{
utility::string_t block_md5;
- if (m_block_hash)
+ if (m_block_hash_provider.is_enabled())
{
- m_block_hash.close().wait();
- block_md5 = utility::conversions::to_base64(m_block_hash.hash());
- m_block_hash = hash_md5_streambuf();
+ m_block_hash_provider.close();
+ block_md5 = m_block_hash_provider.hash();
+ m_block_hash_provider = hash_provider::create_md5_hash_provider();
}
auto buffer = std::make_shared(m_buffer, block_md5);
@@ -102,19 +103,17 @@ namespace azure { namespace storage { namespace core {
write_size = remaining;
}
- // All streambuf puts below are waited, because one is a memory buffer and the others
- // are hash buffers. Hence, there is no async IO involved.
-
- if (m_block_hash)
+ if (m_block_hash_provider.is_enabled())
{
- m_block_hash.putn(ptr, write_size).wait();
+ m_block_hash_provider.write(ptr, write_size);
}
- if (m_blob_hash)
+ if (m_blob_hash_provider.is_enabled())
{
- m_blob_hash.putn(ptr, write_size).wait();
+ m_blob_hash_provider.write(ptr, write_size);
}
+ // The streambuf is waited because it is a memory buffer, so does not involve async I/O
m_buffer.putn(ptr, write_size).wait();
if (m_buffer_size == m_buffer.size())
{
@@ -178,9 +177,9 @@ namespace azure { namespace storage { namespace core {
auto this_pointer = std::dynamic_pointer_cast(shared_from_this());
return _sync().then([this_pointer] (bool) -> pplx::task
{
- if (this_pointer->m_blob_hash)
+ if (this_pointer->m_blob_hash_provider.is_enabled())
{
- this_pointer->m_blob->properties().set_content_md5(utility::conversions::to_base64(this_pointer->m_blob_hash.hash()));
+ this_pointer->m_blob->properties().set_content_md5(this_pointer->m_blob_hash_provider.hash());
}
return this_pointer->m_blob->upload_block_list_async(this_pointer->m_block_list, this_pointer->m_condition, this_pointer->m_options, this_pointer->m_context);
@@ -243,12 +242,12 @@ namespace azure { namespace storage { namespace core {
pplx::task basic_cloud_page_blob_ostreambuf::commit_blob()
{
- if (m_blob_hash)
+ if (m_blob_hash_provider.is_enabled())
{
auto this_pointer = std::dynamic_pointer_cast