diff --git a/thirdparty/SimpleRestServices/README.md b/thirdparty/SimpleRestServices/README.md new file mode 100644 index 0000000000..6d210364f5 --- /dev/null +++ b/thirdparty/SimpleRestServices/README.md @@ -0,0 +1,6 @@ +SimpleRestServices +================== + +A simple set of REST server and client helpers + +Click here for License Info \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/appveyor.yml b/thirdparty/SimpleRestServices/appveyor.yml new file mode 100644 index 0000000000..58320dc0ab --- /dev/null +++ b/thirdparty/SimpleRestServices/appveyor.yml @@ -0,0 +1,11 @@ +version: 1.0.{build} +init: +- git config --global core.autocrlf true +build_script: +- cd build +- powershell -Command .\build.ps1 -VisualStudioVersion "12.0" -InstallSHFB -Verbosity minimal -Logger "${env:ProgramFiles}\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" +- cd .. +after_build: +- cd build +- powershell -Command .\appveyor-deploy-docs.ps1 +- cd .. diff --git a/thirdparty/SimpleRestServices/build/appveyor-deploy-docs.ps1 b/thirdparty/SimpleRestServices/build/appveyor-deploy-docs.ps1 new file mode 100644 index 0000000000..16bf82e643 --- /dev/null +++ b/thirdparty/SimpleRestServices/build/appveyor-deploy-docs.ps1 @@ -0,0 +1,17 @@ +$DocsPath = "..\src\Documentation\Help" + +# make sure the script was run from the expected path +If (!(Test-Path $DocsPath)) { + $host.ui.WriteErrorLine('The script was run from an invalid working directory.') + Exit 1 +} + +function Upload-Folder() { + param([string]$LocalPath, [string]$ArtifactName) + + [Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') + [System.IO.Compression.ZipFile]::CreateFromDirectory((Join-Path (pwd) $LocalPath), (Join-Path (pwd) $ArtifactName)) + Push-AppveyorArtifact (Join-Path (pwd) $ArtifactName) +} + +Upload-Folder -LocalPath "$DocsPath\v4.0" -ArtifactName "docs.zip" diff --git a/thirdparty/SimpleRestServices/build/build.ps1 b/thirdparty/SimpleRestServices/build/build.ps1 new file mode 100644 index 0000000000..f61d20c437 --- /dev/null +++ b/thirdparty/SimpleRestServices/build/build.ps1 @@ -0,0 +1,133 @@ +param ( + [switch]$Debug, + [string]$VisualStudioVersion = "12.0", + [switch]$NoDocs, + [string]$Verbosity = "normal", + [string]$Logger, + [switch]$InstallSHFB +) + +# build the solution +$SolutionPath = "..\src\SimpleRestServices.sln" + +# make sure the script was run from the expected path +if (!(Test-Path $SolutionPath)) { + $host.ui.WriteErrorLine('The script was run from an invalid working directory.') + exit 1 +} + +. .\version.ps1 + +If ($Debug) { + $BuildConfig = 'Debug' +} Else { + $BuildConfig = 'Release' +} + +If ($Version.Contains('-')) { + $KeyConfiguration = 'Dev' +} Else { + $KeyConfiguration = 'Final' +} + +If ($NoDocs -and -not $Debug) { + $SolutionBuildConfig = $BuildConfig + 'NoDocs' +} Else { + $SolutionBuildConfig = $BuildConfig +} + +# build the main project +$nuget = '..\src\.nuget\NuGet.exe' + +if ($VisualStudioVersion -eq '4.0') { + $msbuild = "$env:windir\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe" +} Else { + $msbuild = "${env:ProgramFiles(x86)}\MSBuild\$VisualStudioVersion\Bin\MSBuild.exe" +} + +# Attempt to restore packages up to 3 times, to improve resiliency to connection timeouts and access denied errors. +$maxAttempts = 3 +For ($attempt = 0; $attempt -lt $maxAttempts; $attempt++) { + &$nuget 'restore' $SolutionPath + If ($?) { + Break + } ElseIf (($attempt + 1) -eq $maxAttempts) { + $host.ui.WriteErrorLine('Failed to restore required NuGet packages, aborting!') + exit $LASTEXITCODE + } +} + +If ($InstallSHFB) { + # This is the NuGet package name for the SHFB package + $SHFBPackageName = 'EWSoftware.SHFB' + # This is the version according to the NuGet package itself + $SHFBVersion = '2014.11.22.0' + + $SHFBPackagePath = "..\.shfb\$SHFBPackageName.$SHFBVersion.nupkg" + If (-not (Test-Path $SHFBPackagePath)) { + If (-not (Test-Path '..\.shfb')) { + mkdir '..\.shfb' + } + + # This is the release name on GitHub where the NuGet package is attached + $SHFBRelease = 'v2014.11.22.0-beta' + + $SHFBInstallerSource = "https://github.com/tunnelvisionlabs/SHFB/releases/download/$SHFBRelease/$SHFBPackageName.$SHFBVersion.nupkg" + Invoke-WebRequest $SHFBInstallerSource -OutFile $SHFBPackagePath + If (-not $?) { + $host.ui.WriteErrorLine('Failed to download the SHFB NuGet package') + Exit $LASTEXITCODE + } + } + + $SHFBPackages = [System.IO.Path]::GetFullPath((Join-Path (pwd) '..\.shfb')) + $SHFBPackagesUri = [System.Uri]$SHFBPackages + Echo "$nuget 'install' 'EWSoftware.SHFB' -Version $SHFBVersion -OutputDirectory '..\src\packages' -Source $SHFBPackagesUri" + &$nuget 'install' $SHFBPackageName -Version $SHFBVersion -OutputDirectory '..\src\packages' -Source $SHFBPackagesUri + If (-not $?) { + $host.ui.WriteErrorLine('Failed to install the SHFB NuGet package') + Exit $LASTEXITCODE + } + + $env:SHFBROOT = [System.IO.Path]::GetFullPath((Join-Path (pwd) "..\src\packages\$SHFBPackageName.$SHFBVersion\tools")) +} + +If (-not $NoDocs) { + If ((-not $env:SHFBROOT) -or (-not (Test-Path $env:SHFBROOT))) { + $host.ui.WriteErrorLine('Could not locate Sandcastle Help File Builder') + Exit 1 + } +} + +If ($Logger) { + $LoggerArgument = "/logger:$Logger" +} + +&$msbuild '/nologo' '/m' '/nr:false' '/t:rebuild' $LoggerArgument "/verbosity:$Verbosity" "/p:Configuration=$SolutionBuildConfig" "/p:Platform=Any CPU" "/p:VisualStudioVersion=$VisualStudioVersion" "/p:KeyConfiguration=$KeyConfiguration" $SolutionPath +if (-not $?) { + $host.ui.WriteErrorLine('Build failed, aborting!') + exit $LASTEXITCODE +} + +# By default, do not create a NuGet package unless the expected strong name key files were used +. .\keys.ps1 + +foreach ($pair in $Keys.GetEnumerator()) { + $assembly = Resolve-FullPath -Path "..\src\SimpleRestServices\bin\$($pair.Key)\$BuildConfig\SimpleRESTServices.dll" + # Run the actual check in a separate process or the current process will keep the assembly file locked + powershell -Command ".\check-key.ps1 -Assembly '$assembly' -ExpectedKey '$($pair.Value)' -Build '$($pair.Key)'" + if (-not $?) { + $host.ui.WriteErrorLine("Failed to verify strong name key for build $($pair.Key).") + Exit $LASTEXITCODE + } +} + +if (-not (Test-Path 'nuget')) { + mkdir "nuget" +} + +# The NuGet packages reference XML documentation which is post-processed by SHFB. If the -NoDocs flag is specified, +# these files are not created so packaging will fail. +If (-not $NoDocs) { + &$nuget 'pack' '..\src\SimpleRestServices\SimpleRestServices.nuspec' '-OutputDirectory' 'nuget' '-Prop' "Configuration=$BuildConfig" '-Version' "$Version" '-Symbols' +} diff --git a/thirdparty/SimpleRestServices/build/check-key.ps1 b/thirdparty/SimpleRestServices/build/check-key.ps1 new file mode 100644 index 0000000000..b92a9cdccf --- /dev/null +++ b/thirdparty/SimpleRestServices/build/check-key.ps1 @@ -0,0 +1,31 @@ +param( + [string]$Assembly, + [string]$ExpectedKey, + [string]$Build = $null +) + +function Get-PublicKeyToken() { + param([string]$assembly = $null) + if ($assembly) { + $bytes = $null + $bytes = [System.Reflection.Assembly]::ReflectionOnlyLoadFrom($assembly).GetName().GetPublicKeyToken() + if ($bytes) { + $key = "" + for ($i=0; $i -lt $bytes.Length; $i++) { + $key += "{0:x2}" -f $bytes[$i] + } + + $key + } + } +} + +if (-not $Build) { + $Build = $Assembly +} + +$actual = Get-PublicKeyToken -assembly $Assembly +if ($actual -ne $ExpectedKey) { + $host.ui.WriteErrorLine("Invalid publicKeyToken for '$Build'; expected '$ExpectedKey' but found '$actual'") + exit 1 +} diff --git a/thirdparty/SimpleRestServices/build/keys.ps1 b/thirdparty/SimpleRestServices/build/keys.ps1 new file mode 100644 index 0000000000..32bc0c536f --- /dev/null +++ b/thirdparty/SimpleRestServices/build/keys.ps1 @@ -0,0 +1,25 @@ +# Note: these values may only change during major release +# Also, if the values change, assembly binding redirection will not work between the affected releases. + +If ($Version.Contains('-')) { + + # Use the development keys + $Keys = @{ + 'v3.5' = '579ef5a5d8b3751c' + 'v4.0' = '579ef5a5d8b3751c' + } + +} Else { + + # Use the final release keys + $Keys = @{ + 'v3.5' = '541c51dcbcf0ec3c' + 'v4.0' = '541c51dcbcf0ec3c' + } + +} + +function Resolve-FullPath() { + param([string]$Path) + [System.IO.Path]::GetFullPath((Join-Path (pwd) $Path)) +} diff --git a/thirdparty/SimpleRestServices/build/keys/TestingKey.snk b/thirdparty/SimpleRestServices/build/keys/TestingKey.snk new file mode 100644 index 0000000000..64f666a8f6 Binary files /dev/null and b/thirdparty/SimpleRestServices/build/keys/TestingKey.snk differ diff --git a/thirdparty/SimpleRestServices/build/keys/simplerestservices.dev.snk b/thirdparty/SimpleRestServices/build/keys/simplerestservices.dev.snk new file mode 100644 index 0000000000..a302d290ec Binary files /dev/null and b/thirdparty/SimpleRestServices/build/keys/simplerestservices.dev.snk differ diff --git a/thirdparty/SimpleRestServices/build/keys/simplerestservices.snk b/thirdparty/SimpleRestServices/build/keys/simplerestservices.snk new file mode 100644 index 0000000000..ac5b7c1164 Binary files /dev/null and b/thirdparty/SimpleRestServices/build/keys/simplerestservices.snk differ diff --git a/thirdparty/SimpleRestServices/build/push.ps1 b/thirdparty/SimpleRestServices/build/push.ps1 new file mode 100644 index 0000000000..a1c82fbdd7 --- /dev/null +++ b/thirdparty/SimpleRestServices/build/push.ps1 @@ -0,0 +1,8 @@ +. .\version.ps1 + +If ($Version.EndsWith('-dev')) { + $host.ui.WriteErrorLine("Cannot push development version '$Version' to NuGet.") + Exit 1 +} + +..\src\.nuget\NuGet.exe 'push' ".\nuget\SimpleRestServices.$Version.nupkg" diff --git a/thirdparty/SimpleRestServices/build/version.ps1 b/thirdparty/SimpleRestServices/build/version.ps1 new file mode 100644 index 0000000000..301eb5a36a --- /dev/null +++ b/thirdparty/SimpleRestServices/build/version.ps1 @@ -0,0 +1 @@ +$Version = "1.3.0.3-dev" diff --git a/thirdparty/SimpleRestServices/src/.nuget/NuGet.Config b/thirdparty/SimpleRestServices/src/.nuget/NuGet.Config new file mode 100644 index 0000000000..67f8ea046e --- /dev/null +++ b/thirdparty/SimpleRestServices/src/.nuget/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/.nuget/NuGet.exe b/thirdparty/SimpleRestServices/src/.nuget/NuGet.exe new file mode 100644 index 0000000000..9cba6edbfc Binary files /dev/null and b/thirdparty/SimpleRestServices/src/.nuget/NuGet.exe differ diff --git a/thirdparty/SimpleRestServices/src/Documentation/Content/MSHelpViewerRoot.aml b/thirdparty/SimpleRestServices/src/Documentation/Content/MSHelpViewerRoot.aml new file mode 100644 index 0000000000..fcc870ff67 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/Documentation/Content/MSHelpViewerRoot.aml @@ -0,0 +1,18 @@ + + + + + Welcome to the SimpleRESTServices Library Reference + + +
+ + Select a topic from the table of contents. + +
+ + + + +
+
diff --git a/thirdparty/SimpleRestServices/src/Documentation/Content/Welcome.aml b/thirdparty/SimpleRestServices/src/Documentation/Content/Welcome.aml new file mode 100644 index 0000000000..47f825a439 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/Documentation/Content/Welcome.aml @@ -0,0 +1,17 @@ + + + + + + + Welcome to the SimpleRESTServices libary. If you have any information, tips, updates, or corrections that + you would like to see added to the guide, feel free to submit them to the author using the + Send Feedback link at the bottom of the page or the e-mail link in the page footer. + + + + + + diff --git a/thirdparty/SimpleRestServices/src/Documentation/Documentation.v3.5.shfbproj b/thirdparty/SimpleRestServices/src/Documentation/Documentation.v3.5.shfbproj new file mode 100644 index 0000000000..9d22b85523 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/Documentation/Documentation.v3.5.shfbproj @@ -0,0 +1,101 @@ + + + + + Debug + AnyCPU + 2.0 + 93356b99-d84c-4291-b739-ef8ec6a9b382 + 1.9.9.0 + + Documentation + Documentation + Documentation + + .NET Framework 3.5 + .\Help\v3.5\ + SimpleRESTServices + en-US + + + + OnlyWarningsAndErrors + Website + False + True + False + False + True + Standard + Blank + API Reference + True + VS2013 + False + MemberName + SimpleRESTServices API Reference Documentation + openstack.net%40lists.rackspace.com + AboveNamespaces + Msdn + Msdn + True + True + Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, ProtectedInternalAsProtected, SealedProtected + + + + + + + + + + + + + + + + + + + + + 2 + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/Documentation/Documentation.v4.0.shfbproj b/thirdparty/SimpleRestServices/src/Documentation/Documentation.v4.0.shfbproj new file mode 100644 index 0000000000..8ca6cf4bba --- /dev/null +++ b/thirdparty/SimpleRestServices/src/Documentation/Documentation.v4.0.shfbproj @@ -0,0 +1,97 @@ + + + + + Debug + AnyCPU + 2.0 + 7ac93313-d825-4668-a188-b7c9f21ddb37 + 1.9.9.0 + + Documentation + Documentation + Documentation.v4.0 + + .NET Framework 4.0 + .\Help\v4.0\ + SimpleRESTServices + en-US + + + + OnlyWarningsAndErrors + Website + False + True + False + False + True + Standard + Blank + API Reference + True + VS2013 + False + MemberName + SimpleRESTServices API Reference Documentation + openstack.net%40lists.rackspace.com + AboveNamespaces + Msdn + Msdn + True + True + Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, ProtectedInternalAsProtected, SealedProtected + + + + + + + + + + + + + + + + + 2 + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/Documentation/SimpleRestServices.content b/thirdparty/SimpleRestServices/src/Documentation/SimpleRestServices.content new file mode 100644 index 0000000000..3b4403fac5 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/Documentation/SimpleRestServices.content @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/Local.testsettings b/thirdparty/SimpleRestServices/src/Local.testsettings new file mode 100644 index 0000000000..f869995adf --- /dev/null +++ b/thirdparty/SimpleRestServices/src/Local.testsettings @@ -0,0 +1,10 @@ + + + These are default test settings for a local test run. + + + + + + + \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices.sln b/thirdparty/SimpleRestServices/src/SimpleRestServices.sln new file mode 100644 index 0000000000..b1fcc62beb --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices.sln @@ -0,0 +1,89 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleRestServices.v4.0", "SimpleRestServices\SimpleRestServices.v4.0.csproj", "{4A44EB7C-06D5-43F0-B660-F684CBAAC99F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "Testing\UnitTests\UnitTests.csproj", "{BB206928-0F2E-46A1-B438-D3ED9AF72BA1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D7C8177E-0A12-419B-B1BD-AEFD365BA657}" + ProjectSection(SolutionItems) = preProject + ..\appveyor.yml = ..\appveyor.yml + Local.testsettings = Local.testsettings + SimpleRestServices.vsmdi = SimpleRestServices.vsmdi + TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Testing", "Testing", "{F5B9B422-570A-4797-8F59-7A8C13A8934D}" +EndProject +Project("{7CF6DF6D-3B04-46F8-A40B-537D21BCA0B4}") = "Documentation.v4.0", "Documentation\Documentation.v4.0.shfbproj", "{7AC93313-D825-4668-A188-B7C9F21DDB37}" + ProjectSection(ProjectDependencies) = postProject + {4A44EB7C-06D5-43F0-B660-F684CBAAC99F} = {4A44EB7C-06D5-43F0-B660-F684CBAAC99F} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleRestServices.v3.5", "SimpleRestServices\SimpleRestServices.v3.5.csproj", "{1960D862-8AD9-48BE-9290-B7E23EA03D5C}" +EndProject +Project("{7CF6DF6D-3B04-46F8-A40B-537D21BCA0B4}") = "Documentation.v3.5", "Documentation\Documentation.v3.5.shfbproj", "{93356B99-D84C-4291-B739-EF8EC6A9B382}" + ProjectSection(ProjectDependencies) = postProject + {1960D862-8AD9-48BE-9290-B7E23EA03D5C} = {1960D862-8AD9-48BE-9290-B7E23EA03D5C} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{A57581E8-CE20-4E4A-81AA-B6BB5611D10F}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.Config = .nuget\NuGet.Config + .nuget\NuGet.exe = .nuget\NuGet.exe + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{377DB120-46E3-4D5C-956B-A05F9987BF6F}" + ProjectSection(SolutionItems) = preProject + ..\build\appveyor-deploy-docs.ps1 = ..\build\appveyor-deploy-docs.ps1 + ..\build\build.ps1 = ..\build\build.ps1 + ..\build\check-key.ps1 = ..\build\check-key.ps1 + ..\build\keys.ps1 = ..\build\keys.ps1 + ..\build\push.ps1 = ..\build\push.ps1 + ..\build\version.ps1 = ..\build\version.ps1 + EndProjectSection +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = SimpleRestServices.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + ReleaseNoDocs|Any CPU = ReleaseNoDocs|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4A44EB7C-06D5-43F0-B660-F684CBAAC99F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A44EB7C-06D5-43F0-B660-F684CBAAC99F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A44EB7C-06D5-43F0-B660-F684CBAAC99F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A44EB7C-06D5-43F0-B660-F684CBAAC99F}.Release|Any CPU.Build.0 = Release|Any CPU + {4A44EB7C-06D5-43F0-B660-F684CBAAC99F}.ReleaseNoDocs|Any CPU.ActiveCfg = Release|Any CPU + {4A44EB7C-06D5-43F0-B660-F684CBAAC99F}.ReleaseNoDocs|Any CPU.Build.0 = Release|Any CPU + {BB206928-0F2E-46A1-B438-D3ED9AF72BA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BB206928-0F2E-46A1-B438-D3ED9AF72BA1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BB206928-0F2E-46A1-B438-D3ED9AF72BA1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BB206928-0F2E-46A1-B438-D3ED9AF72BA1}.Release|Any CPU.Build.0 = Release|Any CPU + {BB206928-0F2E-46A1-B438-D3ED9AF72BA1}.ReleaseNoDocs|Any CPU.ActiveCfg = Release|Any CPU + {BB206928-0F2E-46A1-B438-D3ED9AF72BA1}.ReleaseNoDocs|Any CPU.Build.0 = Release|Any CPU + {7AC93313-D825-4668-A188-B7C9F21DDB37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AC93313-D825-4668-A188-B7C9F21DDB37}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AC93313-D825-4668-A188-B7C9F21DDB37}.Release|Any CPU.Build.0 = Release|Any CPU + {7AC93313-D825-4668-A188-B7C9F21DDB37}.ReleaseNoDocs|Any CPU.ActiveCfg = Release|Any CPU + {1960D862-8AD9-48BE-9290-B7E23EA03D5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1960D862-8AD9-48BE-9290-B7E23EA03D5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1960D862-8AD9-48BE-9290-B7E23EA03D5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1960D862-8AD9-48BE-9290-B7E23EA03D5C}.Release|Any CPU.Build.0 = Release|Any CPU + {1960D862-8AD9-48BE-9290-B7E23EA03D5C}.ReleaseNoDocs|Any CPU.ActiveCfg = Release|Any CPU + {1960D862-8AD9-48BE-9290-B7E23EA03D5C}.ReleaseNoDocs|Any CPU.Build.0 = Release|Any CPU + {93356B99-D84C-4291-B739-EF8EC6A9B382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {93356B99-D84C-4291-B739-EF8EC6A9B382}.Release|Any CPU.ActiveCfg = Release|Any CPU + {93356B99-D84C-4291-B739-EF8EC6A9B382}.Release|Any CPU.Build.0 = Release|Any CPU + {93356B99-D84C-4291-B739-EF8EC6A9B382}.ReleaseNoDocs|Any CPU.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {BB206928-0F2E-46A1-B438-D3ED9AF72BA1} = {F5B9B422-570A-4797-8F59-7A8C13A8934D} + EndGlobalSection +EndGlobal diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices.vsmdi b/thirdparty/SimpleRestServices/src/SimpleRestServices.vsmdi new file mode 100644 index 0000000000..573d7a9231 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices.vsmdi @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/HttpHeader.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/HttpHeader.cs new file mode 100644 index 0000000000..9a65a8c2b3 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/HttpHeader.cs @@ -0,0 +1,70 @@ +using System; +using System.Diagnostics; + +namespace JSIStudios.SimpleRESTServices.Client +{ + /// + /// Represents a single header included with an HTTP response. + /// + [Serializable] + [DebuggerDisplay("{Key,nq} = {Value,nq}")] + public class HttpHeader + { + /// + /// The HTTP header key. + /// + private readonly string _key; + + /// + /// The HTTP header value. + /// + private readonly string _value; + + /// + /// Gets the HTTP header key. + /// + public string Key + { + get + { + return _key; + } + } + + /// + /// Gets the HTTP header value. + /// + public string Value + { + get + { + return _value; + } + } + + /// + /// Initializes a new instance of the class using the specified + /// key and value. + /// + /// The HTTP header key. + /// The HTTP header value. + /// + /// If is null. + /// -or- + /// If is null. + /// + /// If is empty. + public HttpHeader(string key, string value) + { + if (key == null) + throw new ArgumentNullException("key"); + if (value == null) + throw new ArgumentNullException("value"); + if (string.IsNullOrEmpty(key)) + throw new ArgumentException("key cannot be empty"); + + _key = key; + _value = value; + } + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/HttpMethod.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/HttpMethod.cs new file mode 100644 index 0000000000..036c658930 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/HttpMethod.cs @@ -0,0 +1,68 @@ +namespace JSIStudios.SimpleRESTServices.Client +{ + /// + /// Represents the types of HTTP protocol methods that can be used with a REST request. + /// + public enum HttpMethod + { + /// + /// Represents an HTTP GET protocol method. + /// + GET, + + /// + /// Represents an HTTP POST protocol method that is used to post a new entity + /// as an addition to a URI. + /// + POST, + + /// + /// Represents an HTTP PUT protocol method that is used to replace an entity + /// identified by a URI. + /// + PUT, + + /// + /// Represents an HTTP DELETE protocol method. + /// + DELETE, + + /// + /// Represents an HTTP HEAD protocol method. The method is identical to + /// except that the server only returns message-headers in the response, + /// without a message-body. + /// + HEAD, + + /// + /// Represents an HTTP PATCH protocol method. + /// + PATCH, + + /// + /// Represents an HTTP OPTIONS protocol method. + /// + OPTIONS, + + /// + /// Represents an HTTP TRACE protocol method. + /// + TRACE, + + /// + /// Represents the HTTP CONNECT protocol method that is used with a proxy that + /// can dynamically switch to tunneling, as in the case of SSL tunneling. + /// + CONNECT, + + /// + /// Represents an HTTP COPY protocol method. + /// + COPY, + + /// + /// Represents an HTTP MOVE protocol method. + /// + MOVE, + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/IStringSerializer.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/IStringSerializer.cs new file mode 100644 index 0000000000..16e68bde51 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/IStringSerializer.cs @@ -0,0 +1,31 @@ +using JSIStudios.SimpleRESTServices.Client.Json; + +namespace JSIStudios.SimpleRESTServices.Client +{ + /// + /// This interface provides simple support for serializing and deserializing generic objects to and from strings. + /// + public interface IStringSerializer + { + /// + /// Deserializes an object from a string. + /// + /// The type of the object to deserialize. + /// The serialized representation of the object. + /// An instance of which describes. + /// If could not be deserialized to an object of type . + T Deserialize(string content); + + /// + /// Serializes an object to a string. + /// + /// + /// The value returned by this method is suitable for deserialization using . + /// + /// The type of the object to serialize. + /// The object to serialize + /// A serialized string representation of . + /// If could not be serialized to a string. + string Serialize(T obj); + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Json/JsonRequestSettings.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Json/JsonRequestSettings.cs new file mode 100644 index 0000000000..fe6953552d --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Json/JsonRequestSettings.cs @@ -0,0 +1,27 @@ +namespace JSIStudios.SimpleRESTServices.Client.Json +{ + /// + /// Extends by setting the default + /// and values to application/json. + /// + public class JsonRequestSettings : RequestSettings + { + /// + /// The content type (MIME type) for a JSON request or response. + /// + /// + /// This value is equal to application/json. + /// + public static readonly string JsonContentType = "application/json"; + + /// + /// Initializes a new instance of the class with the default value + /// application/json for and . + /// + public JsonRequestSettings() + { + ContentType = JsonContentType; + Accept = JsonContentType; + } + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Json/JsonRestService.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Json/JsonRestService.cs new file mode 100644 index 0000000000..4281e671af --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Json/JsonRestService.cs @@ -0,0 +1,59 @@ +using System; +using System.Net; + +using JSIStudios.SimpleRESTServices.Core; + +namespace JSIStudios.SimpleRESTServices.Client.Json +{ + /// + /// An implementation of that uses JSON notation for + /// the serialized representation of objects. + /// + public class JsonRestServices : RestServiceBase, IRestService + { + /// + /// Initializes a new instance of the class with the default + /// JSON string serializer, retry logic, and URL builder. + /// + public JsonRestServices():this(null) {} + + /// + /// Initializes a new instance of the class with the specified + /// request logger and the default JSON string serializer and URL builder. + /// + /// The logger to use for requests. Specify null if requests do not need to be logged. + public JsonRestServices(IRequestLogger requestLogger) : this(requestLogger, new RequestRetryLogic(), new UrlBuilder(), new JsonStringSerializer()) {} + + /// + /// Initializes a new instance of the class with the specified + /// logger, retry logic, URI builder, and string serializer. + /// + /// The logger to use for requests. Specify null if requests do not need to be logged. + /// The retry logic to use for REST operations. + /// The URL builder to use for constructing URLs with query parameters. + /// The string serializer to use for requests from this service. + /// + /// If is null. + /// -or- + /// If is null. + /// -or- + /// If is null. + /// + public JsonRestServices(IRequestLogger logger, IRetryLogic retryLogic, IUrlBuilder urlBuilder, IStringSerializer stringSerializer) : base(stringSerializer, logger, retryLogic, urlBuilder) { } + + /// + /// Gets the default to use for requests sent from this service. + /// + /// + /// This implementation uses a new instance of as the + /// default request settings. + /// + protected override RequestSettings DefaultRequestSettings + { + get + { + return new JsonRequestSettings(); + } + } + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Json/JsonStringSerializer.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Json/JsonStringSerializer.cs new file mode 100644 index 0000000000..748cf27f13 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Json/JsonStringSerializer.cs @@ -0,0 +1,86 @@ +using System; +using Newtonsoft.Json; + +namespace JSIStudios.SimpleRESTServices.Client.Json +{ + /// + /// Provides a default implementation of using JSON for + /// the underlying serialized notation. + /// + public class JsonStringSerializer : IStringSerializer + { + /// + public T Deserialize(string content) + { + if (string.IsNullOrEmpty(content)) + return default(T); + + try + { + return JsonConvert.DeserializeObject(content, + new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }); + } + catch (JsonReaderException ex) + { + throw new StringSerializationException(ex); + } + catch (JsonSerializationException ex) + { + throw new StringSerializationException(ex); + } + } + + /// + public string Serialize(T obj) + { + if (Equals(obj, default(T))) + return null; + + try + { + return JsonConvert.SerializeObject(obj, + new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }); + } + catch (JsonReaderException ex) + { + throw new StringSerializationException(ex); + } + catch (JsonSerializationException ex) + { + throw new StringSerializationException(ex); + } + } + } + + /// + /// The exception thrown when string serialization or deserialization fails. + /// + public class StringSerializationException : Exception + { + /// + /// Initializes a new instance of the class + /// with a reference to the inner exception that is the cause of this exception. + /// + /// The exception that is the cause of the current exception. + /// If the parameter is not a null reference, the current + /// exception is raised in a catch block that handles the inner exception. + public StringSerializationException(Exception innerException) + : base(GetMessageFromInnerException(innerException, "An error occurred during string serialization."), innerException) + { + } + + private static string GetMessageFromInnerException(Exception innerException, string defaultMessage) + { + if (innerException == null) + return defaultMessage; + + return innerException.Message ?? defaultMessage; + } + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/RequestSettings.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/RequestSettings.cs new file mode 100644 index 0000000000..5e21c74d7b --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/RequestSettings.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Net; +using JSIStudios.SimpleRESTServices.Client.Json; +using JSIStudios.SimpleRESTServices.Core; + +namespace JSIStudios.SimpleRESTServices.Client +{ + /// + /// Specifies the settings for an HTTP REST request. + /// + /// + /// The base implementation does not specify values for the + /// or properties. In most cases, these should be properly + /// set for the particular application either manually or in the constructor of a derived class + /// (e.g. ). + /// + public class RequestSettings + { + /// + /// Gets or sets the value of the Content-Type HTTP header. If this value is + /// null, the Content-Type header is omitted from the request. + /// + /// + /// In the base implementation, the default value is null. + /// + public virtual string ContentType { get; set; } + + /// + /// Gets or sets the number of times this request should be retried if it fails. + /// + /// + /// In the base implementation, the default value is 0. + /// + public int RetryCount { get; set; } + + /// + /// Gets or sets the delay before retrying a failed request. + /// + /// + /// In the base implementation, the default value is . + /// + public TimeSpan RetryDelay { get; set; } + + /// + /// Gets or sets the set of HTTP status codes greater than or equal to 300 which + /// should be considered a successful result for this request. A value of + /// null is allowed, and should be treated as an empty collection. + /// + /// + /// In the base implementation, the default value is null. + /// + public IEnumerable Non200SuccessCodes { get; set; } + + /// + /// Gets or sets the HTTP Accept header, which specifies the MIME types that are + /// acceptable for the response. If this value is null, the Accept header + /// is omitted from the request. + /// + /// + /// In the base implementation, the default value is null. + /// + public virtual string Accept { get; set; } + + /// + /// Gets or sets a map of user-defined actions to execute in response to specific + /// HTTP status codes. A value of null is allowed, and should be treated as + /// an empty collection. + /// + /// + /// In the base implementation, the default value is null. + /// + /// If this value is non-null, and the request results in a status code not + /// present in this collection, no custom action is executed for the response. + /// + public Dictionary> ResponseActions { get; set; } + + /// + /// Gets or sets the value of the User-Agent HTTP header. If this value is null, + /// the User-Agent header is omitted from the request. + /// + /// + /// In the base implementation, the default value is null. + /// + public string UserAgent { get; set; } + + /// + /// Gets or sets the credentials to use for this request. This value can be + /// null if credentials are not specified. + /// + /// + /// In the base implementation, the default value is null. + /// + public ICredentials Credentials { get; set; } + + /// + /// Gets or sets the request timeout. + /// + /// + /// The time to wait before the request times out. In the base + /// implementation, the default value is 100,000 milliseconds (100 seconds). + /// + public TimeSpan Timeout { get; set; } + + /// + /// Gets or sets a value indicating whether to send data in segments to the + /// Internet resource. + /// + /// + /// true to send data to the Internet resource in segments; otherwise, + /// false. In the base implementation, the default value is false. + /// + public bool ChunkRequest { get; set; } + + /// + /// Gets or sets a user-defined collection to pass as the final argument to the + /// callback method. + /// + /// + /// This value not used directly within SimpleRESTServices. + /// + public Dictionary ExtendedLoggingData { get; set; } + + /// + /// Gets or sets the value of the Content-Length HTTP header. + /// + /// + /// When this value is 0, the property controls + /// whether or not the Content-Length header is included with the request. + /// + /// In the base implementation, the default value is 0. + /// + public long ContentLength { get; set; } + + /// + /// Gets or sets a value indicating whether or not 0 is a valid value for the Content-Length HTTP header + /// for this request. + /// + /// + /// When is non-zero, this value is ignored. + /// When is zero and this is true, the + /// Content-Length HTTP header is added to the request with an explicit value of 0. + /// Otherwise, when is 0 the Content-Length HTTP header + /// is omitted from the request. + /// + /// In the base implementation, the default value is false. + /// + public bool AllowZeroContentLength { get; set; } + + /// + /// Gets or sets the maximum number of connections allowed on the object + /// used for the request. If the value is null, the connection limit value for the + /// object is not altered. + /// + public int? ConnectionLimit + { + get; + set; + } + + /// + /// Gets or sets a value indicating whether the request should follow redirection responses. + /// + /// + /// The default value is . + /// + /// + /// if the request should follow redirection responses; otherwise, + /// . + /// + /// + public bool AllowAutoRedirect { get; set; } + + /// + /// Initializes a new instance of the class with the default values. + /// + public RequestSettings() + { + RetryCount = 0; + RetryDelay = TimeSpan.Zero; + Non200SuccessCodes = null; + Timeout = TimeSpan.FromMilliseconds(100000); + AllowAutoRedirect = true; + } + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Response.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Response.cs new file mode 100644 index 0000000000..2dea80f118 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/Response.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Net; + +namespace JSIStudios.SimpleRESTServices.Client +{ + /// + /// Represents the basic response of an HTTP REST request, where the body of the response + /// is stored as a text string. + /// + [Serializable] + public class Response + { + /// + /// Gets the HTTP status code for this response. + /// + public HttpStatusCode StatusCode { get; private set; } + + /// + /// Gets a string representation of the HTTP status code for this response. + /// + public string Status { get; private set; } + + /// + /// Gets a collection of all HTTP headers included with this response. + /// + public IList Headers { get; private set; } + + /// + /// Gets the raw body of this HTTP response as a text string. + /// + public string RawBody { get; private set; } + + /// + /// Initializes a new instance of the class with the given HTTP status code, + /// status, headers, and raw body. + /// + /// The HTTP status code. + /// A string representation of the HTTP status code. + /// A collection of all HTTP headers included with this response. + /// + /// The raw body of this HTTP response as a text string. When included in the response, this + /// value should be loaded with the encoding specified in the Content-Encoding and/or + /// Content-Type HTTP headers. + /// + public Response(HttpStatusCode responseCode, string status, IList headers, string rawBody) + { + StatusCode = responseCode; + Status = status; + Headers = headers; + RawBody = rawBody; + } + + /// + /// Initializes a new instance of the class with the given HTTP status code, + /// headers, and raw body. + /// + /// The HTTP status code. + /// A collection of all HTTP headers included with this response. + /// + /// The raw body of this HTTP response as a text string. When included in the response, this + /// value should be loaded with the encoding specified in the Content-Encoding and/or + /// Content-Type HTTP headers. + /// + public Response(HttpStatusCode statusCode, IList headers, string rawBody) + : this(statusCode, statusCode.ToString(), headers, rawBody) + { + } + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/ResponseOfT.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/ResponseOfT.cs new file mode 100644 index 0000000000..4ce9611352 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/ResponseOfT.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Net; + +namespace JSIStudios.SimpleRESTServices.Client +{ + /// + /// Extends to include a strongly-typed return value + /// from the response. + /// + /// The type of the data included with the response. + [Serializable] + public class Response : Response + { + /// + /// Gets the strongly-typed representation of the value included with this response. + /// + public T Data { get; private set; } + + /// + /// Initializes a new instance of the class with the given HTTP status code, + /// status, strongly-type data, headers, and raw body. + /// + /// The HTTP status code. + /// A string representation of the HTTP status code. + /// The strongly-typed data representation of the value returned with this response. + /// A collection of all HTTP headers included with this response. + /// + /// The raw body of this HTTP response as a text string. When included in the response, this + /// value should be loaded with the encoding specified in the Content-Encoding and/or + /// Content-Type HTTP headers. + /// + public Response(HttpStatusCode responseCode, string status, T data, IList headers, string rawBody) + : base(responseCode, status, headers, rawBody) + { + Data = data; + } + + /// + /// Initializes a new instance of the class with the given HTTP status code, + /// strongly-type data, headers, and raw body. + /// + /// The HTTP status code. + /// The strongly-typed data representation of the value returned with this response. + /// A collection of all HTTP headers included with this response. + /// + /// The raw body of this HTTP response as a text string. When included in the response, this + /// value should be loaded with the encoding specified in the Content-Encoding and/or + /// Content-Type HTTP headers. + /// + public Response(HttpStatusCode statusCode, T data, IList headers, string rawBody) + : this(statusCode, statusCode.ToString(), data, headers, rawBody) + { + } + + /// + /// Initializes a new instance of the class by adding a strongly-typed + /// data value to a base response. + /// + /// The base response. + /// The strongly-typed data representation of the value returned with this response. + public Response(Response baseResponse, T data) + : this((baseResponse == null) ? default(int) : baseResponse.StatusCode, + (baseResponse == null) ? null : baseResponse.Status, data, + (baseResponse == null) ? null : baseResponse.Headers, + (baseResponse == null) ? null : baseResponse.RawBody) { } + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/RestServiceBase.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/RestServiceBase.cs new file mode 100644 index 0000000000..407cc235fe --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/RestServiceBase.cs @@ -0,0 +1,583 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using JSIStudios.SimpleRESTServices.Client.Json; +using JSIStudios.SimpleRESTServices.Core; +#if !NET35 +using System.Diagnostics.Contracts; +#endif + +namespace JSIStudios.SimpleRESTServices.Client +{ + /// + /// Implements basic support for in terms of an implementation + /// of , , + /// , and . + /// + public abstract class RestServiceBase : IRestService + { + private readonly IRetryLogic _retryLogic; + private readonly IRequestLogger _logger; + private readonly IUrlBuilder _urlBuilder; + private readonly IStringSerializer _stringSerializer; + + /// + /// Initializes a new instance of the class with the specified string serializer + /// and the default retry logic and URL builder. + /// + /// The string serializer to use for requests from this service. + /// If is null. + protected RestServiceBase(IStringSerializer stringSerializer) : this(stringSerializer, null) { } + + /// + /// Initializes a new instance of the class with the specified string serializer + /// and logger, and the default retry logic and URL builder. + /// + /// The string serializer to use for requests from this service. + /// The logger to use for requests. Specify null if requests do not need to be logged. + /// If is null. + protected RestServiceBase(IStringSerializer stringSerializer, IRequestLogger requestLogger) : this(stringSerializer, requestLogger, new RequestRetryLogic(), new UrlBuilder()) { } + + /// + /// Initializes a new instance of the class with the specified string serializer, + /// logger, retry logic, and URI builder. + /// + /// The string serializer to use for requests from this service. + /// The logger to use for requests. Specify null if requests do not need to be logged. + /// The retry logic to use for REST operations. + /// The URL builder to use for constructing URLs with query parameters. + /// + /// If is null. + /// -or- + /// If is null. + /// -or- + /// If is null. + /// + protected RestServiceBase(IStringSerializer stringSerializer, IRequestLogger logger, IRetryLogic retryLogic, IUrlBuilder urlBuilder) + { + if (stringSerializer == null) + throw new ArgumentNullException("stringSerializer"); + if (retryLogic == null) + throw new ArgumentNullException("retryLogic"); + if (urlBuilder == null) + throw new ArgumentNullException("urlBuilder"); + + _retryLogic = retryLogic; + _logger = logger; + _urlBuilder = urlBuilder; + _stringSerializer = stringSerializer; + } + + /// + /// Gets the default to use for requests sent from this service. + /// + protected virtual RequestSettings DefaultRequestSettings + { + get + { + return new RequestSettings(); + } + } + + /// + public virtual Response Execute(string url, HttpMethod method, TBody body, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings) + { + if (url == null) + throw new ArgumentNullException("url"); + if (string.IsNullOrEmpty(url)) + throw new ArgumentException("url cannot be empty"); + + return Execute(new Uri(url), method, body, headers, queryStringParameters, settings); + } + + /// + public virtual Response Execute(Uri url, HttpMethod method, TBody body, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings) + { + if (url == null) + throw new ArgumentNullException("url"); + + var rawBody = _stringSerializer.Serialize(body); + return Execute(url, method, rawBody, headers, queryStringParameters, settings); + } + + /// + public virtual Response Execute(string url, HttpMethod method, string body, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings) + { + if (url == null) + throw new ArgumentNullException("url"); + if (string.IsNullOrEmpty(url)) + throw new ArgumentException("url cannot be empty"); + + return Execute(new Uri(url), method, body, headers, queryStringParameters, settings); + } + + /// + public virtual Response Execute(Uri url, HttpMethod method, string body, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings) + { + if (url == null) + throw new ArgumentNullException("url"); + + return Execute(url, method, BuildWebResponse, body, headers, queryStringParameters, settings) as Response; + } + + /// + public virtual Response Execute(string url, HttpMethod method, TBody body, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings) + { + if (url == null) + throw new ArgumentNullException("url"); + if (string.IsNullOrEmpty(url)) + throw new ArgumentException("url cannot be empty"); + + return Execute(new Uri(url), method, body, headers, queryStringParameters, settings); + } + + /// + public virtual Response Execute(Uri url, HttpMethod method, TBody body, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings) + { + if (url == null) + throw new ArgumentNullException("url"); + + var rawBody = _stringSerializer.Serialize(body); + return Execute(url, method, rawBody, headers, queryStringParameters, settings); + } + + /// + public virtual Response Execute(string url, HttpMethod method, string body, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings) + { + if (url == null) + throw new ArgumentNullException("url"); + if (string.IsNullOrEmpty(url)) + throw new ArgumentException("url cannot be empty"); + + return Execute(new Uri(url), method, body, headers, queryStringParameters, settings); + } + + /// + public virtual Response Execute(Uri url, HttpMethod method, string body, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings) + { + if (url == null) + throw new ArgumentNullException("url"); + + return Execute(url, method, null, body, headers, queryStringParameters, settings); + } + + /// + public virtual Response Execute(Uri url, HttpMethod method, Func responseBuilderCallback, string body, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings) + { + if (url == null) + throw new ArgumentNullException("url"); + + return ExecuteRequest(url, method, responseBuilderCallback, headers, queryStringParameters, settings, (req) => + { + // Encode the parameters as form data: + if (!string.IsNullOrEmpty(body)) + { + byte[] formData = UTF8Encoding.UTF8.GetBytes(body); + req.ContentLength = formData.Length; + + // Send the request: + using (Stream post = req.GetRequestStream()) + { + post.Write(formData, 0, formData.Length); + } + } + + return body; + }); + } + + /// + public virtual Response Stream(string url, HttpMethod method, Stream content, int bufferSize, long maxReadLength, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings, Action progressUpdated) + { + if (url == null) + throw new ArgumentNullException("url"); + if (content == null) + throw new ArgumentNullException("content"); + if (string.IsNullOrEmpty(url)) + throw new ArgumentException("url cannot be empty"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException("bufferSize"); + if (maxReadLength < 0) + throw new ArgumentOutOfRangeException("maxReadLength"); + + return Stream(new Uri(url), method, content, bufferSize, maxReadLength, headers, queryStringParameters, settings, progressUpdated) as Response; + } + + /// + public virtual Response Stream(string url, HttpMethod method, Stream content, int bufferSize, long maxReadLength, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings, Action progressUpdated) + { + if (url == null) + throw new ArgumentNullException("url"); + if (content == null) + throw new ArgumentNullException("content"); + if (string.IsNullOrEmpty(url)) + throw new ArgumentException("url cannot be empty"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException("bufferSize"); + if (maxReadLength < 0) + throw new ArgumentOutOfRangeException("maxReadLength"); + + return Stream(new Uri(url), method, content, bufferSize, maxReadLength, headers, queryStringParameters, settings, progressUpdated); + } + + /// + public virtual Response Stream(Uri url, HttpMethod method, Stream content, int bufferSize, long maxReadLength, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings, Action progressUpdated) + { + if (url == null) + throw new ArgumentNullException("url"); + if (content == null) + throw new ArgumentNullException("content"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException("bufferSize"); + if (maxReadLength < 0) + throw new ArgumentOutOfRangeException("maxReadLength"); + + return Stream(url, method, BuildWebResponse, content, bufferSize, maxReadLength, headers, queryStringParameters, settings, progressUpdated) as Response; + } + + /// + public virtual Response Stream(Uri url, HttpMethod method, Stream content, int bufferSize, long maxReadLength, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings, Action progressUpdated) + { + if (url == null) + throw new ArgumentNullException("url"); + if (content == null) + throw new ArgumentNullException("content"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException("bufferSize"); + if (maxReadLength < 0) + throw new ArgumentOutOfRangeException("maxReadLength"); + + return Stream(url, method, null, content, bufferSize, maxReadLength, headers, queryStringParameters, settings, progressUpdated); + } + + /// + /// Executes a REST request with a + /// and user-defined callback function for constructing the resulting + /// object. + /// + /// The base URI. + /// The HTTP method to use for the request. + /// A user-specified function used to construct the resulting + /// object from the and a Boolean value specifying whether or not a + /// was thrown during the request. If this value is null, this method is equivalent to calling + /// . + /// A stream providing the body of the request. + /// + /// The size of the buffer used for copying data from to the + /// HTTP request stream. + /// + /// + /// The maximum number of bytes to send with the request. This parameter is optional. + /// If the value is 0, the request will include all data from . + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// + /// A user-defined callback function for reporting progress of the send operation. + /// This parameter is optional. If the value is null, the method does not report + /// progress updates to the caller. + /// + /// Returns a object containing the HTTP status code, headers, + /// and body from the REST response. + /// + /// If is null. + /// -or- + /// If is null. + /// + /// + /// If is less than or equal to zero. + /// -or- + /// If is less than zero. + /// + /// If is not supported by the service. + public virtual Response Stream(Uri url, HttpMethod method, Func responseBuilderCallback, Stream content, int bufferSize, long maxReadLength, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings, Action progressUpdated) + { + if (url == null) + throw new ArgumentNullException("url"); + if (content == null) + throw new ArgumentNullException("content"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException("bufferSize"); + if (maxReadLength < 0) + throw new ArgumentOutOfRangeException("maxReadLength"); + + return ExecuteRequest(url, method, responseBuilderCallback, headers, queryStringParameters, settings, (req) => + { + long bytesWritten = 0; + + if (settings.ChunkRequest || maxReadLength > 0 ) + { + req.SendChunked = settings.ChunkRequest; + req.AllowWriteStreamBuffering = false; + + req.ContentLength = content.Length > maxReadLength ? maxReadLength : content.Length; + } + + using (Stream stream = req.GetRequestStream()) + { + var buffer = new byte[bufferSize]; + int count; + while ((count = content.Read(buffer, 0, maxReadLength > 0 ? (int)Math.Min(bufferSize, maxReadLength - bytesWritten) : bufferSize)) > 0) + { + bytesWritten += count; + stream.Write(buffer, 0, count); + + if (progressUpdated != null) + progressUpdated(bytesWritten); + + if (maxReadLength > 0 && bytesWritten >= maxReadLength) + break; + } + } + + return "[STREAM CONTENT]"; + }); + } + + /// + /// Executes a REST request indirectly via a callback function , + /// and using a user-defined callback function for + /// constructing the resulting object. + /// + /// + /// The callback method is responsible for setting the body + /// of the request, if any, before executing the request. The callback method returns a string + /// representation of the body of the final request when available, otherwise returns a string + /// indicating the body is no longer available (e.g. was sent as a stream, or is binary). The + /// result is only required for passing as an argument to . + /// + /// The Boolean argument to indicates whether + /// or not an exception was thrown while executing the request. The value is true + /// if an exception occurred, otherwise false. + /// + /// The base URI. + /// The HTTP method to use for the request. + /// A user-specified function used to construct the resulting + /// object from the and a Boolean value specifying whether or not a + /// was thrown during the request. If this value is null, a default method is used to construct + /// the resulting object. + /// + /// A collection of custom HTTP headers to include with the request. If the value is + /// null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// If the value is null, no parameters are added to the query string. + /// + /// + /// The settings to use for the request. If the value is null, the default settings returned + /// by will be used for the request. + /// + /// + /// Returns a object containing the HTTP status code, headers, + /// and body from the REST response. + /// + /// If is null. + /// -or- + /// If is null. + /// + /// If is not supported by the service. + public virtual Response ExecuteRequest(Uri url, HttpMethod method, Func responseBuilderCallback, Dictionary headers, Dictionary queryStringParameters, RequestSettings settings, Func executeCallback) + { + if (url == null) + throw new ArgumentNullException("url"); + if (executeCallback == null) + throw new ArgumentNullException("executeCallback"); + + url = _urlBuilder.Build(url, queryStringParameters); + + if (settings == null) + settings = DefaultRequestSettings; + + return _retryLogic.Execute(() => + { + Response response; + + var startTime = DateTimeOffset.UtcNow; + + string requestBodyText = null; + try + { + var req = WebRequest.Create(url) as HttpWebRequest; + req.Method = method.ToString(); + req.ContentType = settings.ContentType; + req.Accept = settings.Accept; + req.AllowAutoRedirect = settings.AllowAutoRedirect; + if(settings.ContentLength > 0 || settings.AllowZeroContentLength) + req.ContentLength = settings.ContentLength; + + if (settings.ConnectionLimit != null) + req.ServicePoint.ConnectionLimit = settings.ConnectionLimit.Value; + + req.Timeout = (int)settings.Timeout.TotalMilliseconds; + + if (!string.IsNullOrEmpty(settings.UserAgent)) + req.UserAgent = settings.UserAgent; + + if (settings.Credentials != null) + req.Credentials = settings.Credentials; + + if (headers != null) + { + foreach (var header in headers) + { + req.Headers.Add(header.Key, header.Value); + } + } + + requestBodyText = executeCallback(req); + + using (var resp = req.GetResponse() as HttpWebResponse) + { + if (responseBuilderCallback != null) + response = responseBuilderCallback(resp, false); + else + response = BuildWebResponse(resp); + } + } + catch (WebException ex) + { + if (ex.Response == null) + throw; + + using (var resp = ex.Response as HttpWebResponse) + { + if (responseBuilderCallback != null) + response = responseBuilderCallback(resp, true); + else + response = BuildWebResponse(resp); + } + } + var endTime = DateTimeOffset.UtcNow; + + // Log the request + if (_logger != null) + _logger.Log(method, url.OriginalString, headers, requestBodyText, response, startTime, endTime, settings.ExtendedLoggingData); + + if (response != null && settings.ResponseActions != null && settings.ResponseActions.ContainsKey(response.StatusCode)) + { + var action = settings.ResponseActions[response.StatusCode]; + if (action != null) + action(response); + } + + return response; + }, settings.Non200SuccessCodes, settings.RetryCount, settings.RetryDelay); + } + + /// + /// Build a for a given . + /// + /// The response from the REST request. + /// A object representing the result of the REST API call. + /// If is null. + private Response BuildWebResponse(HttpWebResponse resp) + { + if (resp == null) + throw new ArgumentNullException("resp"); + + string respBody; + using (var reader = new StreamReader(resp.GetResponseStream(), GetEncoding(resp))) + { + respBody = reader.ReadToEnd(); + } + + var respHeaders = + resp.Headers.AllKeys.Select(key => new HttpHeader(key, resp.GetResponseHeader(key))) + .ToList(); + return new Response(resp.StatusCode, respHeaders, respBody); + } + + /// + /// Determines the to use for reading an + /// body as text based on the response headers. + /// + /// + /// If the response provides the Content-Encoding header, then it is used. + /// Otherwise, if the optional charset parameter to the Content-Type header + /// is provided, then it is used. If no encoding is specified in the headers, or if the + /// encoding specified in the headers is not valid, is + /// used. + /// + /// The response to examine + /// The to use when reading the response stream as text. + /// is null. + private Encoding GetEncoding(HttpWebResponse response) + { + if (response == null) + throw new ArgumentNullException("response"); +#if !NET35 + Contract.Ensures(Contract.Result() != null); + Contract.EndContractBlock(); +#endif + + string contentEncoding = response.ContentEncoding; + if (!string.IsNullOrEmpty(contentEncoding)) + { + try + { + return Encoding.GetEncoding(contentEncoding); + } + catch (ArgumentException) + { + // continue below + } + } + + string characterSet = response.CharacterSet; + if (string.IsNullOrEmpty(characterSet)) + return Encoding.Default; + + try + { + return Encoding.GetEncoding(characterSet) ?? Encoding.Default; + } + catch (ArgumentException) + { + return Encoding.Default; + } + } + + /// + /// Builds a for a given + /// containing a serialized representation of strongly-typed data in the body of + /// the response. + /// + /// The object model type for the data contained in the body of . + /// The response from the REST request. + /// Indicates whether the response is an error response. If the value is true the response + /// will not be deserialized to + /// A instance representing the response from the REST API call. + /// If is null. + /// + /// If the body of could not be deserialized to an object of type . + /// + private Response BuildWebResponse(HttpWebResponse resp, bool isError = false) + { + var baseReponse = BuildWebResponse(resp); + T data = default(T); + + if (!isError) + { + if (baseReponse != null && !string.IsNullOrEmpty(baseReponse.RawBody)) + data = _stringSerializer.Deserialize(baseReponse.RawBody); + } + + return new Response(baseReponse, data); + } + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/UrlBuilder.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/UrlBuilder.cs new file mode 100644 index 0000000000..cb8345c69d --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/UrlBuilder.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using JSIStudios.SimpleRESTServices.Core; + +namespace JSIStudios.SimpleRESTServices.Client +{ + /// + /// A simple, default implementation of a URI builder. + /// + public class UrlBuilder : IUrlBuilder + { + /// + public Uri Build(Uri baseUrl, Dictionary queryStringParameters) + { + if (baseUrl == null) + throw new ArgumentNullException("baseUrl"); + + return new Uri(Build(baseUrl.AbsoluteUri, queryStringParameters)); + } + + /// + /// Constructs a complete URI for an HTTP request using a base URI and a + /// collection of query string parameters. + /// + /// + /// If already contains a query string, the specified + /// are appended to the existing query string. + /// This method does not perform substitution for any template parameters + /// which may exist in . If + /// is null or empty, is returned unchanged. + /// + /// The base URI. + /// A collection of parameters to place in the URI query string, + /// or null if there are no parameters. + /// A constructed from and the specified + /// . + /// If is null. + public string Build(string baseAbsoluteUrl, Dictionary queryStringParameters) + { + if (baseAbsoluteUrl == null) + throw new ArgumentNullException("baseAbsoluteUrl"); + + if (queryStringParameters != null && queryStringParameters.Count > 0) + { + var paramsCombinedList = + queryStringParameters.Select( + param => + string.Format("{0}={1}", System.Web.HttpUtility.UrlEncode(param.Key), + System.Web.HttpUtility.UrlEncode(param.Value))); + var paramsCombined = string.Join("&", paramsCombinedList.ToArray()); + + var separator = baseAbsoluteUrl.Contains("?") ? "&" : "?"; + return baseAbsoluteUrl + separator + paramsCombined; + } + + return baseAbsoluteUrl; + } + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/WebResponseRetryLogic.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/WebResponseRetryLogic.cs new file mode 100644 index 0000000000..d924c6bbbe --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Client/WebResponseRetryLogic.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading; +using JSIStudios.SimpleRESTServices.Core; + +namespace JSIStudios.SimpleRESTServices.Client +{ + /// + /// Provides a simple default implementation of + /// for HTTP REST requests. + /// + /// + /// This implementation of invokes the callback + /// method until one of the following conditions is met. + /// + /// + /// The operation has been attempted retryCount times. + /// The status code is less than 300. + /// The status code is contained in the + /// non200SuccessCodes collection. + /// + /// + /// If the retry delay is greater than zero, is called + /// between retry attempts. + /// + public class RequestRetryLogic : IRetryLogic + { + /// + public Response Execute(Func callback, int retryCount = 0, TimeSpan? retryDelay = null) + { + if (callback == null) + throw new ArgumentNullException("callback"); + if (retryCount < 0) + throw new ArgumentOutOfRangeException("retryCount"); + if (retryDelay.HasValue && retryDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("retryDelay"); + + return Execute(callback, Enumerable.Empty(), retryCount, retryDelay); + } + + /// + public Response Execute(Func callback, IEnumerable non200SuccessCodes, int retryCount = 0, TimeSpan? retryDelay = null) + { + if (callback == null) + throw new ArgumentNullException("callback"); + if (retryCount < 0) + throw new ArgumentOutOfRangeException("retryCount"); + if (retryDelay.HasValue && retryDelay < TimeSpan.Zero) + throw new ArgumentOutOfRangeException("retryDelay"); + + Response response; + do + { + response = callback(); + if (IsRequestSuccessful(response, non200SuccessCodes)) + return response; + + retryCount--; + if (retryCount >= 0) + Thread.Sleep(retryDelay ?? TimeSpan.Zero); + } + while (retryCount >= 0); + + return response; + } + + /// + /// Checks if is considered a successful HTTP response. + /// + /// The response. + /// The HTTP status codes to consider successful, in addition to codes + /// below 300. + /// true if is considered a successful HTTP + /// response, otherwise false. + private static bool IsRequestSuccessful(Response response, IEnumerable non200SuccessCodes) + { + if (response != null && response.StatusCode < (HttpStatusCode)300) + return true; + + if (non200SuccessCodes == null) + return false; + + return non200SuccessCodes.Contains(response.StatusCode); + } + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/BadWebRequestException.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/BadWebRequestException.cs new file mode 100644 index 0000000000..d1b47aff4b --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/BadWebRequestException.cs @@ -0,0 +1,17 @@ +using System; + +namespace JSIStudios.SimpleRESTServices.Core.Exceptions +{ + public class BadWebRequestException : Exception + { + public BadWebRequestException(string message) + : base(message) + { + } + + public BadWebRequestException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/HttpHeaderNotFoundException.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/HttpHeaderNotFoundException.cs new file mode 100644 index 0000000000..c317d6f322 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/HttpHeaderNotFoundException.cs @@ -0,0 +1,23 @@ +using System; + +namespace JSIStudios.SimpleRESTServices.Core.Exceptions +{ + public class HttpHeaderNotFoundException : Exception + { + public string Name { get; set; } + public HttpHeaderNotFoundException(string name, string message) + : base(message) + { + Name = name; + } + + public HttpHeaderNotFoundException(string name) + { + Name = name; + } + + public HttpHeaderNotFoundException() + { + } + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/HttpResourceNotFoundException.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/HttpResourceNotFoundException.cs new file mode 100644 index 0000000000..d181f6a3bb --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/HttpResourceNotFoundException.cs @@ -0,0 +1,12 @@ +using System; + +namespace JSIStudios.SimpleRESTServices.Core.Exceptions +{ + public class HttpResourceNotFoundException : Exception + { + public HttpResourceNotFoundException(string message) + : base(message) + { + } + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/HttpResourceNotModifiedException.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/HttpResourceNotModifiedException.cs new file mode 100644 index 0000000000..e5f7691128 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/Exceptions/HttpResourceNotModifiedException.cs @@ -0,0 +1,11 @@ +using System; + +namespace JSIStudios.SimpleRESTServices.Core.Exceptions +{ + public class HttpResourceNotModifiedException : Exception + { + public HttpResourceNotModifiedException() + { + } + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRequestLogger.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRequestLogger.cs new file mode 100644 index 0000000000..78036e4c59 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRequestLogger.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using JSIStudios.SimpleRESTServices.Client; + +namespace JSIStudios.SimpleRESTServices.Core +{ + /// + /// Represents custom logging behavior for a REST request. + /// + public interface IRequestLogger + { + /// + /// Logs a REST request along with its response. + /// + /// The used for the request. + /// The complete URI, including the query string (if any). + /// The set of custom headers sent with the request. This may be null if no custom headers were specified. + /// The body of the request. This is null or empty if the request did not include a body. + /// The response. + /// The request start time. + /// The request end time. + /// The user-defined extended data specified in . + void Log(HttpMethod httpMethod, string uri, Dictionary requestHeaders, string requestBody, Response response, DateTimeOffset requestStartTime, DateTimeOffset requestEndTime, Dictionary extendedData); + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRequestProcessor.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRequestProcessor.cs new file mode 100644 index 0000000000..0da6f3147b --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRequestProcessor.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Specialized; +using System.Net; +using JSIStudios.SimpleRESTServices.Server.EventArgs; + +namespace JSIStudios.SimpleRESTServices.Core +{ + public interface IRequestProcessor + { + event EventHandler RequestStarted; + event EventHandler RequestCompleted; + event EventHandler OnError; + + void Execute(Action callBack, HttpStatusCode successStatus = HttpStatusCode.OK); + void Execute(Action callBack, NameValueCollection responseHeaders, HttpStatusCode successStatus = HttpStatusCode.OK); + + TResult Execute(Func callBack, HttpStatusCode successStatus = HttpStatusCode.OK); + TResult Execute(Func callBack, NameValueCollection responseHeaders, HttpStatusCode successStatus = HttpStatusCode.OK); + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRestService.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRestService.cs new file mode 100644 index 0000000000..8f3e863f01 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRestService.cs @@ -0,0 +1,585 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using JSIStudios.SimpleRESTServices.Client.Json; + +namespace JSIStudios.SimpleRESTServices.Client +{ + /// + /// Represents a service for executing generic REST requests. + /// + public interface IRestService + { + /// + /// Executes a REST request with a strongly-typed and result. + /// + /// The type of the data returned in the REST response. + /// The type of the data included in the body of the REST request. + /// The base URI. + /// The HTTP method to use for the request. + /// + /// The strongly-typed data to include in the body of the request. If the value is null, + /// the behavior is implementation-defined. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// Returns a object containing the HTTP status code, headers, body, + /// and strongly-typed data from the REST response. + /// If is null. + /// If is not a valid base URI. + /// If is not supported by the service. + /// + /// If the body of the response could not be deserialized to an object of type . + /// + Response Execute( + String url, + HttpMethod method, + TBody body, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null); + + /// + /// Executes a REST request with a strongly-typed and result. + /// + /// The type of the data returned in the REST response. + /// The type of the data included in the body of the REST request. + /// The base URI. + /// The HTTP method to use for the request. + /// + /// The strongly-typed data to include in the body of the request. If the value is null, + /// the behavior is implementation-defined. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// Returns a object containing the HTTP status code, headers, body, + /// and strongly-typed data from the REST response. + /// If is null. + /// If is not supported by the service. + /// + /// If the body of the response could not be deserialized to an object of type . + /// + Response Execute( + Uri url, + HttpMethod method, + TBody body, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null); + + /// + /// Executes a REST request with a string and strongly-typed result. + /// + /// The type of the data returned in the REST response. + /// The base URI. + /// The HTTP method to use for the request. + /// + /// The body of the request. This parameter is optional. If the value is null, + /// the request is sent without a body. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// Returns a object containing the HTTP status code, headers, body, + /// and strongly-typed data from the REST response. + /// If is null. + /// If is not a valid base URI. + /// If is not supported by the service. + /// + /// If the body of the response could not be deserialized to an object of type . + /// + Response Execute( + String url, + HttpMethod method, + string body = null, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null); + + /// + /// Executes a REST request with a string and strongly-typed result. + /// + /// The type of the data returned in the REST response. + /// The base URI. + /// The HTTP method to use for the request. + /// + /// The body of the request. This parameter is optional. If the value is null, + /// the request is sent without a body. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// Returns a object containing the HTTP status code, headers, body, + /// and strongly-typed data from the REST response. + /// If is null. + /// If is not supported by the service. + /// + /// If the body of the response could not be deserialized to an object of type . + /// + Response Execute( + Uri url, + HttpMethod method, + string body = null, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null); + + /// + /// Executes a REST request with a strongly-typed and basic result (text or no content). + /// + /// The type of the data included in the body of the REST request. + /// The base URI. + /// The HTTP method to use for the request. + /// + /// The strongly-typed data to include in the body of the request. If the value is null, + /// the behavior is implementation-defined. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// Returns a object containing the HTTP status code, headers, + /// and body from the REST response. + /// If is null. + /// If is not a valid base URI. + /// If is not supported by the service. + Response Execute( + String url, + HttpMethod method, + TBody body, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null); + + /// + /// Executes a REST request with a strongly-typed and basic result (text or no content). + /// + /// The type of the data included in the body of the REST request. + /// The base URI. + /// The HTTP method to use for the request. + /// + /// The strongly-typed data to include in the body of the request. If the value is null, + /// the behavior is implementation-defined. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// Returns a object containing the HTTP status code, headers, + /// and body from the REST response. + /// If is null. + /// If is not supported by the service. + Response Execute( + Uri url, + HttpMethod method, + TBody body, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null); + + /// + /// Executes a REST request with a string and basic result (text or no content). + /// + /// The base URI. + /// The HTTP method to use for the request. + /// + /// The body of the request. This parameter is optional. If the value is null, + /// the request is sent without a body. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// Returns a object containing the HTTP status code, headers, + /// and body from the REST response. + /// If is null. + /// If is not a valid base URI. + /// If is not supported by the service. + Response Execute( + String url, + HttpMethod method, + string body = null, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null); + + /// + /// Executes a REST request with a string and basic result (text or no content). + /// + /// The base URI. + /// The HTTP method to use for the request. + /// + /// The body of the request. This parameter is optional. If the value is null, + /// the request is sent without a body. + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// Returns a object containing the HTTP status code, headers, + /// and body from the REST response. + /// If is null. + /// If is not supported by the service. + Response Execute( + Uri url, + HttpMethod method, + string body = null, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null); + + /// + /// Executes a REST request with a and strongly-typed result. + /// + /// The type of the data returned in the REST response. + /// The base URI. + /// The HTTP method to use for the request. + /// A stream providing the body of the request. + /// + /// The size of the buffer used for copying data from to the + /// HTTP request stream. + /// + /// + /// The maximum number of bytes to send with the request. This parameter is optional. + /// If the value is 0, the request will include all data from . + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// + /// A user-defined callback function for reporting progress of the send operation. + /// This parameter is optional. If the value is null, the method does not report + /// progress updates to the caller. + /// + /// Returns a object containing the HTTP status code, headers, body, + /// and strongly-typed data from the REST response. + /// + /// If is null. + /// -or- + /// If is null. + /// + /// + /// If is less than or equal to zero. + /// -or- + /// If is less than zero. + /// + /// If is not supported by the service. + /// + /// If the body of the response could not be deserialized to an object of type . + /// + Response Stream( + Uri url, + HttpMethod method, + Stream content, + int bufferSize, + long maxReadLength = 0, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null, + Action progressUpdated = null); + + /// + /// Executes a REST request with a and basic result (text or no content). + /// + /// The base URI. + /// The HTTP method to use for the request. + /// A stream providing the body of the request. + /// + /// The size of the buffer used for copying data from to the + /// HTTP request stream. + /// + /// + /// The maximum number of bytes to send with the request. This parameter is optional. + /// If the value is 0, the request will include all data from . + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// + /// A user-defined callback function for reporting progress of the send operation. + /// This parameter is optional. If the value is null, the method does not report + /// progress updates to the caller. + /// + /// Returns a object containing the HTTP status code, headers, + /// and body from the REST response. + /// + /// If is null. + /// -or- + /// If is null. + /// + /// + /// If is less than or equal to zero. + /// -or- + /// If is less than zero. + /// + /// If is not supported by the service. + Response Stream( + Uri url, + HttpMethod method, + Stream content, + int bufferSize, + long maxReadLength = 0, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null, + Action progressUpdated = null); + + /// + /// Executes a REST request with a and strongly-typed result. + /// + /// The type of the data returned in the REST response. + /// The base URI. + /// The HTTP method to use for the request. + /// A stream providing the body of the request. + /// + /// The size of the buffer used for copying data from to the + /// HTTP request stream. + /// + /// + /// The maximum number of bytes to send with the request. This parameter is optional. + /// If the value is 0, the request will include all data from . + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// + /// A user-defined callback function for reporting progress of the send operation. + /// This parameter is optional. If the value is null, the method does not report + /// progress updates to the caller. + /// + /// Returns a object containing the HTTP status code, headers, body, + /// and strongly-typed data from the REST response. + /// + /// If is null. + /// -or- + /// If is null. + /// + /// + /// If is less than or equal to zero. + /// -or- + /// If is less than zero. + /// + /// If is not a valid base URI. + /// If is not supported by the service. + /// + /// If the body of the response could not be deserialized to an object of type . + /// + Response Stream( + string url, + HttpMethod method, + Stream content, + int bufferSize, + long maxReadLength = 0, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null, + Action progressUpdated = null); + + /// + /// Executes a REST request with a and basic result (text or no content). + /// + /// The base URI. + /// The HTTP method to use for the request. + /// A stream providing the body of the request. + /// + /// The size of the buffer used for copying data from to the + /// HTTP request stream. + /// + /// + /// The maximum number of bytes to send with the request. This parameter is optional. + /// If the value is 0, the request will include all data from . + /// + /// + /// A collection of custom HTTP headers to include with the request. This parameter is + /// optional. If the value is null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// This parameter is optional. If the value is null, no parameters are added + /// to the query string. + /// + /// + /// The settings to use for the request. This parameters is optional. If the value is + /// null, an implementation-specific set of default settings will be used for the request. + /// + /// + /// A user-defined callback function for reporting progress of the send operation. + /// This parameter is optional. If the value is null, the method does not report + /// progress updates to the caller. + /// + /// Returns a object containing the HTTP status code, headers, + /// and body from the REST response. + /// + /// If is null. + /// -or- + /// If is null. + /// + /// + /// If is less than or equal to zero. + /// -or- + /// If is less than zero. + /// + /// If is not a valid base URI. + /// If is not supported by the service. + Response Stream( + string url, + HttpMethod method, + Stream content, + int bufferSize, + long maxReadLength = 0, + Dictionary headers = null, + Dictionary queryStringParameters = null, + RequestSettings settings = null, + Action progressUpdated = null); + + /// + /// Executes a REST request with a string and user-defined + /// callback function for constructing the resulting object. + /// + /// + /// The Boolean argument to indicates whether + /// or not an exception was thrown while executing the request. The value is true + /// if an exception occurred, otherwise false. + /// + /// The base URI. + /// The HTTP method to use for the request. + /// A user-specified function used to construct the resulting + /// object from the and a Boolean value specifying whether or not a + /// was thrown during the request. If this value is null, this method is equivalent to calling + /// . + /// The body of the request. If the value is null, the request is sent without a body. + /// + /// A collection of custom HTTP headers to include with the request. If the value is + /// null, no custom headers are added to the HTTP request. + /// + /// + /// A collection of parameters to add to the query string portion of the request URI. + /// If the value is null, no parameters are added to the query string. + /// + /// + /// The settings to use for the request. If the value is null, an implementation-specific + /// set of default settings will be used for the request. + /// + /// Returns a object containing the HTTP status code, headers, + /// and body from the REST response. + /// If is null. + /// If is not supported by the service. + Response Execute( + Uri url, + HttpMethod method, + Func responseBuilderCallback, + string body, + Dictionary headers, + Dictionary queryStringParameters, + RequestSettings settings); + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRetryLogic.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRetryLogic.cs new file mode 100644 index 0000000000..68a4178df6 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IRetryLogic.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; + +namespace JSIStudios.SimpleRESTServices.Core +{ + /// + /// Provides the behavior for executing a callback method with configurable success + /// values, number of retries, and the retry delay. + /// + /// The operation return type + /// The type of the value used to represent the operation's success or failure +#if NET35 + public interface IRetryLogic +#else + public interface IRetryLogic +#endif + { + /// + /// Executes a user-defined operation with the specified number of retry attempts + /// if a failure occurs and delay time between retry attempts. + /// + /// The user-defined operation to execute. + /// The number of times to retry a failed operation. This parameter is optional. The default value is 1. + /// The delay between retry operations. This parameter is optional. If the value is null, the default is (no delay). + /// Returns the result of a successful execution of . If + /// failed and the maximum number of retries has been reached, + /// the method returns the last (unsuccessful) result returned by . + /// If is null. + /// + /// If is less than zero. + /// -or- + /// If is less than . + /// + T Execute(Func logic, int retryCount = 0, TimeSpan? retryDelay = null); + + /// + /// Executes a user-defined operation with the specified "success" values, number of + /// retry attempts if a failure occurs, and delay time between retry attempts. + /// + /// The user-defined operation to execute. + /// A collection of values which are generally considered failures, but should be treated as success values for this call. + /// The number of times to retry a failed operation. This parameter is optional. The default value is 1. + /// The delay between retry operations. This parameter is optional. If the value is null, the default is (no delay). + /// Returns the result of a successful execution of . If + /// failed and the maximum number of retries has been reached, + /// the method returns the last (unsuccessful) result returned by . + /// If is null. + /// + /// If is less than zero. + /// -or- + /// If is less than . + /// + T Execute(Func logic, IEnumerable successValues, int retryCount = 0, TimeSpan? retryDelay = null); + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/ITextCleaner.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/ITextCleaner.cs new file mode 100644 index 0000000000..d6e9a7b893 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/ITextCleaner.cs @@ -0,0 +1,7 @@ +namespace JSIStudios.SimpleRESTServices.Core +{ + public interface ITextCleaner + { + string Clean(string text); + } +} diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IUrlBuilder.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IUrlBuilder.cs new file mode 100644 index 0000000000..2441ff4c86 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Core/IUrlBuilder.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; + +namespace JSIStudios.SimpleRESTServices.Core +{ + /// + /// Represents a builder which can construct a complete URI for a GET or HEAD request + /// from a base URI and a collection of query parameters. + /// + public interface IUrlBuilder + { + /// + /// Constructs a complete URI for an HTTP request using a base URI and a + /// collection of query string parameters. + /// + /// + /// If already contains a query string, the specified + /// are appended to the existing query string. + /// This method does not perform substitution for any template parameters + /// which may exist in . If + /// is null or empty, is returned unchanged. + /// + /// The base URI. + /// A collection of parameters to place in the URI query string, + /// or null if there are no parameters. + /// A constructed from and the specified + /// . + /// If is null. + Uri Build(Uri baseUrl, Dictionary queryStringParameters); + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Properties/AssemblyInfo.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..ed4abb41fc --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SimpleRESTServices")] +[assembly: AssemblyDescription("A simple set of client side and server side REST helpers")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("JSI Studios")] +[assembly: AssemblyProduct("SimpleRESTServices")] +[assembly: AssemblyCopyright("Copyright © JSI Studios 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: CLSCompliant(true)] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5a741815-e26d-4cb0-a42b-78f7c1611190")] + +// Refer to the following issue before changing these version numbers: +// https://github.com/JSIStudios/SimpleRestServices/issues/53 +[assembly: AssemblyVersion("1.3.0.0")] +[assembly: AssemblyFileVersion("1.3.0.3")] +[assembly: AssemblyInformationalVersion("1.3.0.3-dev")] diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/EventArgs/RESTRequestCompletedEventArgs.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/EventArgs/RESTRequestCompletedEventArgs.cs new file mode 100644 index 0000000000..4ea560c0f7 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/EventArgs/RESTRequestCompletedEventArgs.cs @@ -0,0 +1,22 @@ +using System; + +namespace JSIStudios.SimpleRESTServices.Server.EventArgs +{ + public class RESTRequestCompletedEventArgs : System.EventArgs + { + public Guid RequestId { get; private set; } + + public object Response { get; private set; } + + public TimeSpan ExecutionTime { get; private set; } + + public RESTRequestCompletedEventArgs(Guid requestId, object response, TimeSpan executionTime) + : base() + { + RequestId = requestId; + Response = response; + ExecutionTime = executionTime; + + } + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/EventArgs/RESTRequestErrorEventArgs.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/EventArgs/RESTRequestErrorEventArgs.cs new file mode 100644 index 0000000000..63fd3e718d --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/EventArgs/RESTRequestErrorEventArgs.cs @@ -0,0 +1,18 @@ +using System; + +namespace JSIStudios.SimpleRESTServices.Server.EventArgs +{ + public class RESTRequestErrorEventArgs : System.EventArgs + { + public Guid RequestId { get; private set; } + + public Exception Error { get; private set; } + + public RESTRequestErrorEventArgs(Guid requestId, Exception error) + : base() + { + RequestId = requestId; + Error = error; + } + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/EventArgs/RESTRequestStartedEventArgs.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/EventArgs/RESTRequestStartedEventArgs.cs new file mode 100644 index 0000000000..6ad9eb21ea --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/EventArgs/RESTRequestStartedEventArgs.cs @@ -0,0 +1,18 @@ +using System; + +namespace JSIStudios.SimpleRESTServices.Server.EventArgs +{ + public class RESTRequestStartedEventArgs : System.EventArgs + { + public Guid RequestId { get; private set; } + + public string Request { get; private set; } + + public RESTRequestStartedEventArgs(Guid requestId, string request) + : base() + { + RequestId = requestId; + Request = request; + } + } +} \ No newline at end of file diff --git a/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/FullHtmlTagCleaner.cs b/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/FullHtmlTagCleaner.cs new file mode 100644 index 0000000000..276ead2099 --- /dev/null +++ b/thirdparty/SimpleRestServices/src/SimpleRestServices/Server/FullHtmlTagCleaner.cs @@ -0,0 +1,219 @@ +using System; +using System.Linq; +using System.Text.RegularExpressions; +using System.Web; +using JSIStudios.SimpleRESTServices.Core; + +namespace JSIStudios.SimpleRESTServices.Server +{ + public class FullHtmlTagCleaner : ITextCleaner + { + public static string Name = "FullHtmlTagCleaner"; + + private string[] _allowedTags = new string[] { }; + private string[] _illegalTags = new string[] { "style", "script", "embed", "object" }; + private static string[] _illegalCharacters = new[] { "�", "�", "%0", "", "", "%1", "", "", "%2", "", "", "%3", "", "", "%4", "", "", "%5", "", "", "%6", "", "", "%7", "", "", "%8", " ", " ", "%9", " ", " ", "%a", " ", " ", "%b", " ", " ", "%c", " ", " ", "%d", "", "", "%e", "", "", "%f", "", "", "%10", "", "", "%11", "", "", "%12", "", "", "%13", "", "", "%14", "", "", "%15", "", "", "%16", "", "", "%17", "", "", "%18", "", "", "%19", "", "", "%1a", "", "", "%1b", "", "", "%1c", "", "", "%1d", "", "", "%1e", "", "", "%1f", "", "", "%7f", "€", "€", "%80", "", "", "%81", "‚", "‚", "%82", "ƒ", "ƒ", "%83", "„", "„", "%84", "…", "…", "%85", "†", "†", "%86", "‡", "‡", "%87", "ˆ", "ˆ", "%88", "‰", "‰", "%89", "Š", "Š", "%8a", "‹", "‹", "%8b", "Œ", "Œ", "%8c", "", "", "%8d", "Ž", "Ž", "%8e", "", "", "%8f", "", "", "%90", "‘", "‘", "%91", "’", "’", "%92", "“", "“", "%93", "”", "”", "%94", "•", "•", "%95", "–", "–", "%96", "—", "—", "%97", "˜", "˜", "%98", "™", "™", "%99", "š", "š", "%9a", "›", "›", "%9b", "œ", "œ", "%9c", "", "", "%9d", "ž", "ž", "%9e", "Ÿ", "Ÿ", "%9f" }; + + public virtual string[] IllegalTags + { + get { return _illegalTags; } + set { _illegalTags = value; } + } + + public virtual string[] AllowedTags + { + get { return _allowedTags; } + set { _allowedTags = value; } + } + + public static string[] IllegalCharacters + { + get { return _illegalCharacters; } + set { _illegalCharacters = value; } + } + + public string Clean(string source) + { + if (string.IsNullOrEmpty(source)) + { + return null; + } + + var allowedTags = AllowedTags; + var illegalTags = IllegalTags; + + source = RemoveIllegalCharacters(source); + source = illegalTags.Where(illegalTag => illegalTag == "style" || illegalTag == "script").Aggregate(source, (current, illegalTag) => RemoveTagsAndTextBetweenTags("<" + illegalTag + ">", "", current)); + + var array = new char[source.Length]; + var arrayIndex = 0; + + source = Regex.Replace(source, @"(\r\n)|(\r)|(\n)", " ").Replace("\t", ""); + var sourceLen = source.Length; + + for (int idx = 0; idx < sourceLen; idx++) + { + char let = source[idx]; + if (let == '<') + { + var len = 0; + var idx2 = idx; + char let2; + string tag = string.Empty; + + do + { + idx2++; + if (idx2 >= sourceLen) + { + tag = string.Empty; + break; + } + + len++; + let2 = source[idx2]; + + + if (string.IsNullOrEmpty(tag) && (let2 == ' ' || (let2 == '/' && len > 1))) + { + tag = source.Substring(idx + 1, len - 1); + } + + } while (let2 != '>'); + + if (string.IsNullOrEmpty(tag)) + { + int start = idx + 1; + if (source[start] == '/') + { + start++; + len--; + } + + tag = source.Substring(start, len - 1); + } + + if (allowedTags.Contains(tag.ToLower())) + { + for (int i = idx; i <= idx2; i++) + { + if (i >= sourceLen) + break; + array[arrayIndex] = source[i]; + arrayIndex++; + } + + } + + idx = idx2; + + if (illegalTags.Contains(tag.ToLower())) + { + do + { + idx++; + if (idx < (sourceLen - 1)) + { + let = source[idx]; + + if (let == '<' && source[++idx] == '/') + { + len = 0; + idx2 = idx; + var endTag = string.Empty; + do + { + idx2++; + len++; + let2 = source[idx2]; + } while (let2 != '>' && idx2 < sourceLen); + + idx = idx2; + let = let2; + } + } + } while (let != '>' && idx < (sourceLen - 1)); + } + } + else + { + array[arrayIndex] = let; + arrayIndex++; + } + } + //return new string(array, 0, arrayIndex); + var s = new string(array, 0, arrayIndex); + return HttpUtility.HtmlDecode(s.Trim()); + + } + + private static string RemoveIllegalCharacters(string source) + { + var sortedArray = from s in IllegalCharacters + orderby s.Length descending + select s; + return sortedArray.Aggregate(source, (current, illegalCharacter) => current.Replace(illegalCharacter, "")); + } + + private static string RemoveTagsAndTextBetweenTags(string startTag, string endTag, string strSource) + { + var temp = strSource; + + // remove the text in start tag if any. eg - + // replaces the tag with simple tags like + while (temp.IndexOf(startTag.Substring(0, startTag.Length - 1), StringComparison.OrdinalIgnoreCase) != -1) + { + var result = GetTextAlongWithTag(startTag.Substring(0, startTag.Length - 1), ">", temp, true, true); + temp = !string.IsNullOrWhiteSpace(result[0]) ? strSource.Replace(result[0], string.Empty) : temp; + if (result[0] != startTag) + { + // to handle the tags which doesn't have closing tags. eg -