diff --git a/Build/libHttpClient.140.UWP.C/libHttpClient.140.UWP.C.vcxproj b/Build/libHttpClient.140.UWP.C/libHttpClient.140.UWP.C.vcxproj
index b4c05539..893f7c4c 100644
--- a/Build/libHttpClient.140.UWP.C/libHttpClient.140.UWP.C.vcxproj
+++ b/Build/libHttpClient.140.UWP.C/libHttpClient.140.UWP.C.vcxproj
@@ -108,6 +108,7 @@
+
diff --git a/Build/libHttpClient.140.UWP.C/libHttpClient.140.UWP.C.vcxproj.filters b/Build/libHttpClient.140.UWP.C/libHttpClient.140.UWP.C.vcxproj.filters
index 7a14bdad..71da9e5c 100644
--- a/Build/libHttpClient.140.UWP.C/libHttpClient.140.UWP.C.vcxproj.filters
+++ b/Build/libHttpClient.140.UWP.C/libHttpClient.140.UWP.C.vcxproj.filters
@@ -81,6 +81,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -198,46 +201,46 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {84EAA571-662D-338E-93ED-5F199E278D3A}
+ {B245C598-513E-31E2-86F2-B936F07371C7}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {19F27A1D-1A07-34C1-BD02-058666E43986}
+ {4EF99C88-F2E5-32A2-8923-C7AC29483D0D}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.140.Win32.C/libHttpClient.140.Win32.C.vcxproj b/Build/libHttpClient.140.Win32.C/libHttpClient.140.Win32.C.vcxproj
index 41f2762d..8bdb23a9 100644
--- a/Build/libHttpClient.140.Win32.C/libHttpClient.140.Win32.C.vcxproj
+++ b/Build/libHttpClient.140.Win32.C/libHttpClient.140.Win32.C.vcxproj
@@ -99,6 +99,7 @@
+
diff --git a/Build/libHttpClient.140.Win32.C/libHttpClient.140.Win32.C.vcxproj.filters b/Build/libHttpClient.140.Win32.C/libHttpClient.140.Win32.C.vcxproj.filters
index 0b01976f..7c121e53 100644
--- a/Build/libHttpClient.140.Win32.C/libHttpClient.140.Win32.C.vcxproj.filters
+++ b/Build/libHttpClient.140.Win32.C/libHttpClient.140.Win32.C.vcxproj.filters
@@ -75,6 +75,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -186,46 +189,46 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {4BEDE216-DAE5-33E7-93E9-294BBFE29520}
+ {7A5EA885-D945-3941-BA96-ED8304FE3455}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {D32651A6-7E85-35EF-B860-E8E3CF1E6177}
+ {8EE7BD63-CD1F-30B2-BB86-794DE9F2EA90}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.140.XDK.C/libHttpClient.140.XDK.C.vcxproj b/Build/libHttpClient.140.XDK.C/libHttpClient.140.XDK.C.vcxproj
index 51191089..57425aa8 100644
--- a/Build/libHttpClient.140.XDK.C/libHttpClient.140.XDK.C.vcxproj
+++ b/Build/libHttpClient.140.XDK.C/libHttpClient.140.XDK.C.vcxproj
@@ -78,6 +78,7 @@
+
diff --git a/Build/libHttpClient.140.XDK.C/libHttpClient.140.XDK.C.vcxproj.filters b/Build/libHttpClient.140.XDK.C/libHttpClient.140.XDK.C.vcxproj.filters
index 48923f46..f8710b65 100644
--- a/Build/libHttpClient.140.XDK.C/libHttpClient.140.XDK.C.vcxproj.filters
+++ b/Build/libHttpClient.140.XDK.C/libHttpClient.140.XDK.C.vcxproj.filters
@@ -81,6 +81,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -198,46 +201,46 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {84EAA571-662D-338E-93ED-5F199E278D3A}
+ {B245C598-513E-31E2-86F2-B936F07371C7}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {19F27A1D-1A07-34C1-BD02-058666E43986}
+ {4EF99C88-F2E5-32A2-8923-C7AC29483D0D}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.141.GDK.C/libHttpClient.141.GDK.C.vcxproj b/Build/libHttpClient.141.GDK.C/libHttpClient.141.GDK.C.vcxproj
index cf41a6da..060f2dfe 100644
--- a/Build/libHttpClient.141.GDK.C/libHttpClient.141.GDK.C.vcxproj
+++ b/Build/libHttpClient.141.GDK.C/libHttpClient.141.GDK.C.vcxproj
@@ -99,6 +99,7 @@
+
@@ -119,8 +120,12 @@
-
-
+
+
+
+
+
+
diff --git a/Build/libHttpClient.141.GDK.C/libHttpClient.141.GDK.C.vcxproj.filters b/Build/libHttpClient.141.GDK.C/libHttpClient.141.GDK.C.vcxproj.filters
index b6007e81..73e37c7e 100644
--- a/Build/libHttpClient.141.GDK.C/libHttpClient.141.GDK.C.vcxproj.filters
+++ b/Build/libHttpClient.141.GDK.C/libHttpClient.141.GDK.C.vcxproj.filters
@@ -22,8 +22,14 @@
C++ Source\Global
-
- C++ Source\HTTP\WinHttp
+
+ C++ Source\HTTP\Curl
+
+
+ C++ Source\HTTP\Curl
+
+
+ C++ Source\HTTP\Curl
C++ Source\HTTP
@@ -60,6 +66,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -90,8 +99,14 @@
C++ Source\Global
-
- C++ Source\HTTP\WinHttp
+
+ C++ Source\HTTP\Curl
+
+
+ C++ Source\HTTP\Curl
+
+
+ C++ Source\HTTP\Curl
C++ Source\HTTP
@@ -138,40 +153,40 @@
- {4B24093D-5F61-3E7B-B53A-155D833CE990}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {5DB96368-8B66-3AD7-8E55-F250991593AE}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {7FA52DF8-9864-3D90-8217-C02E81138559}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {5DE2D652-C0DA-3F33-B684-A0C93FEA6009}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {B06E9020-4922-3461-9A26-D85D45D52710}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
-
- {6CB3A0CF-6B86-31AF-AFFD-88577A6FD759}
+
+ {8A8BB441-2DBF-39CE-BF15-42D8FA1F2451}
- {4BC6EB69-E166-3264-A585-E5996C2AF5B9}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {3D96EFFD-6054-3227-B362-297897876C05}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {FA75CFAD-BC14-3A9D-A907-23E1F994DB66}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {D048DED3-BA76-342E-AC88-0640A35BF2F3}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {32F0BE1E-07C2-3438-A72C-E0F17C94E14B}
+ {8EE7BD63-CD1F-30B2-BB86-794DE9F2EA90}
- {8D3620F6-F6C6-3211-B325-CE19BE6BA40A}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.141.UWP.C/libHttpClient.141.UWP.C.vcxproj b/Build/libHttpClient.141.UWP.C/libHttpClient.141.UWP.C.vcxproj
index f5f025be..da2852d9 100644
--- a/Build/libHttpClient.141.UWP.C/libHttpClient.141.UWP.C.vcxproj
+++ b/Build/libHttpClient.141.UWP.C/libHttpClient.141.UWP.C.vcxproj
@@ -123,6 +123,7 @@
+
diff --git a/Build/libHttpClient.141.UWP.C/libHttpClient.141.UWP.C.vcxproj.filters b/Build/libHttpClient.141.UWP.C/libHttpClient.141.UWP.C.vcxproj.filters
index 7a14bdad..71da9e5c 100644
--- a/Build/libHttpClient.141.UWP.C/libHttpClient.141.UWP.C.vcxproj.filters
+++ b/Build/libHttpClient.141.UWP.C/libHttpClient.141.UWP.C.vcxproj.filters
@@ -81,6 +81,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -198,46 +201,46 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {84EAA571-662D-338E-93ED-5F199E278D3A}
+ {B245C598-513E-31E2-86F2-B936F07371C7}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {19F27A1D-1A07-34C1-BD02-058666E43986}
+ {4EF99C88-F2E5-32A2-8923-C7AC29483D0D}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.141.Win32.C/libHttpClient.141.Win32.C.vcxproj b/Build/libHttpClient.141.Win32.C/libHttpClient.141.Win32.C.vcxproj
index 0a42fd0f..eb62e3b3 100644
--- a/Build/libHttpClient.141.Win32.C/libHttpClient.141.Win32.C.vcxproj
+++ b/Build/libHttpClient.141.Win32.C/libHttpClient.141.Win32.C.vcxproj
@@ -112,6 +112,7 @@
+
diff --git a/Build/libHttpClient.141.Win32.C/libHttpClient.141.Win32.C.vcxproj.filters b/Build/libHttpClient.141.Win32.C/libHttpClient.141.Win32.C.vcxproj.filters
index 0b01976f..7c121e53 100644
--- a/Build/libHttpClient.141.Win32.C/libHttpClient.141.Win32.C.vcxproj.filters
+++ b/Build/libHttpClient.141.Win32.C/libHttpClient.141.Win32.C.vcxproj.filters
@@ -75,6 +75,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -186,46 +189,46 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {4BEDE216-DAE5-33E7-93E9-294BBFE29520}
+ {7A5EA885-D945-3941-BA96-ED8304FE3455}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {D32651A6-7E85-35EF-B860-E8E3CF1E6177}
+ {8EE7BD63-CD1F-30B2-BB86-794DE9F2EA90}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.141.XDK.C/libHttpClient.141.XDK.C.vcxproj b/Build/libHttpClient.141.XDK.C/libHttpClient.141.XDK.C.vcxproj
index a0ea3dc8..92c0a020 100644
--- a/Build/libHttpClient.141.XDK.C/libHttpClient.141.XDK.C.vcxproj
+++ b/Build/libHttpClient.141.XDK.C/libHttpClient.141.XDK.C.vcxproj
@@ -79,6 +79,7 @@
+
diff --git a/Build/libHttpClient.141.XDK.C/libHttpClient.141.XDK.C.vcxproj.filters b/Build/libHttpClient.141.XDK.C/libHttpClient.141.XDK.C.vcxproj.filters
index 48923f46..f8710b65 100644
--- a/Build/libHttpClient.141.XDK.C/libHttpClient.141.XDK.C.vcxproj.filters
+++ b/Build/libHttpClient.141.XDK.C/libHttpClient.141.XDK.C.vcxproj.filters
@@ -81,6 +81,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -198,46 +201,46 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {84EAA571-662D-338E-93ED-5F199E278D3A}
+ {B245C598-513E-31E2-86F2-B936F07371C7}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {19F27A1D-1A07-34C1-BD02-058666E43986}
+ {4EF99C88-F2E5-32A2-8923-C7AC29483D0D}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.142.GDK.C/libHttpClient.142.GDK.C.vcxproj b/Build/libHttpClient.142.GDK.C/libHttpClient.142.GDK.C.vcxproj
index 8b4624ba..e767af62 100644
--- a/Build/libHttpClient.142.GDK.C/libHttpClient.142.GDK.C.vcxproj
+++ b/Build/libHttpClient.142.GDK.C/libHttpClient.142.GDK.C.vcxproj
@@ -99,6 +99,7 @@
+
@@ -119,8 +120,12 @@
-
-
+
+
+
+
+
+
diff --git a/Build/libHttpClient.142.GDK.C/libHttpClient.142.GDK.C.vcxproj.filters b/Build/libHttpClient.142.GDK.C/libHttpClient.142.GDK.C.vcxproj.filters
index b6007e81..73e37c7e 100644
--- a/Build/libHttpClient.142.GDK.C/libHttpClient.142.GDK.C.vcxproj.filters
+++ b/Build/libHttpClient.142.GDK.C/libHttpClient.142.GDK.C.vcxproj.filters
@@ -22,8 +22,14 @@
C++ Source\Global
-
- C++ Source\HTTP\WinHttp
+
+ C++ Source\HTTP\Curl
+
+
+ C++ Source\HTTP\Curl
+
+
+ C++ Source\HTTP\Curl
C++ Source\HTTP
@@ -60,6 +66,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -90,8 +99,14 @@
C++ Source\Global
-
- C++ Source\HTTP\WinHttp
+
+ C++ Source\HTTP\Curl
+
+
+ C++ Source\HTTP\Curl
+
+
+ C++ Source\HTTP\Curl
C++ Source\HTTP
@@ -138,40 +153,40 @@
- {4B24093D-5F61-3E7B-B53A-155D833CE990}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {5DB96368-8B66-3AD7-8E55-F250991593AE}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {7FA52DF8-9864-3D90-8217-C02E81138559}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {5DE2D652-C0DA-3F33-B684-A0C93FEA6009}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {B06E9020-4922-3461-9A26-D85D45D52710}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
-
- {6CB3A0CF-6B86-31AF-AFFD-88577A6FD759}
+
+ {8A8BB441-2DBF-39CE-BF15-42D8FA1F2451}
- {4BC6EB69-E166-3264-A585-E5996C2AF5B9}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {3D96EFFD-6054-3227-B362-297897876C05}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {FA75CFAD-BC14-3A9D-A907-23E1F994DB66}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {D048DED3-BA76-342E-AC88-0640A35BF2F3}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {32F0BE1E-07C2-3438-A72C-E0F17C94E14B}
+ {8EE7BD63-CD1F-30B2-BB86-794DE9F2EA90}
- {8D3620F6-F6C6-3211-B325-CE19BE6BA40A}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.142.UWP.C/libHttpClient.142.UWP.C.vcxproj b/Build/libHttpClient.142.UWP.C/libHttpClient.142.UWP.C.vcxproj
index e75f492a..2a6891a2 100644
--- a/Build/libHttpClient.142.UWP.C/libHttpClient.142.UWP.C.vcxproj
+++ b/Build/libHttpClient.142.UWP.C/libHttpClient.142.UWP.C.vcxproj
@@ -123,6 +123,7 @@
+
diff --git a/Build/libHttpClient.142.UWP.C/libHttpClient.142.UWP.C.vcxproj.filters b/Build/libHttpClient.142.UWP.C/libHttpClient.142.UWP.C.vcxproj.filters
index 7a14bdad..71da9e5c 100644
--- a/Build/libHttpClient.142.UWP.C/libHttpClient.142.UWP.C.vcxproj.filters
+++ b/Build/libHttpClient.142.UWP.C/libHttpClient.142.UWP.C.vcxproj.filters
@@ -81,6 +81,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -198,46 +201,46 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {84EAA571-662D-338E-93ED-5F199E278D3A}
+ {B245C598-513E-31E2-86F2-B936F07371C7}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {19F27A1D-1A07-34C1-BD02-058666E43986}
+ {4EF99C88-F2E5-32A2-8923-C7AC29483D0D}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.142.Win32.C/libHttpClient.142.Win32.C.vcxproj b/Build/libHttpClient.142.Win32.C/libHttpClient.142.Win32.C.vcxproj
index 20aa523c..6e7325b7 100644
--- a/Build/libHttpClient.142.Win32.C/libHttpClient.142.Win32.C.vcxproj
+++ b/Build/libHttpClient.142.Win32.C/libHttpClient.142.Win32.C.vcxproj
@@ -112,6 +112,7 @@
+
diff --git a/Build/libHttpClient.142.Win32.C/libHttpClient.142.Win32.C.vcxproj.filters b/Build/libHttpClient.142.Win32.C/libHttpClient.142.Win32.C.vcxproj.filters
index 0b01976f..7c121e53 100644
--- a/Build/libHttpClient.142.Win32.C/libHttpClient.142.Win32.C.vcxproj.filters
+++ b/Build/libHttpClient.142.Win32.C/libHttpClient.142.Win32.C.vcxproj.filters
@@ -75,6 +75,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -186,46 +189,46 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {4BEDE216-DAE5-33E7-93E9-294BBFE29520}
+ {7A5EA885-D945-3941-BA96-ED8304FE3455}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {D32651A6-7E85-35EF-B860-E8E3CF1E6177}
+ {8EE7BD63-CD1F-30B2-BB86-794DE9F2EA90}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.142.XDK.C/libHttpClient.142.XDK.C.vcxproj b/Build/libHttpClient.142.XDK.C/libHttpClient.142.XDK.C.vcxproj
index 907e9c4b..a5588d90 100644
--- a/Build/libHttpClient.142.XDK.C/libHttpClient.142.XDK.C.vcxproj
+++ b/Build/libHttpClient.142.XDK.C/libHttpClient.142.XDK.C.vcxproj
@@ -79,6 +79,7 @@
+
diff --git a/Build/libHttpClient.142.XDK.C/libHttpClient.142.XDK.C.vcxproj.filters b/Build/libHttpClient.142.XDK.C/libHttpClient.142.XDK.C.vcxproj.filters
index 48923f46..f8710b65 100644
--- a/Build/libHttpClient.142.XDK.C/libHttpClient.142.XDK.C.vcxproj.filters
+++ b/Build/libHttpClient.142.XDK.C/libHttpClient.142.XDK.C.vcxproj.filters
@@ -81,6 +81,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -198,46 +201,46 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {84EAA571-662D-338E-93ED-5F199E278D3A}
+ {B245C598-513E-31E2-86F2-B936F07371C7}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {19F27A1D-1A07-34C1-BD02-058666E43986}
+ {4EF99C88-F2E5-32A2-8923-C7AC29483D0D}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.UnitTest.141.TAEF/libHttpClient.UnitTest.141.TAEF.vcxproj b/Build/libHttpClient.UnitTest.141.TAEF/libHttpClient.UnitTest.141.TAEF.vcxproj
index 9b2ab34c..5d06d665 100644
--- a/Build/libHttpClient.UnitTest.141.TAEF/libHttpClient.UnitTest.141.TAEF.vcxproj
+++ b/Build/libHttpClient.UnitTest.141.TAEF/libHttpClient.UnitTest.141.TAEF.vcxproj
@@ -56,12 +56,16 @@
/bigobj /Zm512 /GS %(AdditionalOptions)
- $(WindowsSDKDir_10)Testing\Development\inc;$(MSBuildThisFileDirectory)..\..\Source\Task;%(AdditionalIncludeDirectories)
+
+ c:\Program Files (x86)\Windows Kits\10\Testing\Development\inc;
+ $(MSBuildThisFileDirectory)..\..\Source\Task;
+ %(AdditionalIncludeDirectories)
+
- $(WindowsSDKDir_10)Testing\Development\lib\x64;%(AdditionalLibraryDirectories)
- $(WindowsSDKDir_10)Testing\Development\lib\x86;%(AdditionalLibraryDirectories)
- $(WindowsSDKDir_10)Testing\Development\lib\arm64;%(AdditionalLibraryDirectories)
+ C:\Program Files (x86)\Windows Kits\10\Testing\Development\lib\x64;%(AdditionalLibraryDirectories)
+ C:\Program Files (x86)\Windows Kits\10\Testing\Development\lib\x86;%(AdditionalLibraryDirectories)
+ C:\Program Files (x86)\Windows Kits\10\Testing\Development\lib\arm64;%(AdditionalLibraryDirectories)
@@ -110,6 +114,7 @@
+
@@ -189,9 +194,9 @@
Microsoft.Xbox.System.UnitTest
- $(WindowsSDKDir_10)Testing\Runtimes\TAEF\x64\TE.exe
+ C:\Program Files (x86)\Windows Kits\10\Testing\Runtimes\TAEF\x64\TE.exe
$(TargetPath) /inproc
WindowsLocalDebugger
-
\ No newline at end of file
+
diff --git a/Build/libHttpClient.UnitTest.141.TAEF/libHttpClient.UnitTest.141.TAEF.vcxproj.filters b/Build/libHttpClient.UnitTest.141.TAEF/libHttpClient.UnitTest.141.TAEF.vcxproj.filters
index 7971da36..d65a2fa4 100644
--- a/Build/libHttpClient.UnitTest.141.TAEF/libHttpClient.UnitTest.141.TAEF.vcxproj.filters
+++ b/Build/libHttpClient.UnitTest.141.TAEF/libHttpClient.UnitTest.141.TAEF.vcxproj.filters
@@ -99,6 +99,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -222,55 +225,55 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {6D0EEE4B-8A61-37FC-BFB1-2B242FD06B77}
+ {449C188B-2421-3ECF-88BD-7B85E0FFB8B4}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {EC698838-C450-37D0-B39D-05B2997275C7}
+ {D8238937-E47F-352E-AF00-EAAC1AF0C700}
- {07B17B8F-467C-3701-BBA0-ECEAD5ECCC2F}
+ {16308D30-130C-394A-AD28-51E91740ED63}
- {622663E3-C17A-32F2-AFB2-825B97C95BF3}
+ {8DEE0723-9333-3E6E-BD8A-FDE4969E749A}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {1F0C99DD-47D3-3404-8982-9B4C0F5454CE}
+ {216D66A1-4EBE-3C4B-9BAC-88EB74CC3262}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.UnitTest.141.TE/libHttpClient.UnitTest.141.TE.vcxproj b/Build/libHttpClient.UnitTest.141.TE/libHttpClient.UnitTest.141.TE.vcxproj
index fe6a9fc6..7192aff0 100644
--- a/Build/libHttpClient.UnitTest.141.TE/libHttpClient.UnitTest.141.TE.vcxproj
+++ b/Build/libHttpClient.UnitTest.141.TE/libHttpClient.UnitTest.141.TE.vcxproj
@@ -34,7 +34,7 @@
$(IntDir)pch.pch
true
/bigobj /Zm512 %(AdditionalOptions)
- C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\lib\store\references;C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\VC\vcpackages;C:\Program Files (x86)\Windows Kits\10\UnionMetadata;%(AdditionalUsingDirectories)
+ C:\Program Files (x86)\Windows Kits\10\UnionMetadata;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\lib\store\references;%(AdditionalUsingDirectories)
true
@@ -178,6 +178,7 @@
+
@@ -254,4 +255,4 @@
-
\ No newline at end of file
+
diff --git a/Build/libHttpClient.UnitTest.141.TE/libHttpClient.UnitTest.141.TE.vcxproj.filters b/Build/libHttpClient.UnitTest.141.TE/libHttpClient.UnitTest.141.TE.vcxproj.filters
index 07907cfe..3dc05b46 100644
--- a/Build/libHttpClient.UnitTest.141.TE/libHttpClient.UnitTest.141.TE.vcxproj.filters
+++ b/Build/libHttpClient.UnitTest.141.TE/libHttpClient.UnitTest.141.TE.vcxproj.filters
@@ -96,6 +96,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -216,55 +219,55 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {6D0EEE4B-8A61-37FC-BFB1-2B242FD06B77}
+ {449C188B-2421-3ECF-88BD-7B85E0FFB8B4}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {EC698838-C450-37D0-B39D-05B2997275C7}
+ {D8238937-E47F-352E-AF00-EAAC1AF0C700}
- {07B17B8F-467C-3701-BBA0-ECEAD5ECCC2F}
+ {16308D30-130C-394A-AD28-51E91740ED63}
- {622663E3-C17A-32F2-AFB2-825B97C95BF3}
+ {8DEE0723-9333-3E6E-BD8A-FDE4969E749A}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {1F0C99DD-47D3-3404-8982-9B4C0F5454CE}
+ {216D66A1-4EBE-3C4B-9BAC-88EB74CC3262}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.UnitTest.142.TAEF/libHttpClient.UnitTest.142.TAEF.vcxproj b/Build/libHttpClient.UnitTest.142.TAEF/libHttpClient.UnitTest.142.TAEF.vcxproj
index 281cbd02..315a8b94 100644
--- a/Build/libHttpClient.UnitTest.142.TAEF/libHttpClient.UnitTest.142.TAEF.vcxproj
+++ b/Build/libHttpClient.UnitTest.142.TAEF/libHttpClient.UnitTest.142.TAEF.vcxproj
@@ -102,6 +102,7 @@
+
diff --git a/Build/libHttpClient.UnitTest.142.TAEF/libHttpClient.UnitTest.142.TAEF.vcxproj.filters b/Build/libHttpClient.UnitTest.142.TAEF/libHttpClient.UnitTest.142.TAEF.vcxproj.filters
index 7971da36..d65a2fa4 100644
--- a/Build/libHttpClient.UnitTest.142.TAEF/libHttpClient.UnitTest.142.TAEF.vcxproj.filters
+++ b/Build/libHttpClient.UnitTest.142.TAEF/libHttpClient.UnitTest.142.TAEF.vcxproj.filters
@@ -99,6 +99,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -222,55 +225,55 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {6D0EEE4B-8A61-37FC-BFB1-2B242FD06B77}
+ {449C188B-2421-3ECF-88BD-7B85E0FFB8B4}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {EC698838-C450-37D0-B39D-05B2997275C7}
+ {D8238937-E47F-352E-AF00-EAAC1AF0C700}
- {07B17B8F-467C-3701-BBA0-ECEAD5ECCC2F}
+ {16308D30-130C-394A-AD28-51E91740ED63}
- {622663E3-C17A-32F2-AFB2-825B97C95BF3}
+ {8DEE0723-9333-3E6E-BD8A-FDE4969E749A}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {1F0C99DD-47D3-3404-8982-9B4C0F5454CE}
+ {216D66A1-4EBE-3C4B-9BAC-88EB74CC3262}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Build/libHttpClient.UnitTest.142.TE/libHttpClient.UnitTest.142.TE.vcxproj b/Build/libHttpClient.UnitTest.142.TE/libHttpClient.UnitTest.142.TE.vcxproj
index 8f069ff2..db94d543 100644
--- a/Build/libHttpClient.UnitTest.142.TE/libHttpClient.UnitTest.142.TE.vcxproj
+++ b/Build/libHttpClient.UnitTest.142.TE/libHttpClient.UnitTest.142.TE.vcxproj
@@ -178,6 +178,7 @@
+
diff --git a/Build/libHttpClient.UnitTest.142.TE/libHttpClient.UnitTest.142.TE.vcxproj.filters b/Build/libHttpClient.UnitTest.142.TE/libHttpClient.UnitTest.142.TE.vcxproj.filters
index 07907cfe..3dc05b46 100644
--- a/Build/libHttpClient.UnitTest.142.TE/libHttpClient.UnitTest.142.TE.vcxproj.filters
+++ b/Build/libHttpClient.UnitTest.142.TE/libHttpClient.UnitTest.142.TE.vcxproj.filters
@@ -96,6 +96,9 @@
C++ Source\Common
+
+ C++ Source\Common
+
C++ Source\Common
@@ -216,55 +219,55 @@
- {A1D6BFE0-C752-37C4-84A8-DC1BAD7ACDBB}
+ {7AC647CD-3FC4-3617-ACC3-BBFE274959CB}
- {311C2E0C-757A-396B-B005-9C3E2AC974F6}
+ {9DF77FF5-7EF8-3DA6-8C65-36B669024AB4}
- {B9434CE8-713E-36C3-BCDA-769594459CD1}
+ {43E16D74-2A1C-32E2-B3CE-5A63B678C17C}
- {748EFFF4-1C27-379F-90E2-0343E1267432}
+ {5A22794E-EF59-3A69-8DA2-FC7906ABE95D}
- {EBBC7A73-32B3-304C-A088-0766E8E09094}
+ {CAD911E1-C397-3832-9431-A7DC58D7E2E8}
- {6D0EEE4B-8A61-37FC-BFB1-2B242FD06B77}
+ {449C188B-2421-3ECF-88BD-7B85E0FFB8B4}
- {EE80538A-4E77-32F6-9CB6-FD60616A0C52}
+ {D6B64F15-5825-33F1-8FFC-1929189AC0FA}
- {7FBD5635-E218-3828-9907-011F9FEB0020}
+ {EBFE27FD-29C5-3AD4-BFE3-9D4524A9C9EB}
- {C1D0A9B1-A7E8-307D-B0E3-6D0577F43340}
+ {4394D2D2-0582-3D96-91ED-DCDAE0B58239}
- {424D80A0-2669-3072-B27A-D961C7D2D31B}
+ {4DEAFEB9-86B2-3358-BD19-E0AE4159EBE0}
- {839B03FA-A816-3B0D-B78E-80E1B8A6B4E4}
+ {EF64EA95-FEED-3E91-BC0E-4A59FDE0770D}
- {EC698838-C450-37D0-B39D-05B2997275C7}
+ {D8238937-E47F-352E-AF00-EAAC1AF0C700}
- {07B17B8F-467C-3701-BBA0-ECEAD5ECCC2F}
+ {16308D30-130C-394A-AD28-51E91740ED63}
- {622663E3-C17A-32F2-AFB2-825B97C95BF3}
+ {8DEE0723-9333-3E6E-BD8A-FDE4969E749A}
- {3928859A-5E7E-3865-8877-2AD5FBB92278}
+ {8CC08048-6545-3E2E-97E1-12D79A5FA30C}
- {1F0C99DD-47D3-3404-8982-9B4C0F5454CE}
+ {216D66A1-4EBE-3C4B-9BAC-88EB74CC3262}
- {DBC2122A-8939-3C43-8F28-44E5561A58D4}
+ {8FC5B9E5-7989-3075-B3FA-AFD7C7C58F28}
diff --git a/Include/httpClient/httpClient.h b/Include/httpClient/httpClient.h
index c803c8a7..60aedfc2 100644
--- a/Include/httpClient/httpClient.h
+++ b/Include/httpClient/httpClient.h
@@ -677,7 +677,9 @@ STDAPI HCHttpCallResponseGetStatusCode(
/// The network error code of the HTTP call. Possible values are S_OK, or E_FAIL.
/// The platform specific network error code of the HTTP call to be used for tracing / debugging.
/// Result code for this API operation. Possible values are S_OK, E_INVALIDARG, or E_FAIL.
-/// This can only be called after calling HCHttpCallPerformAsync when the HTTP task is completed.
+/// This can only be called after calling HCHttpCallPerformAsync when the HTTP task is completed. On the GDK Platform, HTTP calls that fail
+/// due to the title being suspended will have platformNetworkErrorCode set to HRESULT_FROM_WIN32(PROCESS_SUSPEND_RESUME).
+///
STDAPI HCHttpCallResponseGetNetworkErrorCode(
_In_ HCCallHandle call,
_Out_ HRESULT* networkErrorCode,
diff --git a/Source/Common/Result.h b/Source/Common/Result.h
new file mode 100644
index 00000000..06b21b97
--- /dev/null
+++ b/Source/Common/Result.h
@@ -0,0 +1,88 @@
+#pragma once
+
+template
+class Result
+{
+public:
+ // Construct successful result
+ Result(T&& payload);
+
+ // Failed result (no payload)
+ Result(HRESULT hr);
+
+ Result(const Result&) = default;
+ Result(Result&&) = default;
+ Result& operator=(const Result&) = default;
+ Result& operator=(Result&&) = default;
+ ~Result() = default;
+
+ HRESULT const hr;
+
+ // Get result payload. Asserts if result isn't successful.
+ const T& Payload() const;
+ T&& ExtractPayload();
+
+private:
+ T m_payload{};
+};
+
+// Result specialization without a payload
+template<>
+class Result
+{
+public:
+ // Construct successful result
+ Result();
+
+ // Failed result (no payload)
+ Result(HRESULT hr);
+
+ Result(const Result&) = default;
+ Result(Result&&) = default;
+ Result& operator=(const Result&) = default;
+ Result& operator=(Result&&) = default;
+ ~Result() = default;
+
+ HRESULT const hr;
+};
+
+//------------------------------------------------------------------------------
+// Template implementations
+//------------------------------------------------------------------------------
+
+template
+Result::Result(T&& payload) :
+ hr{ S_OK },
+ m_payload{ std::move(payload) }
+{
+}
+
+template
+Result::Result(HRESULT hr_) :
+ hr{ hr_ }
+{
+}
+
+template
+const T& Result::Payload() const
+{
+ assert(SUCCEEDED(hr));
+ return m_payload;
+}
+
+template
+T&& Result::ExtractPayload()
+{
+ assert(SUCCEEDED(hr));
+ return std::move(m_payload);
+}
+
+inline Result::Result() :
+ hr{ S_OK }
+{
+}
+
+inline Result::Result(HRESULT hr_) :
+ hr{ hr_ }
+{
+}
diff --git a/Source/Global/mem.h b/Source/Global/mem.h
index 2679707f..93ff7d61 100644
--- a/Source/Global/mem.h
+++ b/Source/Global/mem.h
@@ -165,3 +165,5 @@ using http_internal_dequeue = std::deque>;
template
using http_internal_queue = std::queue>;
+template
+using http_internal_list = std::list>;
diff --git a/Source/HTTP/Curl/CurlEasyRequest.cpp b/Source/HTTP/Curl/CurlEasyRequest.cpp
new file mode 100644
index 00000000..e0cf9a9b
--- /dev/null
+++ b/Source/HTTP/Curl/CurlEasyRequest.cpp
@@ -0,0 +1,366 @@
+#include "pch.h"
+#include "CurlEasyRequest.h"
+#include "CurlProvider.h"
+
+namespace xbox
+{
+namespace http_client
+{
+
+CurlEasyRequest::CurlEasyRequest(CURL* curlEasyHandle, HCCallHandle hcCall, XAsyncBlock* async)
+ : m_curlEasyHandle{ curlEasyHandle },
+ m_hcCallHandle{ hcCall },
+ m_asyncBlock{ async }
+{
+}
+
+CurlEasyRequest::~CurlEasyRequest()
+{
+ curl_easy_cleanup(m_curlEasyHandle);
+ curl_slist_free_all(m_headers);
+}
+
+Result> CurlEasyRequest::Initialize(HCCallHandle hcCall, XAsyncBlock* async)
+{
+ CURL* curlEasyHandle{ curl_easy_init() };
+ if (!curlEasyHandle)
+ {
+ HC_TRACE_ERROR(HTTPCLIENT, "CurlEasyRequest::Initialize:: curl_easy_init failed");
+ return E_FAIL;
+ }
+
+ http_stl_allocator a{};
+ HC_UNIQUE_PTR easyRequest{ new (a.allocate(1)) CurlEasyRequest{ curlEasyHandle, hcCall, async } };
+
+ // body (first so we can override things curl "helpfully" sets for us)
+ uint8_t const* body = nullptr;
+ uint32_t bodySize = 0;
+ RETURN_IF_FAILED(HCHttpCallRequestGetRequestBodyBytes(hcCall, &body, &bodySize));
+
+ if (bodySize > 0)
+ {
+ // we set both POSTFIELDSIZE and INFILESIZE because curl uses one or the
+ // other depending on method
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_POSTFIELDSIZE, bodySize));
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_INFILESIZE, bodySize));
+
+ // read callback
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_READFUNCTION, &ReadCallback));
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_READDATA, easyRequest.get()));
+ }
+
+ // url & method
+ char const* url = nullptr;
+ char const* method = nullptr;
+ RETURN_IF_FAILED(HCHttpCallRequestGetUrl(hcCall, &method, &url));
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_URL, url));
+
+ CURLoption opt = CURLOPT_HTTPGET;
+ RETURN_IF_FAILED(MethodStringToOpt(method, opt));
+ if (opt == CURLOPT_CUSTOMREQUEST)
+ {
+ RETURN_IF_FAILED(easyRequest->SetOpt(opt, method));
+ }
+ else
+ {
+ RETURN_IF_FAILED(easyRequest->SetOpt(opt, 1));
+ }
+
+ // headers
+ uint32_t headerCount{ 0 };
+ RETURN_IF_FAILED(HCHttpCallRequestGetNumHeaders(hcCall, &headerCount));
+
+ bool haveUserAgentHeader = false;
+ for (auto i = 0u; i < headerCount; ++i)
+ {
+ char const* name{ nullptr };
+ char const* value{ nullptr };
+ RETURN_IF_FAILED(HCHttpCallRequestGetHeaderAtIndex(hcCall, i, &name, &value));
+ if (std::strcmp(name, "User-Agent") == 0)
+ {
+ haveUserAgentHeader = true;
+ }
+ RETURN_IF_FAILED(easyRequest->AddHeader(name, value));
+ }
+
+ if (!haveUserAgentHeader)
+ {
+ RETURN_IF_FAILED(easyRequest->AddHeader("User-Agent", "libHttpClient/1.0.0.0"));
+ }
+
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_HTTPHEADER, easyRequest->m_headers));
+
+ // timeout
+ uint32_t timeoutSeconds{ 0 };
+ RETURN_IF_FAILED(HCHttpCallRequestGetTimeout(hcCall, &timeoutSeconds));
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_TIMEOUT_MS, timeoutSeconds * 1000));
+
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_VERBOSE, 0)); // verbose logging (0 off, 1 on)
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_HEADER, 0)); // do not write headers to the write callback
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_ERRORBUFFER, easyRequest->m_errorBuffer));
+
+ // write data callback
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_WRITEFUNCTION, &WriteDataCallback));
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_WRITEDATA, easyRequest.get()));
+
+ // write header callback
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_HEADERFUNCTION, &WriteHeaderCallback));
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_HEADERDATA, easyRequest.get()));
+
+ // debug callback
+ RETURN_IF_FAILED(easyRequest->SetOpt(CURLOPT_DEBUGFUNCTION, &DebugCallback));
+
+ return Result>{ std::move(easyRequest) };
+}
+
+CURL* CurlEasyRequest::Handle() const noexcept
+{
+ return m_curlEasyHandle;
+}
+
+void CurlEasyRequest::Complete(CURLcode result)
+{
+ HC_TRACE_VERBOSE(HTTPCLIENT, "CurlEasyRequest::Complete: CURLCode=%ul", result);
+
+ if (result != CURLE_OK)
+ {
+ HC_TRACE_VERBOSE(HTTPCLIENT, "CurlEasyRequest::m_errorBuffer='%s'", m_errorBuffer);
+
+ long platformError = 0;
+ auto curle = curl_easy_getinfo(m_curlEasyHandle, CURLINFO_OS_ERRNO, &platformError);
+ if (curle != CURLE_OK)
+ {
+ return Fail(HrFromCurle(curle));
+ }
+
+ HRESULT hr = HCHttpCallResponseSetNetworkErrorCode(m_hcCallHandle, E_FAIL, static_cast(platformError));
+ assert(SUCCEEDED(hr));
+
+ hr = HCHttpCallResponseSetPlatformNetworkErrorMessage(m_hcCallHandle, curl_easy_strerror(result));
+ assert(SUCCEEDED(hr));
+ }
+ else
+ {
+ long httpStatus = 0;
+ auto curle = curl_easy_getinfo(m_curlEasyHandle, CURLINFO_RESPONSE_CODE, &httpStatus);
+ if (curle != CURLE_OK)
+ {
+ return Fail(HrFromCurle(curle));
+ }
+
+ HRESULT hr = HCHttpCallResponseSetStatusCode(m_hcCallHandle, httpStatus);
+ assert(SUCCEEDED(hr));
+ UNREFERENCED_PARAMETER(hr);
+ }
+
+ // At this point, always complete with XAsync success - http/network errors returned via HCCallHandle
+ XAsyncComplete(m_asyncBlock, S_OK, 0);
+}
+
+void CurlEasyRequest::Fail(HRESULT hr)
+{
+ HC_TRACE_ERROR_HR(HTTPCLIENT, hr, "CurlEasyRequest::Fail");
+ XAsyncComplete(m_asyncBlock, hr, 0);
+}
+
+HRESULT CurlEasyRequest::AddHeader(char const* name, char const* value) noexcept
+{
+ int required = std::snprintf(nullptr, 0, "%s: %s", name, value);
+ assert(required > 0);
+
+ m_headersBuffer.emplace_back();
+ auto& header = m_headersBuffer.back();
+
+ header.resize(static_cast(required), '\0');
+ int written = std::snprintf(&header[0], header.size() + 1, "%s: %s", name, value);
+ assert(written == required);
+ (void)written;
+
+ m_headers = curl_slist_append(m_headers, header.c_str());
+
+ return S_OK;
+}
+
+HRESULT CurlEasyRequest::CopyNextBodySection(void* buffer, size_t maxSize, size_t& bytesCopied) noexcept
+{
+ assert(buffer);
+
+ uint8_t const* body = nullptr;
+ uint32_t bodySize = 0;
+ RETURN_IF_FAILED(HCHttpCallRequestGetRequestBodyBytes(m_hcCallHandle, &body, &bodySize));
+
+ size_t toCopy = 0;
+
+ if (m_bodyCopied == bodySize)
+ {
+ bytesCopied = 0;
+ return S_OK;
+ }
+ else if (maxSize >= bodySize - m_bodyCopied)
+ {
+ // copy everything
+ toCopy = bodySize - m_bodyCopied;
+ }
+ else
+ {
+ // copy as much as we can
+ toCopy = maxSize;
+ }
+
+ void const* startCopyFrom = body + m_bodyCopied;
+ assert(startCopyFrom < body + bodySize);
+
+ m_bodyCopied += toCopy;
+ assert(m_bodyCopied <= bodySize);
+
+ assert(toCopy <= maxSize);
+ memcpy(buffer, startCopyFrom, toCopy);
+
+ bytesCopied = toCopy;
+ return S_OK;
+}
+
+size_t CurlEasyRequest::ReadCallback(char* buffer, size_t size, size_t nitems, void* context) noexcept
+{
+ HC_TRACE_VERBOSE(HTTPCLIENT, "CurlEasyRequest::ReadCallback: reading body data (%llu items of size %llu)", nitems, size);
+
+ auto request = static_cast(context);
+
+ size_t bufferSize = size * nitems;
+ size_t copied = 0;
+ HRESULT hr = request->CopyNextBodySection(buffer, bufferSize, copied);
+ if (FAILED(hr))
+ {
+ return CURL_READFUNC_ABORT;
+ }
+
+ return copied;
+}
+
+size_t CurlEasyRequest::WriteHeaderCallback(char* buffer, size_t size, size_t nitems, void* context) noexcept
+{
+ HC_TRACE_VERBOSE(HTTPCLIENT, "CurlEasyRequest::WriteHeaderCallback: received header (%llu items of size %llu)", nitems, size);
+
+ auto request = static_cast(context);
+
+#if HC_TRACE_INFORMATION_ENABLE
+ if (size * nitems > 2)
+ {
+ HC_TRACE_INFORMATION(HTTPCLIENT, "'%.*s'", size * nitems - 2, buffer); // -2 to avoid printing \r\n
+ }
+#endif
+
+ size_t bufferSize = size * nitems;
+ char const* current = buffer;
+ char const* end = buffer + bufferSize;
+
+ // scan for the end of the header name
+ char const* name = current;
+ size_t nameSize = 0;
+ for (; current < end; ++current)
+ {
+ if (*current == ':')
+ {
+ nameSize = current - buffer;
+ ++current;
+ break;
+ }
+ }
+ if (current == end)
+ {
+ // not a real header, drop it
+ return bufferSize;
+ }
+
+ // skip whitespace
+ for (; current < end && *current == ' '; ++current) // assume that Curl canonicalizes headers
+ {}
+
+ // scan for the end of the header value
+ char const* value = current;
+ size_t valueSize = 0;
+ char const* valueStart = current;
+ for (; current < end; ++current)
+ {
+ if (*current == '\r')
+ {
+ valueSize = current - valueStart;
+ break;
+ }
+ }
+ if (current == end)
+ {
+ // curl should always gives us the new lines at the end of the header
+ assert(false);
+ }
+
+ HRESULT hr = HCHttpCallResponseSetHeaderWithLength(request->m_hcCallHandle, name, nameSize, value, valueSize);
+ assert(SUCCEEDED(hr));
+
+ return bufferSize;
+}
+
+size_t CurlEasyRequest::WriteDataCallback(char* buffer, size_t size, size_t nmemb, void* context) noexcept
+{
+ HC_TRACE_VERBOSE(HTTPCLIENT, "CurlEasyRequest::WriteDataCallback: received data (%llu bytes)", nmemb);
+
+ auto request = static_cast(context);
+
+ HC_TRACE_INFORMATION(HTTPCLIENT, "'%.*s'", nmemb, buffer);
+
+ size_t bufferSize = size * nmemb;
+ HRESULT hr = HCHttpCallResponseAppendResponseBodyBytes(request->m_hcCallHandle, reinterpret_cast(buffer), bufferSize);
+ assert(SUCCEEDED(hr));
+
+ return nmemb;
+}
+
+int CurlEasyRequest::DebugCallback(CURL* /*curlHandle*/, curl_infotype type, char* data, size_t size, void* /*context*/) noexcept
+{
+ char const* event = "";
+ switch (type)
+ {
+ case CURLINFO_TEXT: event = "TEXT"; break;
+ case CURLINFO_HEADER_OUT: event = "HEADER OUT"; break;
+ case CURLINFO_DATA_OUT: event = "DATA OUT"; break;
+ case CURLINFO_SSL_DATA_OUT: event = "SSL OUT"; break;
+ case CURLINFO_HEADER_IN: event = "HEADER IN"; break;
+ case CURLINFO_DATA_IN: event = "DATA IN"; break;
+ case CURLINFO_SSL_DATA_IN: event = "SSL IN"; break;
+ case CURLINFO_END: event = "END"; break;
+ }
+
+ if (type == CURLINFO_TEXT && data[size - 1] == '\n')
+ {
+ size -= 1;
+ }
+
+ HC_TRACE_INFORMATION(HTTPCLIENT, "CURL %10s - %.*s", event, size, data);
+
+ return CURLE_OK;
+}
+
+HRESULT CurlEasyRequest::MethodStringToOpt(char const* method, CURLoption& opt) noexcept
+{
+ if (strcmp(method, "GET") == 0)
+ {
+ opt = CURLOPT_HTTPGET;
+ }
+ else if (strcmp(method, "POST") == 0)
+ {
+ opt = CURLOPT_POST;
+ }
+ else if (strcmp(method, "PUT") == 0)
+ {
+ opt = CURLOPT_UPLOAD;
+ }
+ else
+ {
+ opt = CURLOPT_CUSTOMREQUEST;
+ }
+
+ return S_OK;
+}
+
+}
+}
diff --git a/Source/HTTP/Curl/CurlEasyRequest.h b/Source/HTTP/Curl/CurlEasyRequest.h
new file mode 100644
index 00000000..8f9b9f9e
--- /dev/null
+++ b/Source/HTTP/Curl/CurlEasyRequest.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#if HC_PLATFORM == HC_PLATFORM_GDK
+#include
+#else
+// This path is untested, but this http provider should work with other curl implementations as well.
+// The logic in CurlMulti::Perform is optimized for XCurl, but should work on any curl implementation.
+#include
+#endif
+#include "Result.h"
+
+namespace xbox
+{
+namespace http_client
+{
+
+class CurlEasyRequest
+{
+public:
+ static Result> Initialize(HCCallHandle hcCall, XAsyncBlock* async);
+ CurlEasyRequest(const CurlEasyRequest&) = delete;
+ CurlEasyRequest(CurlEasyRequest&&) = delete;
+ CurlEasyRequest& operator=(const CurlEasyRequest&) = delete;
+ ~CurlEasyRequest();
+
+ CURL* Handle() const noexcept;
+
+ void Complete(CURLcode result);
+ void Fail(HRESULT hr);
+
+private:
+ CurlEasyRequest(CURL* curlEasyHandle, HCCallHandle hcCall, XAsyncBlock* async);
+
+ // Wrapper of curl_easy_setopt. Requires explicit template instantiation to ensure the correct arg is passed
+ template
+ struct OptType
+ {
+ using type = T;
+ };
+ template
+ HRESULT SetOpt(CURLoption option, typename OptType::type) noexcept;
+
+ HRESULT AddHeader(char const* name, char const* value) noexcept;
+ HRESULT CopyNextBodySection(void* buffer, size_t maxSize, size_t& bytesCopied) noexcept;
+
+ // Curl callbacks
+ static size_t ReadCallback(char* buffer, size_t size, size_t nitems, void* context) noexcept;
+ static size_t WriteHeaderCallback(char* buffer, size_t size, size_t nitems, void* context) noexcept;
+ static size_t WriteDataCallback(char* buffer, size_t size, size_t nmemb, void* context) noexcept;
+ static int DebugCallback(CURL* curlHandle, curl_infotype type, char* data, size_t size, void* context) noexcept;
+
+ static HRESULT MethodStringToOpt(char const* method, CURLoption& opt) noexcept;
+
+ CURL* m_curlEasyHandle;
+ HCCallHandle m_hcCallHandle; // non-owning
+ XAsyncBlock* m_asyncBlock; // non-owning
+
+ curl_slist* m_headers{ nullptr };
+ http_internal_list m_headersBuffer{};
+ size_t m_bodyCopied{ 0 };
+ char m_errorBuffer[CURL_ERROR_SIZE]{ 0 };
+};
+
+//------------------------------------------------------------------------------
+// Template implementations
+//------------------------------------------------------------------------------
+
+template
+HRESULT CurlEasyRequest::SetOpt(CURLoption option, typename OptType::type v) noexcept
+{
+ CURLcode result = curl_easy_setopt(m_curlEasyHandle, option, v);
+ if (result != CURLE_OK)
+ {
+ HC_TRACE_ERROR(HTTPCLIENT, "curl_easy_setopt(request, %d, value) failed with %d", option, result);
+ }
+ return HrFromCurle(result);
+}
+
+} // http_client
+} // xbox
diff --git a/Source/HTTP/Curl/CurlMulti.cpp b/Source/HTTP/Curl/CurlMulti.cpp
new file mode 100644
index 00000000..0f90b042
--- /dev/null
+++ b/Source/HTTP/Curl/CurlMulti.cpp
@@ -0,0 +1,168 @@
+#include "pch.h"
+#include "CurlMulti.h"
+#include "CurlProvider.h"
+
+namespace xbox
+{
+namespace http_client
+{
+
+// XCurl doesn't support curl_multi_timeout, so use a small, fixed delay between calls to curl_multi_perform
+#define PERFORM_DELAY_MS 50
+#define POLL_TIMEOUT_MS 0
+
+Result> CurlMulti::Initialize(XTaskQueuePortHandle workPort)
+{
+ assert(workPort);
+
+ http_stl_allocator a{};
+ HC_UNIQUE_PTR multi{ new (a.allocate(1)) CurlMulti };
+
+ multi->m_curlMultiHandle = curl_multi_init();
+ if (!multi->m_curlMultiHandle)
+ {
+ HC_TRACE_ERROR(HTTPCLIENT, "XCurlMulti::Initialize: curl_multi_init failed");
+ return E_FAIL;
+ }
+
+ RETURN_IF_FAILED(XTaskQueueCreateComposite(workPort, workPort, &multi->m_queue));
+
+ return Result>{ std::move(multi) };
+}
+
+CurlMulti::~CurlMulti()
+{
+ if (m_queue)
+ {
+ XTaskQueueTerminate(m_queue, true, nullptr, nullptr);
+ XTaskQueueCloseHandle(m_queue);
+ }
+
+ if (!m_easyRequests.empty())
+ {
+ HC_TRACE_WARNING(HTTPCLIENT, "XCurlMulti::~XCurlMulti: Failing all active requests.");
+ FailAllRequests(E_UNEXPECTED);
+ }
+
+ if (m_curlMultiHandle)
+ {
+ curl_multi_cleanup(m_curlMultiHandle);
+ }
+}
+
+HRESULT CurlMulti::AddRequest(HC_UNIQUE_PTR&& easyRequest)
+{
+ std::unique_lock lock{ m_mutex };
+
+ auto result = curl_multi_add_handle(m_curlMultiHandle, easyRequest->Handle());
+ if (result != CURLM_OK)
+ {
+ HC_TRACE_ERROR(HTTPCLIENT, "XCurlMulti::AddRequest: curl_multi_add_handle failed with CURLCode=%u", result);
+ return HrFromCurlm(result);
+ }
+
+ m_easyRequests.emplace(easyRequest->Handle(), std::move(easyRequest));
+
+ // Release lock before scheduling Perform in case m_queue is an Immediate dispatch queue
+ lock.unlock();
+ RETURN_IF_FAILED(XTaskQueueSubmitCallback(m_queue, XTaskQueuePort::Work, this, CurlMulti::TaskQueueCallback));
+
+ return S_OK;
+}
+
+void CALLBACK CurlMulti::TaskQueueCallback(_In_opt_ void* context, _In_ bool canceled) noexcept
+{
+ if (!canceled)
+ {
+ auto multi = static_cast(context);
+ HRESULT hr = multi->Perform();
+ if (FAILED(hr))
+ {
+ HC_TRACE_ERROR_HR(HTTPCLIENT, hr, "XCurlMulti::Perform failed. Failing all active requests.");
+ multi->FailAllRequests(hr);
+ }
+ }
+}
+
+HRESULT CurlMulti::Perform() noexcept
+{
+ std::unique_lock lock{ m_mutex };
+
+ int runningRequests{ 0 };
+ CURLMcode result = curl_multi_perform(m_curlMultiHandle, &runningRequests);
+ if (result != CURLM_OK)
+ {
+ HC_TRACE_ERROR(HTTPCLIENT, "XCurlMulti::Perform: curl_multi_perform failed with CURLCode=%u", result);
+ return HrFromCurlm(result);
+ }
+
+ int remainingMessages{ 1 }; // assume there is at least 1 message so loop is always entered
+ while (remainingMessages)
+ {
+ CURLMsg* message = curl_multi_info_read(m_curlMultiHandle, &remainingMessages);
+ if (message)
+ {
+ switch (message->msg)
+ {
+ case CURLMSG_DONE:
+ {
+ auto requestIter = m_easyRequests.find(message->easy_handle);
+ assert(requestIter != m_easyRequests.end());
+
+ result = curl_multi_remove_handle(m_curlMultiHandle, message->easy_handle);
+ if (result != CURLM_OK)
+ {
+ HC_TRACE_ERROR(HTTPCLIENT, "XCurlMulti::Perform: curl_multi_remove_handle failed with CURLCode=%u", result);
+ }
+
+ requestIter->second->Complete(message->data.result);
+ m_easyRequests.erase(requestIter);
+ }
+ break;
+ case CURLMSG_NONE:
+ case CURLMSG_LAST:
+ default:
+ {
+ HC_TRACE_ERROR(HTTPCLIENT, "XCurlMulti::Perform: Unrecognized CURLMsg!");
+ assert(false);
+ }
+ break;
+ }
+ }
+ }
+
+ if (runningRequests)
+ {
+ // Reschedule Perform if there are still running requests
+ int workAvailable{ 0 };
+ result = curl_multi_poll(m_curlMultiHandle, nullptr, 0, POLL_TIMEOUT_MS, &workAvailable);
+ if (result != CURLM_OK)
+ {
+ HC_TRACE_ERROR(HTTPCLIENT, "XCurlMulti::Perform: curl_multi_poll failed with CURLCode=%u", result);
+ return HrFromCurlm(result);
+ }
+
+ RETURN_IF_FAILED(XTaskQueueSubmitDelayedCallback(m_queue, XTaskQueuePort::Work, workAvailable ? 0 : PERFORM_DELAY_MS, this, CurlMulti::TaskQueueCallback));
+ }
+
+ return S_OK;
+}
+
+void CurlMulti::FailAllRequests(HRESULT hr) noexcept
+{
+ std::unique_lock lock{ m_mutex };
+
+ for (auto& pair : m_easyRequests)
+ {
+ auto result = curl_multi_remove_handle(m_curlMultiHandle, pair.first);
+ if (FAILED(HrFromCurlm(result)))
+ {
+ HC_TRACE_ERROR(HTTPCLIENT, "XCurlMulti::FailAllRequests: curl_multi_remove_handle failed with CURLCode=%u", result);
+ }
+ pair.second->Fail(hr);
+ }
+ m_easyRequests.clear();
+}
+
+} // http_client
+} // xbox
diff --git a/Source/HTTP/Curl/CurlMulti.h b/Source/HTTP/Curl/CurlMulti.h
new file mode 100644
index 00000000..d1a7c800
--- /dev/null
+++ b/Source/HTTP/Curl/CurlMulti.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "CurlEasyRequest.h"
+#include "Result.h"
+
+namespace xbox
+{
+namespace http_client
+{
+
+class CurlMulti
+{
+public:
+ static Result> Initialize(XTaskQueuePortHandle workPort);
+ CurlMulti(const CurlMulti&) = delete;
+ CurlMulti(CurlMulti&&) = delete;
+ CurlMulti& operator=(const CurlMulti&) = delete;
+ ~CurlMulti();
+
+ // Wrapper around curl_multi_add_handle
+ HRESULT AddRequest(HC_UNIQUE_PTR&& easyRequest);
+
+private:
+ CurlMulti() = default;
+
+ static void CALLBACK TaskQueueCallback(_In_opt_ void* context, _In_ bool canceled) noexcept;
+ HRESULT Perform() noexcept;
+
+ // Fail all active requests due to unexpected CURLM or platform error
+ void FailAllRequests(HRESULT hr) noexcept;
+
+ CURLM* m_curlMultiHandle{ nullptr };
+ XTaskQueueHandle m_queue{ nullptr };
+ std::mutex m_mutex;
+ http_internal_map> m_easyRequests;
+};
+
+} // http_client
+} // xbox
diff --git a/Source/HTTP/Curl/CurlProvider.cpp b/Source/HTTP/Curl/CurlProvider.cpp
new file mode 100644
index 00000000..877a0311
--- /dev/null
+++ b/Source/HTTP/Curl/CurlProvider.cpp
@@ -0,0 +1,126 @@
+#include "pch.h"
+#include "CurlProvider.h"
+#include "CurlEasyRequest.h"
+
+using namespace xbox::http_client;
+
+HRESULT Internal_InitializeHttpPlatform(HCInitArgs* args, PerformEnv& performEnv) noexcept
+{
+ assert(args == nullptr);
+ UNREFERENCED_PARAMETER(args);
+
+ auto initResult = HC_PERFORM_ENV::Initialize();
+ RETURN_IF_FAILED(initResult.hr);
+
+ performEnv = initResult.ExtractPayload();
+
+ return S_OK;
+}
+
+void Internal_CleanupHttpPlatform(HC_PERFORM_ENV* performEnv) noexcept
+{
+ // HC_PERFORM_ENV created with custom deleter - HC_PERFORM_ENV needs to be destroyed and cleaned up explicitly.
+ http_stl_allocator a{};
+ std::allocator_traits>::destroy(a, performEnv);
+ std::allocator_traits>::deallocate(a, performEnv, 1);
+}
+
+HRESULT Internal_SetGlobalProxy(
+ _In_ HC_PERFORM_ENV* performEnv,
+ _In_ const char* proxyUri
+) noexcept
+{
+ UNREFERENCED_PARAMETER(performEnv);
+ UNREFERENCED_PARAMETER(proxyUri);
+ return E_NOTIMPL;
+}
+
+void CALLBACK Internal_HCHttpCallPerformAsync(
+ _In_ HCCallHandle call,
+ _Inout_ XAsyncBlock* asyncBlock,
+ _In_opt_ void* context,
+ _In_ HCPerformEnv env
+) noexcept
+{
+ UNREFERENCED_PARAMETER(context);
+ assert(env);
+
+ HRESULT hr = env->Perform(call, asyncBlock);
+ if (FAILED(hr))
+ {
+ // Complete XAsyncBlock if we fail synchronously
+ XAsyncComplete(asyncBlock, hr, 0);
+ }
+}
+
+namespace xbox
+{
+namespace http_client
+{
+
+HRESULT HrFromCurle(CURLcode c) noexcept
+{
+ switch (c)
+ {
+ case CURLcode::CURLE_OK: return S_OK;
+ case CURLcode::CURLE_BAD_FUNCTION_ARGUMENT: assert(false); return E_INVALIDARG; // Indicates bad provider implementation
+ default: return E_FAIL;
+ }
+}
+
+HRESULT HrFromCurlm(CURLMcode c) noexcept
+{
+ switch (c)
+ {
+ case CURLMcode::CURLM_OK: return S_OK;
+ case CURLMcode::CURLM_BAD_FUNCTION_ARGUMENT: assert(false); return E_INVALIDARG;
+ default: return E_FAIL;
+ }
+}
+
+} // http_client
+} // xbox
+
+Result HC_PERFORM_ENV::Initialize()
+{
+ CURLcode initRes = curl_global_init(CURL_GLOBAL_ALL);
+ RETURN_IF_FAILED(HrFromCurle(initRes));
+
+ http_stl_allocator a{};
+ PerformEnv env{ new (a.allocate(1)) HC_PERFORM_ENV{} };
+
+ return std::move(env);
+}
+
+HC_PERFORM_ENV::~HC_PERFORM_ENV()
+{
+ // make sure XCurlMultis are cleaned up before curl_global_cleanup
+ m_curlMultis.clear();
+
+ curl_global_cleanup();
+}
+
+HRESULT HC_PERFORM_ENV::Perform(HCCallHandle hcCall, XAsyncBlock* async) noexcept
+{
+ XTaskQueuePortHandle workPort{ nullptr };
+ RETURN_IF_FAILED(XTaskQueueGetPort(async->queue, XTaskQueuePort::Work, &workPort));
+
+ HC_TRACE_VERBOSE(HTTPCLIENT, "HC_PERFORM_ENV::Perform: HCCallHandle=%p, workPort=%p", hcCall, workPort);
+
+ auto easyInitResult = CurlEasyRequest::Initialize(hcCall, async);
+ RETURN_IF_FAILED(easyInitResult.hr);
+
+ auto iter = m_curlMultis.find(workPort);
+ if (iter == m_curlMultis.end())
+ {
+ auto multiInitResult = CurlMulti::Initialize(workPort);
+ RETURN_IF_FAILED(multiInitResult.hr);
+
+ iter = m_curlMultis.emplace(workPort, multiInitResult.ExtractPayload()).first;
+ }
+
+ auto& multi{ iter->second };
+ RETURN_IF_FAILED(multi->AddRequest(easyInitResult.ExtractPayload()));
+
+ return S_OK;
+}
diff --git a/Source/HTTP/Curl/CurlProvider.h b/Source/HTTP/Curl/CurlProvider.h
new file mode 100644
index 00000000..45909086
--- /dev/null
+++ b/Source/HTTP/Curl/CurlProvider.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "CurlMulti.h"
+#include "Result.h"
+
+namespace xbox
+{
+namespace http_client
+{
+
+HRESULT HrFromCurle(CURLcode c) noexcept;
+HRESULT HrFromCurlm(CURLMcode c) noexcept;
+
+} // http_client
+} // xbox
+
+struct HC_PERFORM_ENV
+{
+public:
+ static Result Initialize();
+ HC_PERFORM_ENV(const HC_PERFORM_ENV&) = delete;
+ HC_PERFORM_ENV(HC_PERFORM_ENV&&) = delete;
+ HC_PERFORM_ENV& operator=(const HC_PERFORM_ENV&) = delete;
+ virtual ~HC_PERFORM_ENV();
+
+ HRESULT Perform(HCCallHandle hcCall, XAsyncBlock* async) noexcept;
+
+private:
+ HC_PERFORM_ENV() = default;
+
+ // Create an CurlMulti per work port
+ http_internal_map> m_curlMultis{};
+};
diff --git a/Utilities/CMake/CMakeLists.txt b/Utilities/CMake/CMakeLists.txt
index a5d2fe0f..ee61f99d 100644
--- a/Utilities/CMake/CMakeLists.txt
+++ b/Utilities/CMake/CMakeLists.txt
@@ -130,6 +130,15 @@ set(XMLHttp_HTTP_Source_Files
../../../Source/HTTP/XMLHttp/xmlhttp_http_task.h
)
+set(Curl_Source_Files
+ ../../../Source/HTTP/Curl/CurlEasyRequest.cpp
+ ../../../Source/HTTP/Curl/CurlEasyRequest.h
+ ../../../Source/HTTP/Curl/CurlMulti.cpp
+ ../../../Source/HTTP/Curl/CurlMulti.h
+ ../../../Source/HTTP/Curl/CurlProvider.cpp
+ ../../../Source/HTTP/Curl/CurlProvider.h
+ )
+
set(Windows_Logger_Source_Files
../../../Source/Logger/Win/win_logger.cpp
)
@@ -279,14 +288,14 @@ endif()
if( GDK )
message(STATUS "GDK source group")
- source_group("C++ Source\\HTTP\\WinHttp" FILES ${WinHttp_HTTP_Source_Files})
+ source_group("C++ Source\\HTTP\\Curl" FILES ${Curl_Source_Files})
source_group("C++ Source\\Common\\Win" FILES ${Common_Windows_Source_Files})
source_group("C++ Source\\WebSocket\\Win" FILES ${GDK_WebSocket_Source_Files})
source_group("C++ Source\\Logger\\Win" FILES ${Windows_Logger_Source_Files})
list(APPEND
SOURCE_FILES
- ${WinHttp_HTTP_Source_Files}
+ ${Curl_Source_Files}
${Common_Windows_Source_Files}
${Windows_Logger_Source_Files}
${GDK_WebSocket_Source_Files}
diff --git a/Utilities/CMake/GetCommonHCSourceFiles.cmake b/Utilities/CMake/GetCommonHCSourceFiles.cmake
index 2f43b2aa..a9f31861 100644
--- a/Utilities/CMake/GetCommonHCSourceFiles.cmake
+++ b/Utilities/CMake/GetCommonHCSourceFiles.cmake
@@ -33,6 +33,7 @@ function(GET_COMMON_HC_SOURCE_FILES
"${PATH_TO_ROOT}/Source/Common/pch.h"
"${PATH_TO_ROOT}/Source/Common/pch_common.h"
"${PATH_TO_ROOT}/Source/Common/pal_internal.h"
+ "${PATH_TO_ROOT}/Source/Common/Result.h"
"${PATH_TO_ROOT}/Source/Common/ResultMacros.h"
"${PATH_TO_ROOT}/Source/Common/uri.cpp"
"${PATH_TO_ROOT}/Source/Common/uri.h"
diff --git a/libHttpClient.props b/libHttpClient.props
index 2cfbad4b..33f3a306 100644
--- a/libHttpClient.props
+++ b/libHttpClient.props
@@ -87,6 +87,11 @@
+
+
+
+
+