├── .gitignore ├── CHANGELOG.md ├── Generate-ReleaseNotes.cmd ├── LICENSE ├── README.md ├── WebDAV-Client-Solution.sln ├── WebDAV-Client-Solution.sln.DotSettings ├── src └── WebDAV-Client │ ├── ApiParams │ ├── CopyParameters.cs │ ├── DeleteParameters.cs │ ├── GetFileParameters.cs │ ├── LockParameters.cs │ ├── MkColParameters.cs │ ├── MoveParameters.cs │ ├── PropfindParameters.cs │ ├── ProppatchParameters.cs │ ├── PutFileParameters.cs │ ├── RequestParameters.cs │ ├── UnlockParameters.cs │ └── WebDavClientParams.cs │ ├── Domain │ ├── ActiveLock.cs │ ├── ApplyTo.cs │ ├── LockOwner.cs │ ├── LockScope.cs │ ├── NamespaceAttr.cs │ ├── PrincipalLockOwner.cs │ ├── UriLockOwner.cs │ ├── WebDavMethod.cs │ ├── WebDavProperty.cs │ ├── WebDavPropertyStatus.cs │ └── WebDavResource.cs │ ├── Extensions │ ├── LinqToXmlExtensions.cs │ └── XDocumentExtensions.cs │ ├── Helpers │ ├── DepthHeaderHelper.cs │ └── IfHeaderHelper.cs │ ├── Infrastructure │ ├── HttpResponse.cs │ ├── IWebDavDispatcher.cs │ └── WebDavDispatcher.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── Request │ ├── LockRequestBuilder.cs │ ├── PropfindRequestBuilder.cs │ └── ProppatchRequestBuilder.cs │ ├── Response │ ├── IResponseParser.cs │ ├── LockResponse.cs │ ├── LockResponseParser.cs │ ├── MultiStatusParser.cs │ ├── PropertyValueParser.cs │ ├── PropfindResponse.cs │ ├── PropfindResponseParser.cs │ ├── ProppatchResponse.cs │ ├── ProppatchResponseParser.cs │ ├── ResourceType.cs │ ├── WebDavResponse.cs │ └── WebDavStreamResponse.cs │ ├── System.ComponentModel │ └── InvalidEnumArgumentException.cs │ ├── System │ └── RuntimeUtils.cs │ ├── Validation │ ├── Check.cs │ └── CoreStrings.cs │ ├── WebDAV-Client.csproj │ └── WebDavClient.cs └── test ├── WebDAV-Client.Tests.Net452 ├── Infrastructure │ └── WebDavDispatcherTests.cs ├── Properties │ └── AssemblyInfo.cs ├── Response │ ├── LockResponseParserTests.cs │ ├── PropfindResponseParserTests.cs │ └── ProppatchResponseParserTests.cs ├── Responses.cs ├── TestDoubles │ └── Dispatcher.cs ├── WebDAV-Client.Tests.Net452.csproj ├── WebDavClientTests │ ├── CopyTests.cs │ ├── DeleteTests.cs │ ├── GetFileTests.cs │ ├── LockTests.cs │ ├── MkcolTests.cs │ ├── MoveTests.cs │ ├── Predicates.cs │ ├── PropfindTests.cs │ ├── ProppatchTests.cs │ ├── PutFileTests.cs │ └── UnlockTests.cs └── packages.config └── WebDAV-Client.Tests └── WebDAV-Client.Tests.csproj /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.1.2 (04 February 2023) 2 | - [#8](https://github.com/StefH/WebDAV-Client/pull/8) - Bump System.Net.Http from 4.3.0 to 4.3.4 in /src/WebDAV-Client [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot) 3 | - [#12](https://github.com/StefH/WebDAV-Client/pull/12) - Add net6.0 and net7.0 [enhancement] contributed by [StefH](https://github.com/StefH) 4 | - [#11](https://github.com/StefH/WebDAV-Client/issues/11) - PlatformNotSupportedException on Blazor Webassembly / WASM [bug] 5 | 6 | # 1.1.0.0 (02 May 2020) 7 | - [#6](https://github.com/StefH/WebDAV-Client/pull/6) - Fixes for Blazor WASM [bug] contributed by [StefH](https://github.com/StefH) 8 | - [#4](https://github.com/StefH/WebDAV-Client/issues/4) - Upgrade project to VS2017 9 | 10 | # 1.0.3.0 (22 August 2018) 11 | - [#5](https://github.com/StefH/WebDAV-Client/pull/5) - Upgrade to VS2017 and update TargetFrameworks contributed by [StefH](https://github.com/StefH) 12 | - [#2](https://github.com/StefH/WebDAV-Client/issues/2) - Content-Type is set to text/plain when sending XML [bug, enhancement] 13 | 14 | # 1.0.2.0 (06 March 2017) 15 | - [#1](https://github.com/StefH/WebDAV-Client/issues/1) - Add support for using a custom HttpClient or HttpMessageHandler [enhancement] 16 | 17 | -------------------------------------------------------------------------------- /Generate-ReleaseNotes.cmd: -------------------------------------------------------------------------------- 1 | rem https://github.com/StefH/GitHubReleaseNotes 2 | 3 | SET version=1.1.2 4 | 5 | GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate --version %version% --token %GH_TOKEN% -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Stef Heyenrath 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebDAV-Client 2 | An easy-to-use async WebDAV client for .NET, .NETStandard, UAP and Portable based on https://github.com/skazantsev/WebDavClient. 3 | 4 | [![NuGet Badge](https://buildstats.info/nuget/WebDAV-Client)](https://www.nuget.org/packages/WebDAV-Client) 5 | 6 | #### Supported Frameworks 7 | - .NET Framework 4.5 and 4.6 8 | - .NET Standard 1.1, 2.0 and 2.1 9 | - .NET 6.0 and 7.0 10 | - Blazor WASM 11 | - Portable (Profile7, Profile32, Profile44, Profile111, Profile115). See [portablelibraryprofiles](https://portablelibraryprofiles.stephencleary.com/). 12 | 13 | #### Basic usage 14 | ``` csharp 15 | using (var webDavClient = new WebDavClient()) 16 | { 17 | var result = await webDavClient.Propfind("http://mywebdav/1.txt"); 18 | if (result.IsSuccessful) 19 | // continue ... 20 | else 21 | // handle an error 22 | } 23 | ``` 24 | 25 | #### Usage in Blazor WASM 26 | See https://github.com/StefH/WebDAV-AudioPlayer/tree/master/src/Blazor-WebDAV-AudioPlayer.v2 27 | 28 | #### Using BaseAddress 29 | ``` csharp 30 | var clientParams = new WebDavClientParams { BaseAddress = new Uri("http://mywebdav/") }; 31 | using (var webDavClient = new WebDavClient(clientParams)) 32 | { 33 | await webDavClient.Propfind("1.txt"); 34 | } 35 | ``` 36 | 37 | #### Operations with files and directories (resources & collections) 38 | ``` csharp 39 | var clientParams = new WebDavClientParams { BaseAddress = new Uri("http://mywebdav/") }; 40 | using (var webDavClient = new WebDavClient(clientParams)) 41 | { 42 | await webDavClient.Mkcol("mydir"); // create a directory 43 | 44 | await webDavClient.Copy("source.txt", "dest.txt"); // copy a file 45 | 46 | await webDavClient.Move("source.txt", "dest.txt"); // move a file 47 | 48 | await webDavClient.Delete("file.txt", "dest.txt"); // delete a file 49 | 50 | await webDavClient.GetRawFile("file.txt"); // get a file without processing from the server 51 | 52 | await webDavClient.GetProcessedFile("file.txt"); // get a file that can be processed by the server 53 | 54 | await webDavClient.PutFile("file.xml", File.OpenRead("file.xml"), "text/xml"); // upload a resource 55 | } 56 | ``` 57 | 58 | #### PROPFIND example 59 | ``` csharp 60 | // list files & subdirectories in 'mydir' 61 | var result = await webDavClient.Propfind("http://mywebdav/mydir"); 62 | if (result.IsSuccessful) 63 | { 64 | foreach (var res in result.Resources) 65 | { 66 | Trace.WriteLine("Name: " + res.DisplayName); 67 | Trace.WriteLine("Is directory: " + res.IsCollection); 68 | // other params 69 | } 70 | } 71 | ``` 72 | 73 | #### Authentication example 74 | ``` csharp 75 | var clientParams = new WebDavClientParams 76 | { 77 | BaseAddress = new Uri("http://mywebdav/"), 78 | Credentials = new NetworkCredential("user", "12345") 79 | }; 80 | using (var webDavClient = new WebDavClient(clientParams)) 81 | { 82 | // call webdav methods... 83 | } 84 | ``` 85 | 86 | #### License 87 | WebDAV-Client is licensed under the MIT License. 88 | -------------------------------------------------------------------------------- /WebDAV-Client-Solution.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33213.308 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F3674172-2C87-4529-8B3B-D4047ED5F1C3}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{570FF30A-3A31-43E4-A8C3-56610FA26DFA}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Solution Items", "_Solution Items", "{7898F0E5-AE83-4BE9-B8D9-BBD92A4858DF}" 11 | ProjectSection(SolutionItems) = preProject 12 | appveyor.yml = appveyor.yml 13 | CHANGELOG.md = CHANGELOG.md 14 | Generate-ReleaseNotes.cmd = Generate-ReleaseNotes.cmd 15 | README.md = README.md 16 | EndProjectSection 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{049FB370-482F-40A4-A38B-81E600E98775}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebDAV-Client", "src\WebDAV-Client\WebDAV-Client.csproj", "{7C2D4AAD-02B1-4E29-9C10-F397482DC6FC}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebDAV-Client.Tests", "test\WebDAV-Client.Tests\WebDAV-Client.Tests.csproj", "{9C2BF524-C306-4C94-BAC9-2E4ED06B8943}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebDAV-Client.Tests.Net452", "test\WebDAV-Client.Tests.Net452\WebDAV-Client.Tests.Net452.csproj", "{DF7DE4B0-00DD-4B96-A6EF-7C7C83CE689D}" 25 | ProjectSection(ProjectDependencies) = postProject 26 | {7C2D4AAD-02B1-4E29-9C10-F397482DC6FC} = {7C2D4AAD-02B1-4E29-9C10-F397482DC6FC} 27 | EndProjectSection 28 | EndProject 29 | Global 30 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 31 | Debug|Any CPU = Debug|Any CPU 32 | Release|Any CPU = Release|Any CPU 33 | EndGlobalSection 34 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 35 | {7C2D4AAD-02B1-4E29-9C10-F397482DC6FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {7C2D4AAD-02B1-4E29-9C10-F397482DC6FC}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {7C2D4AAD-02B1-4E29-9C10-F397482DC6FC}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {7C2D4AAD-02B1-4E29-9C10-F397482DC6FC}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {9C2BF524-C306-4C94-BAC9-2E4ED06B8943}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {9C2BF524-C306-4C94-BAC9-2E4ED06B8943}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {9C2BF524-C306-4C94-BAC9-2E4ED06B8943}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {9C2BF524-C306-4C94-BAC9-2E4ED06B8943}.Release|Any CPU.Build.0 = Release|Any CPU 43 | {DF7DE4B0-00DD-4B96-A6EF-7C7C83CE689D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 44 | {DF7DE4B0-00DD-4B96-A6EF-7C7C83CE689D}.Debug|Any CPU.Build.0 = Debug|Any CPU 45 | {DF7DE4B0-00DD-4B96-A6EF-7C7C83CE689D}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {DF7DE4B0-00DD-4B96-A6EF-7C7C83CE689D}.Release|Any CPU.Build.0 = Release|Any CPU 47 | EndGlobalSection 48 | GlobalSection(SolutionProperties) = preSolution 49 | HideSolutionNode = FALSE 50 | EndGlobalSection 51 | GlobalSection(NestedProjects) = preSolution 52 | {7C2D4AAD-02B1-4E29-9C10-F397482DC6FC} = {F3674172-2C87-4529-8B3B-D4047ED5F1C3} 53 | {9C2BF524-C306-4C94-BAC9-2E4ED06B8943} = {570FF30A-3A31-43E4-A8C3-56610FA26DFA} 54 | {DF7DE4B0-00DD-4B96-A6EF-7C7C83CE689D} = {570FF30A-3A31-43E4-A8C3-56610FA26DFA} 55 | EndGlobalSection 56 | GlobalSection(ExtensibilityGlobals) = postSolution 57 | SolutionGuid = {A8E50C61-508C-4512-B7A6-02E1C9D34AC4} 58 | EndGlobalSection 59 | EndGlobal 60 | -------------------------------------------------------------------------------- /WebDAV-Client-Solution.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/CopyParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents parameters for the COPY WebDAV method. 7 | /// 8 | public class CopyParameters 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | public CopyParameters() 14 | { 15 | Overwrite = true; 16 | CancellationToken = CancellationToken.None; 17 | } 18 | 19 | /// 20 | /// Gets or sets a value indicating whether the method is to be applied only to the resource or the resource and all its members. 21 | /// It corresponds to the WebDAV Depth header. 22 | /// 23 | public ApplyTo.Copy? ApplyTo { get; set; } 24 | 25 | /// 26 | /// Gets or sets the lock token for the destination resource. 27 | /// 28 | public string DestLockToken { get; set; } 29 | 30 | /// 31 | /// Gets or sets a value indicating whether the server should overwrite a non-null destination. 32 | /// For more information see https://msdn.microsoft.com/en-us/library/aa142944. 33 | /// 34 | /// 35 | /// true if the the server should overwrite a non-null destination; otherwise false. The default value is true. 36 | /// 37 | public bool Overwrite { get; set; } 38 | 39 | /// 40 | /// Gets or sets the cancellation token. 41 | /// 42 | public CancellationToken CancellationToken { get; set; } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/DeleteParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents parameters for the DELETE WebDAV method. 7 | /// 8 | public class DeleteParameters 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | public DeleteParameters() 14 | { 15 | CancellationToken = CancellationToken.None; 16 | } 17 | 18 | /// 19 | /// Gets or sets the resource lock token. 20 | /// 21 | public string LockToken { get; set; } 22 | 23 | /// 24 | /// Gets or sets the cancellation token. 25 | /// 26 | public CancellationToken CancellationToken { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/GetFileParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents parameters for the GET WebDAV method. 7 | /// 8 | public class GetFileParameters 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | public GetFileParameters() 14 | { 15 | CancellationToken = CancellationToken.None; 16 | } 17 | 18 | /// 19 | /// Gets or sets the cancellation token. 20 | /// 21 | public CancellationToken CancellationToken { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/LockParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace WebDav 5 | { 6 | /// 7 | /// Represents parameters for the LOCK WebDAV method. 8 | /// 9 | public class LockParameters 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | public LockParameters() 15 | { 16 | CancellationToken = CancellationToken.None; 17 | } 18 | 19 | /// 20 | /// Gets or sets a value indicating whether this lock is an exclusive lock or a shared lock. 21 | /// 22 | public LockScope LockScope { get; set; } 23 | 24 | /// 25 | /// Gets or sets the timeout of this lock. 26 | /// 27 | public TimeSpan? Timeout { get; set; } 28 | 29 | /// 30 | /// Gets or sets a value indicating whether the method is to be applied only to the resource or the resource and all its members. 31 | /// It corresponds to the WebDAV Depth header. 32 | /// 33 | public ApplyTo.Lock? ApplyTo { get; set; } 34 | 35 | /// 36 | /// Gets or sets the owner of this lock. 37 | /// 38 | public LockOwner Owner { get; set; } 39 | 40 | /// 41 | /// Gets or sets the cancellation token. 42 | /// 43 | public CancellationToken CancellationToken { get; set; } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/MkColParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents parameters for the MKCOL WebDAV method. 7 | /// 8 | public class MkColParameters 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | public MkColParameters() 14 | { 15 | CancellationToken = CancellationToken.None; 16 | } 17 | 18 | /// 19 | /// Gets or sets the resource lock token. 20 | /// 21 | public string LockToken { get; set; } 22 | 23 | /// 24 | /// Gets or sets the cancellation token. 25 | /// 26 | public CancellationToken CancellationToken { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/MoveParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents parameters for the MOVE WebDAV method. 7 | /// 8 | public class MoveParameters 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | public MoveParameters() 14 | { 15 | Overwrite = true; 16 | CancellationToken = CancellationToken.None; 17 | } 18 | 19 | /// 20 | /// Gets or sets the lock token for the moving resource. 21 | /// 22 | public string SourceLockToken { get; set; } 23 | 24 | /// 25 | /// Gets or sets the lock token for the destination resource. 26 | /// 27 | public string DestLockToken { get; set; } 28 | 29 | /// 30 | /// Gets or sets a value indicating whether the server should overwrite a non-null destination. 31 | /// For more information see https://msdn.microsoft.com/en-us/library/aa142944. 32 | /// 33 | /// 34 | /// true if the the server should overwrite a non-null destination; otherwise false. The default value is true. 35 | /// 36 | public bool Overwrite { get; set; } 37 | 38 | /// 39 | /// Gets or sets the cancellation token. 40 | /// 41 | public CancellationToken CancellationToken { get; set; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/PropfindParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Xml.Linq; 4 | 5 | namespace WebDav 6 | { 7 | /// 8 | /// Represents parameters for the PROPFIND WebDAV method. 9 | /// 10 | public class PropfindParameters 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public PropfindParameters() 16 | { 17 | CustomProperties = new List(); 18 | Namespaces = new List(); 19 | CancellationToken = CancellationToken.None; 20 | } 21 | 22 | /// 23 | /// Gets or sets the collection of custom properties (or dead properties in terms of WebDav). 24 | /// 25 | public IReadOnlyCollection CustomProperties { get; set; } 26 | 27 | /// 28 | /// Gets or sets the collection of xml namespaces of properties. 29 | /// 30 | public IReadOnlyCollection Namespaces { get; set; } 31 | 32 | /// 33 | /// Gets or sets a value indicating whether the method is to be applied only to the resource, to the resource and its internal members only, or the resource and all its members. 34 | /// It corresponds to the WebDAV Depth header. 35 | /// 36 | public ApplyTo.Propfind? ApplyTo { get; set; } 37 | 38 | /// 39 | /// Gets or sets the cancellation token. 40 | /// 41 | public CancellationToken CancellationToken { get; set; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/ProppatchParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Xml.Linq; 4 | 5 | namespace WebDav 6 | { 7 | /// 8 | /// Represents parameters for the PROPPATCH WebDAV method. 9 | /// 10 | public class ProppatchParameters 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public ProppatchParameters() 16 | { 17 | PropertiesToSet = new Dictionary(); 18 | PropertiesToRemove = new List(); 19 | Namespaces = new List(); 20 | CancellationToken = CancellationToken.None; 21 | } 22 | 23 | /// 24 | /// Gets or sets properties to set on the resource. 25 | /// 26 | public IDictionary PropertiesToSet { get; set; } 27 | 28 | /// 29 | /// Gets or sets the collection of properties defined on the resource to remove. 30 | /// 31 | public IReadOnlyCollection PropertiesToRemove { get; set; } 32 | 33 | /// 34 | /// Gets or sets the collection of xml namespaces of properties. 35 | /// 36 | public IReadOnlyCollection Namespaces { get; set; } 37 | 38 | /// 39 | /// Gets or sets the cancellation token. 40 | /// 41 | public CancellationToken CancellationToken { get; set; } 42 | 43 | /// 44 | /// Gets or sets the resource lock token. 45 | /// 46 | public string LockToken { get; set; } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/PutFileParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents parameters for the PUT WebDAV method. 7 | /// 8 | public class PutFileParameters 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | public PutFileParameters() 14 | { 15 | ContentType = "application/octet-stream"; 16 | CancellationToken = CancellationToken.None; 17 | } 18 | 19 | /// 20 | /// Gets or sets the content type of the request body. 21 | /// The default value is application/octet-stream. 22 | /// 23 | public string ContentType { get; set; } 24 | 25 | /// 26 | /// Gets or sets the resource lock token. 27 | /// 28 | public string LockToken { get; set; } 29 | 30 | /// 31 | /// Gets or sets the cancellation token. 32 | /// 33 | public CancellationToken CancellationToken { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/RequestParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net.Http; 3 | 4 | namespace WebDav 5 | { 6 | internal class RequestParameters 7 | { 8 | public RequestParameters() 9 | { 10 | Headers = new List>(); 11 | } 12 | 13 | public IReadOnlyCollection> Headers { get; set; } 14 | 15 | public HttpContent Content { get; set; } 16 | 17 | public string ContentType { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/UnlockParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using JetBrains.Annotations; 3 | 4 | namespace WebDav 5 | { 6 | /// 7 | /// Represents parameters for the UNLOCK WebDAV method. 8 | /// 9 | public class UnlockParameters 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// The resource lock token. 14 | /// 15 | public UnlockParameters([NotNull] string lockToken) 16 | { 17 | Check.NotNull(lockToken, nameof(lockToken)); 18 | 19 | LockToken = lockToken; 20 | CancellationToken = CancellationToken.None; 21 | } 22 | 23 | /// 24 | /// Gets the resource lock token. 25 | /// 26 | public string LockToken { get; private set; } 27 | 28 | /// 29 | /// Gets or sets the cancellation token. 30 | /// 31 | public CancellationToken CancellationToken { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/WebDAV-Client/ApiParams/WebDavClientParams.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net; 4 | using System.Net.Http; 5 | 6 | namespace WebDav 7 | { 8 | /// 9 | /// Represents parameters for the class. 10 | /// 11 | public class WebDavClientParams 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | public WebDavClientParams() 17 | { 18 | UseDefaultCredentials = true; 19 | DefaultRequestHeaders = new Dictionary(); 20 | Timeout = TimeSpan.FromMilliseconds(-1); // Infinite timespan is nothing but TimeSpan with milliseconds set to -1 21 | UseProxy = true; 22 | PreAuthenticate = true; 23 | } 24 | 25 | /// 26 | /// Gets or sets the HTTP message handler. Note that this overrides some other properties in this class like: 27 | /// - PreAuthenticate 28 | /// - UseDefaultCredentials 29 | /// - UseProxy 30 | /// - Credentials 31 | /// - Proxy 32 | /// 33 | public HttpMessageHandler HttpMessageHandler { get; set; } 34 | 35 | /// 36 | /// Gets or sets a value that controls whether default credentials are sent. 37 | /// 38 | /// 39 | /// true if the default credentials are used; otherwise false. The default value is true. 40 | /// 41 | public bool UseDefaultCredentials { get; set; } 42 | 43 | /// 44 | /// Gets or sets the base address of the resource's URI used when sending requests. 45 | /// 46 | public Uri BaseAddress { get; set; } 47 | 48 | /// 49 | /// Gets or sets authentication information used by the WebDavClient. 50 | /// 51 | public ICredentials Credentials { get; set; } 52 | 53 | /// 54 | /// Gets or sets the headers which should be sent with each request. 55 | /// 56 | public IDictionary DefaultRequestHeaders { get; set; } 57 | 58 | /// 59 | /// Gets or sets a value that indicates whether an Authorization header should be sent with the request. 60 | /// 61 | /// 62 | /// true if an HTTP Authorization header should be send with requests after authentication has taken place; otherwise, false. The default value is true. 63 | /// 64 | public bool PreAuthenticate { get; set; } 65 | 66 | /// 67 | /// Gets or sets proxy information used by the WebDavClient. 68 | /// 69 | public IWebProxy Proxy { get; set; } 70 | 71 | /// 72 | /// Gets or sets a timeout for WebDAV operations. 73 | /// 74 | public TimeSpan Timeout { get; set; } 75 | 76 | /// 77 | /// Gets or sets a value indicating whether a proxy should be used for requests. 78 | /// 79 | /// 80 | /// true if a proxy should be used for requests; otherwise, false. The default value is true. 81 | /// 82 | public bool UseProxy { get; set; } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Domain/ActiveLock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents an active lock taken on a WebDAV resource. 7 | /// 8 | public class ActiveLock 9 | { 10 | private ActiveLock() 11 | { 12 | } 13 | 14 | /// 15 | /// Gets a value indicating whether the lock is to be applied only to the resource or the resource and all its members. 16 | /// It corresponds to the WebDAV Depth header. 17 | /// 18 | public ApplyTo.Lock? ApplyTo { get; private set; } 19 | 20 | /// 21 | /// Gets a value indicating whether this lock is an exclusive lock or a shared lock. 22 | /// 23 | public LockScope? LockScope { get; private set; } 24 | 25 | /// 26 | /// Gets the resource lock token. 27 | /// 28 | public string LockToken { get; private set; } 29 | 30 | /// 31 | /// Gets the owner of this lock. 32 | /// 33 | public LockOwner Owner { get; private set; } 34 | 35 | /// 36 | /// Gets the root URL of the lock, which is the URL through which the resource was addressed in the LOCK request. 37 | /// 38 | public string LockRoot { get; private set; } 39 | 40 | /// 41 | /// Gets the duration of this lock. 42 | /// 43 | public TimeSpan? Timeout { get; private set; } 44 | 45 | /// 46 | /// Represents a builder of the class. 47 | /// 48 | public class Builder 49 | { 50 | private ApplyTo.Lock? _applyTo; 51 | private LockScope? _lockScope; 52 | private string _lockToken; 53 | private LockOwner _owner; 54 | private string _lockRoot; 55 | private TimeSpan? _timeout; 56 | 57 | /// 58 | /// Sets the ApplyTo parameter of an instance of the class. 59 | /// 60 | public Builder WithApplyTo(ApplyTo.Lock? applyTo) 61 | { 62 | _applyTo = applyTo; 63 | return this; 64 | } 65 | 66 | /// 67 | /// Sets the LockTo parameter of an instance of the class. 68 | /// 69 | public Builder WithLockScope(LockScope? lockScope) 70 | { 71 | _lockScope = lockScope; 72 | return this; 73 | } 74 | 75 | /// 76 | /// Sets the LockToken parameter of an instance of the class. 77 | /// 78 | public Builder WithLockToken(string lockToken) 79 | { 80 | _lockToken = lockToken; 81 | return this; 82 | } 83 | 84 | /// 85 | /// Sets the Owner parameter of an instance of the class. 86 | /// 87 | public Builder WithOwner(LockOwner owner) 88 | { 89 | _owner = owner; 90 | return this; 91 | } 92 | 93 | /// 94 | /// Sets the LockRoot parameter of an instance of the class. 95 | /// 96 | public Builder WithLockRoot(string lockRoot) 97 | { 98 | _lockRoot = lockRoot; 99 | return this; 100 | } 101 | 102 | /// 103 | /// Sets the Timeout parameter of an instance of the class. 104 | /// 105 | public Builder WithTimeout(TimeSpan? timeout) 106 | { 107 | _timeout = timeout; 108 | return this; 109 | } 110 | 111 | /// 112 | /// Builds a new instance of the class. 113 | /// 114 | /// A new instance of the class. 115 | public ActiveLock Build() 116 | { 117 | return new ActiveLock 118 | { 119 | ApplyTo = _applyTo, 120 | LockScope = _lockScope, 121 | LockToken = _lockToken, 122 | Owner = _owner, 123 | LockRoot = _lockRoot, 124 | Timeout = _timeout 125 | }; 126 | } 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Domain/ApplyTo.cs: -------------------------------------------------------------------------------- 1 | namespace WebDav 2 | { 3 | /// 4 | /// Contains classes to specify AppltTo for concrete methods. 5 | /// 6 | public static class ApplyTo 7 | { 8 | /// 9 | /// Specifies whether the PROPFIND method is to be applied only to the resource, to the resource and its internal members only, or the resource and all its members. 10 | /// It corresponds to the WebDAV Depth header. 11 | /// 12 | public enum Propfind 13 | { 14 | ResourceOnly, 15 | ResourceAndChildren, 16 | ResourceAndAncestors 17 | } 18 | 19 | /// 20 | /// Specifies whether the COPY method is to be applied only to the resource or the resource and all its members. 21 | /// It corresponds to the WebDAV Depth header. 22 | /// 23 | public enum Copy 24 | { 25 | ResourceOnly, 26 | ResourceAndAncestors 27 | } 28 | 29 | /// 30 | /// Specifies whether the LOCK method is to be applied only to the resource or the resource and all its members. 31 | /// It corresponds to the WebDAV Depth header. 32 | /// 33 | public enum Lock 34 | { 35 | ResourceOnly, 36 | ResourceAndAncestors 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Domain/LockOwner.cs: -------------------------------------------------------------------------------- 1 | namespace WebDav 2 | { 3 | /// 4 | /// Represents a lock owner. 5 | /// 6 | public abstract class LockOwner 7 | { 8 | /// 9 | /// Gets a value representing an owner. 10 | /// 11 | public abstract string Value { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Domain/LockScope.cs: -------------------------------------------------------------------------------- 1 | namespace WebDav 2 | { 3 | /// 4 | /// Specifies a type of lock - exclusive or shared. 5 | /// 6 | public enum LockScope 7 | { 8 | Shared, 9 | Exclusive 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Domain/NamespaceAttr.cs: -------------------------------------------------------------------------------- 1 | namespace WebDav 2 | { 3 | /// 4 | /// Represents an xml namespace attribute. 5 | /// 6 | public class NamespaceAttr 7 | { 8 | /// 9 | /// Initializes a new instance of the class. 10 | /// 11 | /// The default namespace. 12 | public NamespaceAttr(string defaultNamespace) 13 | { 14 | Namespace = defaultNamespace; 15 | } 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The prefix of the namespace 21 | /// The namespace in form of URI specified at an xmlns attribute 22 | public NamespaceAttr(string prefix, string @namespace) 23 | { 24 | Prefix = prefix; 25 | Namespace = @namespace; 26 | } 27 | 28 | /// 29 | /// Gets the prefix of this namespace. 30 | /// 31 | public string Prefix { get; private set; } 32 | 33 | /// 34 | /// Gets the namespace in form of URI specified at an xmlns attribute as follows. xmlns:prefix="URI". 35 | /// 36 | public string Namespace { get; private set; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Domain/PrincipalLockOwner.cs: -------------------------------------------------------------------------------- 1 | using JetBrains.Annotations; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents a lock owner identified by principal name. 7 | /// 8 | public class PrincipalLockOwner : LockOwner 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// Name of the principal. 14 | public PrincipalLockOwner([NotNull] string principalName) 15 | { 16 | Check.NotNull(principalName, nameof(principalName)); 17 | Value = principalName; 18 | } 19 | 20 | /// 21 | /// Gets a value representing an owner. 22 | /// 23 | public override string Value { get; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Domain/UriLockOwner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents a lock owner identified by URI. 7 | /// 8 | public class UriLockOwner : LockOwner 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The absolute URI. 14 | /// The parameter uri should be a valid absolute uri.;absoluteUri 15 | public UriLockOwner(string absoluteUri) 16 | { 17 | if (!Uri.IsWellFormedUriString(absoluteUri, UriKind.Absolute)) 18 | throw new ArgumentException("The parameter uri should be a valid absolute uri.", nameof(absoluteUri)); 19 | Value = absoluteUri; 20 | } 21 | 22 | /// 23 | /// Gets a value representing an owner. 24 | /// 25 | public override string Value { get; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Domain/WebDavMethod.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | 3 | namespace WebDav 4 | { 5 | internal static class WebDavMethod 6 | { 7 | public static readonly HttpMethod Propfind = new HttpMethod("PROPFIND"); 8 | 9 | public static readonly HttpMethod Proppatch = new HttpMethod("PROPPATCH"); 10 | 11 | public static readonly HttpMethod Mkcol = new HttpMethod("MKCOL"); 12 | 13 | public static readonly HttpMethod Copy = new HttpMethod("COPY"); 14 | 15 | public static readonly HttpMethod Move = new HttpMethod("MOVE"); 16 | 17 | public static readonly HttpMethod Lock = new HttpMethod("LOCK"); 18 | 19 | public static readonly HttpMethod Unlock = new HttpMethod("UNLOCK"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Domain/WebDavProperty.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents a WebDAV resource property. 7 | /// 8 | public class WebDavProperty 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The property name. 14 | /// The property value. 15 | public WebDavProperty(XName name, string value) 16 | { 17 | Check.NotEmpty((name ?? "").ToString(), nameof(name)); 18 | 19 | Name = name; 20 | Value = value; 21 | } 22 | 23 | /// 24 | /// Gets the property name. 25 | /// 26 | public XName Name { get; private set; } 27 | 28 | /// 29 | /// Gets the property value. 30 | /// 31 | public string Value { get; private set; } 32 | 33 | public override string ToString() 34 | { 35 | return string.Format("{{ Name: {0}, Value: {1} }}", Name, Value); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Domain/WebDavPropertyStatus.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents a status of an operation on a resource property. 7 | /// 8 | public class WebDavPropertyStatus 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The property name. 14 | /// The status code of the operation. 15 | public WebDavPropertyStatus(XName name, int statusCode) 16 | :this (name, statusCode, null) 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The property name. 24 | /// The status code of the operation. 25 | /// The description of the operation. 26 | public WebDavPropertyStatus(XName name, int statusCode, string description) 27 | { 28 | Check.NotEmpty((name ?? "").ToString(), nameof(name)); 29 | 30 | Name = name; 31 | StatusCode = statusCode; 32 | Description = description; 33 | } 34 | 35 | /// 36 | /// Gets the property name. 37 | /// 38 | public XName Name { get; private set; } 39 | 40 | /// 41 | /// Gets the status code of the operation. 42 | /// 43 | public int StatusCode { get; private set; } 44 | 45 | /// 46 | /// Gets the description of the operation. 47 | /// 48 | public string Description { get; private set; } 49 | 50 | /// 51 | /// Gets a value indicating whether the operation on the property was successful. 52 | /// 53 | /// 54 | /// true if the operation was successfull; otherwise, false. 55 | /// 56 | public virtual bool IsSuccessful => StatusCode >= 200 && StatusCode <= 299; 57 | 58 | public override string ToString() 59 | { 60 | return string.Format("{{ Name: {0}, StatusCode: {1}, Description: {2} }}", Name, StatusCode, Description); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Domain/WebDavResource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using JetBrains.Annotations; 4 | 5 | namespace WebDav 6 | { 7 | /// 8 | /// Represents a WebDAV resource. 9 | /// 10 | public class WebDavResource 11 | { 12 | /// 13 | /// Prevents a default instance of the class from being created. 14 | /// 15 | private WebDavResource() 16 | { 17 | Properties = new List(); 18 | PropertyStatuses = new List(); 19 | } 20 | 21 | /// 22 | /// Gets a collection locks on this resource. 23 | /// 24 | public IReadOnlyCollection ActiveLocks { get; private set; } 25 | 26 | /// 27 | /// Gets the content language of this resource. 28 | /// 29 | public string ContentLanguage { get; private set; } 30 | 31 | /// 32 | /// Gets the content length of this resource. 33 | /// 34 | public int? ContentLength { get; private set; } 35 | 36 | /// 37 | /// Gets the content type of this resource. 38 | /// 39 | public string ContentType { get; private set; } 40 | 41 | /// 42 | /// Gets the creation date of this resource. 43 | /// 44 | public DateTime? CreationDate { get; private set; } 45 | 46 | /// 47 | /// Gets the display name of this resource. 48 | /// 49 | public string DisplayName { get; private set; } 50 | 51 | /// 52 | /// Gets the ETag of this resource. 53 | /// 54 | public string ETag { get; private set; } 55 | 56 | /// 57 | /// Gets the URI of this resource. 58 | /// 59 | public string Uri { get; private set; } 60 | 61 | /// 62 | /// Gets a value indicating whether this resource is a collection. 63 | /// 64 | /// 65 | /// true if this resource is a collection; otherwise, false. The default value is false. 66 | /// 67 | public bool IsCollection { get; private set; } 68 | 69 | /// 70 | /// Gets a value indicating whether this resource is hidden. 71 | /// 72 | /// 73 | /// true if this resource is hidden; otherwise, false. The default value is false. 74 | /// 75 | public bool IsHidden { get; private set; } 76 | 77 | /// 78 | /// Gets the last modified date of this resource. 79 | /// 80 | public DateTime? LastModifiedDate { get; private set; } 81 | 82 | /// 83 | /// Gets the collection of properties of this resource. 84 | /// 85 | public IReadOnlyCollection Properties { get; private set; } 86 | 87 | /// 88 | /// Gets the collection of property statuses of this resource. 89 | /// 90 | public IReadOnlyCollection PropertyStatuses { get; private set; } 91 | 92 | /// 93 | /// Represents a builder of the class. 94 | /// 95 | public class Builder 96 | { 97 | private IReadOnlyCollection _activeLocks; 98 | private string _contentLanguage; 99 | private int? _contentLength; 100 | private string _contentType; 101 | private DateTime? _creationDate; 102 | private string _displayName; 103 | private string _eTag; 104 | private string _uri; 105 | private bool _isCollection; 106 | private bool _isHidden; 107 | private DateTime? _lastModifiedDate; 108 | private IReadOnlyCollection _properties; 109 | private IReadOnlyCollection _propertyStatuses; 110 | 111 | /// 112 | /// Sets the ActiveLocks parameter of an instance of the class. 113 | /// 114 | public Builder WithActiveLocks(IReadOnlyCollection activeLocks) 115 | { 116 | _activeLocks = activeLocks; 117 | return this; 118 | } 119 | 120 | /// 121 | /// Sets the ContentLanguage parameter of an instance of the class. 122 | /// 123 | public Builder WithContentLanguage(string contentLanguage) 124 | { 125 | _contentLanguage = contentLanguage; 126 | return this; 127 | } 128 | 129 | /// 130 | /// Sets the ContentLength parameter of an instance of the class. 131 | /// 132 | public Builder WithContentLength(int? contentLength) 133 | { 134 | _contentLength = contentLength; 135 | return this; 136 | } 137 | 138 | /// 139 | /// Sets the ContentType parameter of an instance of the class. 140 | /// 141 | public Builder WithContentType(string contentType) 142 | { 143 | _contentType = contentType; 144 | return this; 145 | } 146 | 147 | /// 148 | /// Sets the CreationDate parameter of an instance of the class. 149 | /// 150 | public Builder WithCreationDate(DateTime? creationDate) 151 | { 152 | _creationDate = creationDate; 153 | return this; 154 | } 155 | 156 | /// 157 | /// Sets the DisplayName parameter of an instance of the class. 158 | /// 159 | public Builder WithDisplayName(string displayName) 160 | { 161 | _displayName = displayName; 162 | return this; 163 | } 164 | 165 | /// 166 | /// Sets the ETag parameter of an instance of the class. 167 | /// 168 | public Builder WithETag(string eTag) 169 | { 170 | _eTag = eTag; 171 | return this; 172 | } 173 | 174 | /// 175 | /// Sets the Uri parameter of an instance of the class. 176 | /// 177 | public Builder WithUri(string uri) 178 | { 179 | _uri = uri; 180 | return this; 181 | } 182 | 183 | /// 184 | /// Sets the IsCollection parameter of an instance of the class to true. 185 | /// 186 | public Builder IsCollection() 187 | { 188 | _isCollection = true; 189 | return this; 190 | } 191 | 192 | /// 193 | /// Sets the IsCollection parameter of an instance of the class to false. 194 | /// 195 | public Builder IsNotCollection() 196 | { 197 | _isCollection = false; 198 | return this; 199 | } 200 | 201 | /// 202 | /// Sets the IsHidden parameter of an instance of the class to true. 203 | /// 204 | public Builder IsHidden() 205 | { 206 | _isHidden = true; 207 | return this; 208 | } 209 | 210 | /// 211 | /// Sets the IsHidden parameter of an instance of the class to false. 212 | /// 213 | public Builder IsNotHidden() 214 | { 215 | _isHidden = false; 216 | return this; 217 | } 218 | 219 | /// 220 | /// Sets the LastModifiedDate parameter of an instance of the class. 221 | /// 222 | public Builder WithLastModifiedDate(DateTime? lastModifiedDate) 223 | { 224 | _lastModifiedDate = lastModifiedDate; 225 | return this; 226 | } 227 | 228 | /// 229 | /// Sets the Properties parameter of an instance of the class. 230 | /// 231 | public Builder WithProperties([NotNull] IReadOnlyCollection properties) 232 | { 233 | Check.NotNull(properties, nameof(properties)); 234 | _properties = properties; 235 | return this; 236 | } 237 | 238 | /// 239 | /// Sets the PropertyStatuses parameter of an instance of the class. 240 | /// 241 | public Builder WithPropertyStatuses([NotNull] IReadOnlyCollection propertyStatuses) 242 | { 243 | Check.NotNull(propertyStatuses, nameof(propertyStatuses)); 244 | _propertyStatuses = propertyStatuses; 245 | return this; 246 | } 247 | 248 | /// 249 | /// Builds a new instance of the class. 250 | /// 251 | /// A new instance of the class. 252 | public WebDavResource Build() 253 | { 254 | return new WebDavResource 255 | { 256 | ActiveLocks = _activeLocks, 257 | ContentLanguage = _contentLanguage, 258 | ContentLength = _contentLength, 259 | ContentType = _contentType, 260 | CreationDate = _creationDate, 261 | DisplayName = _displayName, 262 | ETag = _eTag, 263 | Uri = _uri, 264 | IsCollection = _isCollection, 265 | IsHidden = _isHidden, 266 | LastModifiedDate = _lastModifiedDate, 267 | Properties = _properties, 268 | PropertyStatuses = _propertyStatuses 269 | }; 270 | } 271 | } 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Extensions/LinqToXmlExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Xml.Linq; 5 | 6 | namespace WebDav 7 | { 8 | internal static class LinqToXmlExtensions 9 | { 10 | public static string ToStringWithDeclaration(this XDocument doc) 11 | { 12 | if (doc == null) 13 | throw new ArgumentNullException(nameof(doc)); 14 | 15 | return doc.Declaration + Environment.NewLine + doc; 16 | } 17 | 18 | public static string GetValueOrNull(this XElement element) 19 | { 20 | return element != null ? element.Value : null; 21 | } 22 | 23 | public static XElement LocalNameElement(this XElement parent, string localName) 24 | { 25 | return LocalNameElement(parent, localName, StringComparison.Ordinal); 26 | } 27 | 28 | public static XElement LocalNameElement(this XElement parent, string localName, StringComparison comparisonType) 29 | { 30 | return parent.Elements().FirstOrDefault(e => e.Name.LocalName.Equals(localName, comparisonType)); 31 | } 32 | 33 | public static IEnumerable LocalNameElements(this XElement parent, string localName) 34 | { 35 | return LocalNameElements(parent, localName, StringComparison.Ordinal); 36 | } 37 | 38 | public static IEnumerable LocalNameElements(this XElement parent, string localName, StringComparison comparisonType) 39 | { 40 | return parent.Elements().Where(e => e.Name.LocalName.Equals(localName, comparisonType)); 41 | } 42 | 43 | public static string GetInnerXml(this XElement element) 44 | { 45 | using (var reader = element.CreateReader()) 46 | { 47 | reader.MoveToContent(); 48 | return reader.ReadInnerXml(); 49 | } 50 | } 51 | 52 | public static void SetInnerXml(this XElement element, string innerXml) 53 | { 54 | element.ReplaceNodes(XElement.Parse("" + innerXml + "").Nodes()); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Extensions/XDocumentExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | namespace WebDav 4 | { 5 | internal static class XDocumentExtensions 6 | { 7 | public static XDocument TryParse(string text) 8 | { 9 | try 10 | { 11 | return XDocument.Parse(text); 12 | } 13 | catch 14 | { 15 | return null; 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Helpers/DepthHeaderHelper.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace WebDav 4 | { 5 | internal static class DepthHeaderHelper 6 | { 7 | public static string GetValueForPropfind(ApplyTo.Propfind applyTo) 8 | { 9 | switch (applyTo) 10 | { 11 | case ApplyTo.Propfind.ResourceOnly: 12 | return "0"; 13 | case ApplyTo.Propfind.ResourceAndChildren: 14 | return "1"; 15 | case ApplyTo.Propfind.ResourceAndAncestors: 16 | return "infinity"; 17 | default: 18 | throw new InvalidEnumArgumentException("applyTo", (int)applyTo, typeof(ApplyTo.Propfind)); 19 | } 20 | } 21 | 22 | public static string GetValueForCopy(ApplyTo.Copy applyTo) 23 | { 24 | switch (applyTo) 25 | { 26 | case ApplyTo.Copy.ResourceOnly: 27 | return "0"; 28 | case ApplyTo.Copy.ResourceAndAncestors: 29 | return "infinity"; 30 | default: 31 | throw new InvalidEnumArgumentException("applyTo", (int)applyTo, typeof(ApplyTo.Copy)); 32 | } 33 | } 34 | 35 | public static string GetValueForLock(ApplyTo.Lock applyTo) 36 | { 37 | switch (applyTo) 38 | { 39 | case ApplyTo.Lock.ResourceOnly: 40 | return "0"; 41 | case ApplyTo.Lock.ResourceAndAncestors: 42 | return "infinity"; 43 | default: 44 | throw new InvalidEnumArgumentException("applyTo", (int)applyTo, typeof(ApplyTo.Lock)); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Helpers/IfHeaderHelper.cs: -------------------------------------------------------------------------------- 1 | namespace WebDav 2 | { 3 | internal static class IfHeaderHelper 4 | { 5 | public static string GetHeaderValue(string lockToken) 6 | { 7 | return string.Format("(<{0}>)", lockToken); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Infrastructure/HttpResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | 3 | namespace WebDav.Infrastructure 4 | { 5 | internal class HttpResponse 6 | { 7 | public HttpResponse(HttpContent content, int statusCode) 8 | : this (content, statusCode, string.Empty) 9 | { 10 | } 11 | 12 | public HttpResponse(HttpContent content, int statusCode, string description) 13 | { 14 | Content = content; 15 | StatusCode = statusCode; 16 | Description = description; 17 | } 18 | 19 | public HttpContent Content { get; private set; } 20 | 21 | public int StatusCode { get; private set; } 22 | 23 | public string Description { get; private set; } 24 | 25 | public bool IsSuccessful => StatusCode >= 200 && StatusCode <= 299; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Infrastructure/IWebDavDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace WebDav.Infrastructure 7 | { 8 | internal interface IWebDavDispatcher 9 | { 10 | Uri BaseAddress { get; } 11 | 12 | Task Send(Uri requestUri, HttpMethod method, RequestParameters requestParams, CancellationToken cancellationToken); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Infrastructure/WebDavDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Net.Http.Headers; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using JetBrains.Annotations; 7 | 8 | namespace WebDav.Infrastructure 9 | { 10 | internal class WebDavDispatcher : IWebDavDispatcher, IDisposable 11 | { 12 | private readonly HttpClient _httpClient; 13 | 14 | public WebDavDispatcher([NotNull] HttpClient httpClient) 15 | { 16 | Check.NotNull(httpClient, nameof(httpClient)); 17 | 18 | _httpClient = httpClient; 19 | } 20 | 21 | public Uri BaseAddress => _httpClient.BaseAddress; 22 | 23 | public async Task Send(Uri requestUri, HttpMethod method, RequestParameters requestParams, CancellationToken cancellationToken) 24 | { 25 | using (var request = new HttpRequestMessage(method, requestUri)) 26 | { 27 | foreach (var header in requestParams.Headers) 28 | { 29 | request.Headers.Add(header.Key, header.Value); 30 | } 31 | 32 | if (requestParams.Content != null) 33 | { 34 | request.Content = requestParams.Content; 35 | if (!string.IsNullOrEmpty(requestParams.ContentType)) 36 | request.Content.Headers.ContentType = new MediaTypeHeaderValue(requestParams.ContentType); 37 | } 38 | 39 | var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); 40 | return new HttpResponse(response.Content, (int)response.StatusCode, response.ReasonPhrase); 41 | } 42 | } 43 | 44 | #region IDisposable 45 | 46 | public void Dispose() 47 | { 48 | DisposeManagedResources(); 49 | } 50 | 51 | protected virtual void DisposeManagedResources() 52 | { 53 | _httpClient?.Dispose(); 54 | } 55 | 56 | #endregion 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("WebDAV-Client.Tests")] 4 | [assembly: InternalsVisibleTo("WebDAV-Client.Tests.Net452")] 5 | [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] -------------------------------------------------------------------------------- /src/WebDAV-Client/Request/LockRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Xml.Linq; 4 | 5 | namespace WebDav.Request 6 | { 7 | internal static class LockRequestBuilder 8 | { 9 | public static string BuildRequestBody(LockParameters lockParams) 10 | { 11 | var doc = new XDocument(new XDeclaration("1.0", "utf-8", null)); 12 | var lockinfo = new XElement("{DAV:}lockinfo", new XAttribute(XNamespace.Xmlns + "D", "DAV:")); 13 | 14 | lockinfo.Add(GetLockScope(lockParams.LockScope)); 15 | lockinfo.Add(GetLockType()); 16 | 17 | if (lockParams.Owner != null) 18 | lockinfo.Add(GetLockOwner(lockParams.Owner)); 19 | 20 | doc.Add(lockinfo); 21 | return doc.ToStringWithDeclaration(); 22 | } 23 | 24 | private static XElement GetLockScope(LockScope lockScope) 25 | { 26 | var lockscope = new XElement("{DAV:}lockscope"); 27 | switch (lockScope) 28 | { 29 | case LockScope.Shared: 30 | lockscope.Add(new XElement("{DAV:}shared")); 31 | break; 32 | case LockScope.Exclusive: 33 | lockscope.Add(new XElement("{DAV:}exclusive")); 34 | break; 35 | default: 36 | throw new InvalidEnumArgumentException("lockScope", (int)lockScope, typeof(LockScope)); 37 | } 38 | return lockscope; 39 | } 40 | 41 | private static XElement GetLockType() 42 | { 43 | var locktype = new XElement("{DAV:}locktype"); 44 | locktype.Add(new XElement("{DAV:}write")); 45 | return locktype; 46 | } 47 | 48 | private static XElement GetLockOwner(LockOwner lockOwner) 49 | { 50 | var owner = new XElement("{DAV:}owner"); 51 | 52 | if (lockOwner is PrincipalLockOwner) 53 | { 54 | owner.SetValue(lockOwner.Value); 55 | } 56 | else if (lockOwner is UriLockOwner) 57 | { 58 | var uri = new XElement("{DAV:}href"); 59 | uri.SetValue(lockOwner.Value); 60 | owner.Add(uri); 61 | } 62 | else 63 | { 64 | throw new ArgumentException("Lock owner is invalid.", nameof(lockOwner)); 65 | } 66 | 67 | return owner; 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/WebDAV-Client/Request/PropfindRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Xml.Linq; 4 | 5 | namespace WebDav.Request 6 | { 7 | internal static class PropfindRequestBuilder 8 | { 9 | public static string BuildRequestBody(IReadOnlyCollection customProperties, IReadOnlyCollection namespaces) 10 | { 11 | var doc = new XDocument(new XDeclaration("1.0", "utf-8", null)); 12 | var propfind = new XElement("{DAV:}propfind", new XAttribute(XNamespace.Xmlns + "D", "DAV:")); 13 | propfind.Add(new XElement("{DAV:}allprop")); 14 | if (customProperties.Any()) 15 | { 16 | var include = new XElement("{DAV:}include"); 17 | foreach (var ns in namespaces) 18 | { 19 | var nsAttr = string.IsNullOrEmpty(ns.Prefix) ? "xmlns" : XNamespace.Xmlns + ns.Prefix; 20 | include.SetAttributeValue(nsAttr, ns.Namespace); 21 | } 22 | foreach (var prop in customProperties) 23 | { 24 | include.Add(new XElement(prop)); 25 | } 26 | propfind.Add(include); 27 | } 28 | doc.Add(propfind); 29 | return doc.ToStringWithDeclaration(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Request/ProppatchRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Xml.Linq; 4 | 5 | namespace WebDav.Request 6 | { 7 | internal static class ProppatchRequestBuilder 8 | { 9 | public static string BuildRequestBody(IDictionary propertiesToSet, 10 | IReadOnlyCollection propertiesToRemove, 11 | IReadOnlyCollection namespaces) 12 | { 13 | var doc = new XDocument(new XDeclaration("1.0", "utf-8", null)); 14 | var propertyupdate = new XElement("{DAV:}propertyupdate", new XAttribute(XNamespace.Xmlns + "D", "DAV:")); 15 | foreach (var ns in namespaces) 16 | { 17 | var nsAttr = string.IsNullOrEmpty(ns.Prefix) ? "xmlns" : XNamespace.Xmlns + ns.Prefix; 18 | propertyupdate.SetAttributeValue(nsAttr, ns.Namespace); 19 | } 20 | if (propertiesToSet.Any()) 21 | { 22 | var setEl = new XElement("{DAV:}set"); 23 | foreach (var prop in propertiesToSet) 24 | { 25 | var el = new XElement(prop.Key); 26 | el.SetInnerXml(prop.Value); 27 | setEl.Add(new XElement(XName.Get("prop", "DAV:"), el)); 28 | } 29 | propertyupdate.Add(setEl); 30 | } 31 | 32 | if (propertiesToRemove.Any()) 33 | { 34 | var removeEl = new XElement("{DAV:}remove"); 35 | foreach (var prop in propertiesToRemove) 36 | { 37 | removeEl.Add( 38 | new XElement(XName.Get("prop", "DAV:"), 39 | new XElement(prop))); 40 | } 41 | propertyupdate.Add(removeEl); 42 | } 43 | 44 | doc.Add(propertyupdate); 45 | return doc.ToStringWithDeclaration(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/IResponseParser.cs: -------------------------------------------------------------------------------- 1 | namespace WebDav.Response 2 | { 3 | internal interface IResponseParser 4 | { 5 | TResponse Parse(string response, int statusCode, string description); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/LockResponse.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using JetBrains.Annotations; 5 | 6 | namespace WebDav 7 | { 8 | /// 9 | /// Represents a response of the LOCK operation. 10 | /// 11 | public class LockResponse : WebDavResponse 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | /// The status code of the operation. 17 | public LockResponse(int statusCode) 18 | : this(statusCode, null, new List()) 19 | { 20 | } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The status code of the response. 26 | /// The active locks of the resource. 27 | public LockResponse(int statusCode, IEnumerable activeLocks) 28 | : this(statusCode, null, activeLocks) 29 | { 30 | } 31 | 32 | /// 33 | /// Initializes a new instance of the class. 34 | /// 35 | /// The status code of the response. 36 | /// The description of the response. 37 | public LockResponse(int statusCode, string description) 38 | : this(statusCode, description, new List()) 39 | { 40 | } 41 | 42 | /// 43 | /// Initializes a new instance of the class. 44 | /// 45 | /// The status code of the response. 46 | /// The description of the response. 47 | /// The active locks of the resource. 48 | public LockResponse(int statusCode, string description, [NotNull] IEnumerable activeLocks) 49 | : base(statusCode, description) 50 | { 51 | Check.NotNull(activeLocks, nameof(activeLocks)); 52 | ActiveLocks = activeLocks.ToList(); 53 | } 54 | 55 | /// 56 | /// Gets a collection locks on this resource. 57 | /// 58 | public IReadOnlyCollection ActiveLocks { get; private set; } 59 | 60 | public override string ToString() 61 | { 62 | return string.Format("LOCK response - StatusCode: {0}, Description: {1}", StatusCode, Description); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/LockResponseParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Xml.Linq; 5 | 6 | namespace WebDav.Response 7 | { 8 | internal class LockResponseParser : IResponseParser 9 | { 10 | public LockResponse Parse(string response, int statusCode, string description) 11 | { 12 | var xresponse = XDocumentExtensions.TryParse(response); 13 | if (xresponse == null || xresponse.Root == null) 14 | return new LockResponse(statusCode, description); 15 | 16 | var lockdiscovery = xresponse.Root.LocalNameElement("lockdiscovery", StringComparison.OrdinalIgnoreCase); 17 | var activeLocks = ParseLockDiscovery(lockdiscovery); 18 | return new LockResponse(statusCode, description, activeLocks); 19 | } 20 | 21 | public List ParseLockDiscovery(XElement lockdiscovery) 22 | { 23 | if (lockdiscovery == null) 24 | return new List(); 25 | 26 | return lockdiscovery 27 | .LocalNameElements("activelock", StringComparison.OrdinalIgnoreCase) 28 | .Select(x => CreateActiveLock(x.Elements().ToList())) 29 | .ToList(); 30 | } 31 | 32 | private ActiveLock CreateActiveLock(List properties) 33 | { 34 | var activeLock = 35 | new ActiveLock.Builder() 36 | .WithApplyTo(PropertyValueParser.ParseLockDepth(FindProp("depth", properties))) 37 | .WithLockScope(PropertyValueParser.ParseLockScope(FindProp("lockscope", properties))) 38 | .WithLockToken(PropertyValueParser.ParseString(FindProp("locktoken", properties))) 39 | .WithOwner(PropertyValueParser.ParseOwner(FindProp("owner", properties))) 40 | .WithLockRoot(PropertyValueParser.ParseString(FindProp("lockroot", properties))) 41 | .WithTimeout(PropertyValueParser.ParseLockTimeout(FindProp("timeout", properties))) 42 | .Build(); 43 | return activeLock; 44 | } 45 | 46 | private static XElement FindProp(string localName, IEnumerable properties) 47 | { 48 | return properties.FirstOrDefault(x => x.Name.LocalName.Equals(localName, StringComparison.OrdinalIgnoreCase)); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/MultiStatusParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text.RegularExpressions; 5 | using System.Xml.Linq; 6 | 7 | namespace WebDav 8 | { 9 | internal static class MultiStatusParser 10 | { 11 | private static readonly Regex StatusCodeRegex = new Regex(@".*(\d{3}).*"); 12 | 13 | public static List GetPropstats(XElement xresponse) 14 | { 15 | return xresponse.LocalNameElements("propstat", StringComparison.OrdinalIgnoreCase) 16 | .Select(x => 17 | new Propstat 18 | { 19 | Element = x, 20 | StatusCode = GetStatusCodeFromPropstat(x), 21 | Description = GetDescriptionFromPropstat(x) 22 | }) 23 | .ToList(); 24 | } 25 | 26 | public static List GetPropertyStatuses(XElement xresponse) 27 | { 28 | var propstats = GetPropstats(xresponse); 29 | return GetPropertyStatuses(propstats); 30 | } 31 | 32 | public static List GetPropertyStatuses(List propstats) 33 | { 34 | return propstats 35 | .SelectMany(x => x.Element.LocalNameElements("prop", StringComparison.OrdinalIgnoreCase) 36 | .SelectMany(p => p.Elements()) 37 | .Select(p => new { Prop = p, StatusCode = x.StatusCode, Description = x.Description })) 38 | .Select(x => new WebDavPropertyStatus(x.Prop.Name, x.StatusCode, x.Description)) 39 | .ToList(); 40 | } 41 | 42 | public static List GetProperties(List propstats) 43 | { 44 | return propstats 45 | .Where(x => IsSuccessStatusCode(x.StatusCode)) 46 | .SelectMany(x => x.Element.LocalNameElements("prop", StringComparison.OrdinalIgnoreCase)) 47 | .SelectMany(x => x.Elements()) 48 | .ToList(); 49 | } 50 | 51 | private static bool IsSuccessStatusCode(int statusCode) 52 | { 53 | return statusCode >= 200 && statusCode <= 299; 54 | } 55 | 56 | private static string GetDescriptionFromPropstat(XElement propstat) 57 | { 58 | return 59 | propstat.LocalNameElement("responsedescription", StringComparison.OrdinalIgnoreCase).GetValueOrNull() ?? 60 | propstat.LocalNameElement("status", StringComparison.OrdinalIgnoreCase).GetValueOrNull(); 61 | } 62 | 63 | private static int GetStatusCodeFromPropstat(XElement propstat) 64 | { 65 | var statusRawValue = propstat.LocalNameElement("status", StringComparison.OrdinalIgnoreCase).GetValueOrNull(); 66 | if (string.IsNullOrEmpty(statusRawValue)) 67 | return default(int); 68 | 69 | var statusCodeGroup = StatusCodeRegex.Match(statusRawValue).Groups[1]; 70 | if (!statusCodeGroup.Success) 71 | return default(int); 72 | 73 | int statusCode; 74 | if (!int.TryParse(statusCodeGroup.Value, out statusCode)) 75 | return default(int); 76 | 77 | return statusCode; 78 | } 79 | 80 | internal class Propstat 81 | { 82 | public XElement Element { get; set; } 83 | 84 | public int StatusCode { get; set; } 85 | 86 | public string Description { get; set; } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/PropertyValueParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Xml.Linq; 3 | 4 | namespace WebDav.Response 5 | { 6 | internal static class PropertyValueParser 7 | { 8 | public static string ParseString(XElement element) 9 | { 10 | return element != null ? element.Value : null; 11 | } 12 | 13 | public static int? ParseInteger(XElement element) 14 | { 15 | if (element == null) 16 | return null; 17 | 18 | int value; 19 | return int.TryParse(element.Value, out value) ? (int?)value : null; 20 | } 21 | 22 | public static DateTime? ParseDateTime(XElement element) 23 | { 24 | if (element == null) 25 | return null; 26 | 27 | DateTime value; 28 | return DateTime.TryParse(element.Value, out value) ? (DateTime?)value : null; 29 | } 30 | 31 | public static ResourceType ParseResourceType(XElement element) 32 | { 33 | if (element == null) 34 | return ResourceType.Other; 35 | 36 | return element.LocalNameElement("collection") != null 37 | ? ResourceType.Collection 38 | : ResourceType.Other; 39 | } 40 | 41 | public static LockScope? ParseLockScope(XElement element) 42 | { 43 | if (element == null) 44 | return null; 45 | 46 | if (element.LocalNameElement("shared", StringComparison.OrdinalIgnoreCase) != null) 47 | return LockScope.Shared; 48 | if (element.LocalNameElement("exclusive", StringComparison.OrdinalIgnoreCase) != null) 49 | return LockScope.Exclusive; 50 | 51 | return null; 52 | } 53 | 54 | public static ApplyTo.Lock? ParseLockDepth(XElement element) 55 | { 56 | if (element == null) 57 | return null; 58 | return element.Value.Equals("0") ? ApplyTo.Lock.ResourceOnly : ApplyTo.Lock.ResourceAndAncestors; 59 | } 60 | 61 | public static LockOwner ParseOwner(XElement element) 62 | { 63 | if (element == null) 64 | return null; 65 | 66 | var uri = element.LocalNameElement("href", StringComparison.OrdinalIgnoreCase); 67 | if (uri != null && Uri.IsWellFormedUriString(uri.Value, UriKind.Absolute)) 68 | return new UriLockOwner(uri.Value); 69 | 70 | return !string.IsNullOrEmpty(element.Value) ? new PrincipalLockOwner(element.Value) : null; 71 | } 72 | 73 | public static TimeSpan? ParseLockTimeout(XElement element) 74 | { 75 | if (element == null) 76 | return null; 77 | 78 | var value = element.Value; 79 | if (value.Equals("infinity", StringComparison.OrdinalIgnoreCase)) 80 | return null; 81 | 82 | if (value.StartsWith("Second-", StringComparison.OrdinalIgnoreCase)) 83 | { 84 | int seconds; 85 | if (int.TryParse(value.Substring(value.IndexOf("-") + 1), out seconds)) 86 | return TimeSpan.FromSeconds(seconds); 87 | } 88 | return null; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/PropfindResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using JetBrains.Annotations; 4 | 5 | namespace WebDav 6 | { 7 | /// 8 | /// Represents a response of the PROPFIND operation. 9 | /// 10 | public class PropfindResponse : WebDavResponse 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The status code of the operation. 16 | public PropfindResponse(int statusCode) 17 | : this(statusCode, null, new List()) 18 | { 19 | } 20 | 21 | /// 22 | /// Initializes a new instance of the class. 23 | /// 24 | /// The status code of the response. 25 | /// The collection of WebDAV resources. 26 | public PropfindResponse(int statusCode, IEnumerable resources) 27 | : this(statusCode, null, resources) 28 | { 29 | } 30 | 31 | /// 32 | /// Initializes a new instance of the class. 33 | /// 34 | /// The status code of the response. 35 | /// The description of the response. 36 | public PropfindResponse(int statusCode, string description) 37 | : this(statusCode, description, new List()) 38 | { 39 | } 40 | 41 | /// 42 | /// Initializes a new instance of the class. 43 | /// 44 | /// The status code of the response. 45 | /// The description of the response. 46 | /// The collection of WebDAV resources. 47 | public PropfindResponse(int statusCode, string description, [NotNull] IEnumerable resources) 48 | : base(statusCode, description) 49 | { 50 | Check.NotNull(resources, nameof(resources)); 51 | Resources = resources.ToList(); 52 | } 53 | 54 | /// 55 | /// Gets the collection of WebDAV resources. 56 | /// 57 | public IReadOnlyCollection Resources { get; private set; } 58 | 59 | public override string ToString() 60 | { 61 | return string.Format("PROPFIND WebDAV response - StatusCode: {0}, Description: {1}", StatusCode, Description); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/PropfindResponseParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using System.Xml.Linq; 6 | using JetBrains.Annotations; 7 | 8 | namespace WebDav.Response 9 | { 10 | internal class PropfindResponseParser : IResponseParser 11 | { 12 | private readonly LockResponseParser _lockResponseParser; 13 | 14 | public PropfindResponseParser([NotNull] LockResponseParser lockResponseParser) 15 | { 16 | Check.NotNull(lockResponseParser, nameof(lockResponseParser)); 17 | _lockResponseParser = lockResponseParser; 18 | } 19 | 20 | public PropfindResponse Parse(string response, int statusCode, string description) 21 | { 22 | if (string.IsNullOrEmpty(response)) 23 | return new PropfindResponse(statusCode, description); 24 | 25 | var xresponse = XDocumentExtensions.TryParse(response); 26 | if (xresponse == null || xresponse.Root == null) 27 | return new PropfindResponse(statusCode, description); 28 | 29 | var resources = xresponse.Root.LocalNameElements("response", StringComparison.OrdinalIgnoreCase) 30 | .Select(ParseResource) 31 | .ToList(); 32 | return new PropfindResponse(statusCode, description, resources); 33 | } 34 | 35 | private WebDavResource ParseResource(XElement xresponse) 36 | { 37 | var uriValue = xresponse.LocalNameElement("href", StringComparison.OrdinalIgnoreCase).GetValueOrNull(); 38 | var propstats = MultiStatusParser.GetPropstats(xresponse); 39 | return CreateResource(uriValue, propstats); 40 | } 41 | 42 | private WebDavResource CreateResource(string uri, List propstats) 43 | { 44 | var properties = MultiStatusParser.GetProperties(propstats); 45 | var resourceBuilder = new WebDavResource.Builder() 46 | .WithActiveLocks(_lockResponseParser.ParseLockDiscovery(FindProp("{DAV:}lockdiscovery", properties))) 47 | .WithContentLanguage(PropertyValueParser.ParseString(FindProp("{DAV:}getcontentlanguage", properties))) 48 | .WithContentLength(PropertyValueParser.ParseInteger(FindProp("{DAV:}getcontentlength", properties))) 49 | .WithContentType(PropertyValueParser.ParseString(FindProp("{DAV:}getcontenttype", properties))) 50 | .WithCreationDate(PropertyValueParser.ParseDateTime(FindProp("{DAV:}creationdate", properties))) 51 | .WithDisplayName(PropertyValueParser.ParseString(FindProp("{DAV:}displayname", properties))) 52 | .WithETag(PropertyValueParser.ParseString(FindProp("{DAV:}getetag", properties))) 53 | .WithLastModifiedDate(PropertyValueParser.ParseDateTime(FindProp("{DAV:}getlastmodified", properties))) 54 | .WithProperties(new ReadOnlyCollection(properties.Select(x => new WebDavProperty(x.Name, x.GetInnerXml())).ToList())) 55 | .WithPropertyStatuses(MultiStatusParser.GetPropertyStatuses(propstats)); 56 | 57 | var isHidden = PropertyValueParser.ParseInteger(FindProp("{DAV:}ishidden", properties)) > 0; 58 | if (isHidden) 59 | resourceBuilder.IsHidden(); 60 | 61 | var isCollection = PropertyValueParser.ParseInteger(FindProp("{DAV:}iscollection", properties)) > 0 || 62 | PropertyValueParser.ParseResourceType(FindProp("{DAV:}resourcetype", properties)) == ResourceType.Collection; 63 | if (isCollection) 64 | { 65 | resourceBuilder.IsCollection(); 66 | resourceBuilder.WithUri(uri.TrimEnd('/') + "/"); 67 | } 68 | else 69 | { 70 | resourceBuilder.WithUri(uri); 71 | } 72 | return resourceBuilder.Build(); 73 | } 74 | 75 | private static XElement FindProp(XName name, IEnumerable properties) 76 | { 77 | return properties.FirstOrDefault(x => x.Name.Equals(name)); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/ProppatchResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using JetBrains.Annotations; 3 | 4 | namespace WebDav 5 | { 6 | /// 7 | /// Represents a response of the PROPPATCH operation. 8 | /// 9 | public class ProppatchResponse : WebDavResponse 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The status code of the operation. 15 | public ProppatchResponse(int statusCode) 16 | : this(statusCode, null, new List()) 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The status code of the response. 24 | /// The collection of property statuses. 25 | public ProppatchResponse(int statusCode, IEnumerable propertyStatuses) 26 | : this(statusCode, null, propertyStatuses) 27 | { 28 | } 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// The status code of the response. 34 | /// The description of the response. 35 | public ProppatchResponse(int statusCode, string description) 36 | : this(statusCode, description, new List()) 37 | { 38 | } 39 | 40 | /// 41 | /// Initializes a new instance of the class. 42 | /// 43 | /// The status code of the response. 44 | /// The description of the response. 45 | /// The collection of property statuses. 46 | public ProppatchResponse(int statusCode, string description, [NotNull] IEnumerable propertyStatuses) 47 | : base(statusCode, description) 48 | { 49 | Check.NotNull(propertyStatuses, nameof(propertyStatuses)); 50 | PropertyStatuses = new List(propertyStatuses); 51 | } 52 | 53 | /// 54 | /// Gets the collection statuses of set/delete operation on the resource's properties. 55 | /// 56 | public IReadOnlyCollection PropertyStatuses { get; private set; } 57 | 58 | public override string ToString() 59 | { 60 | return string.Format("PROPPATCH WebDAV response - StatusCode: {0}, Description: {1}", StatusCode, Description); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/ProppatchResponseParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace WebDav.Response 5 | { 6 | internal class ProppatchResponseParser : IResponseParser 7 | { 8 | public ProppatchResponse Parse(string response, int statusCode, string description) 9 | { 10 | if (string.IsNullOrEmpty(response)) 11 | return new ProppatchResponse(statusCode, description); 12 | 13 | var xresponse = XDocumentExtensions.TryParse(response); 14 | if (xresponse == null || xresponse.Root == null) 15 | return new ProppatchResponse(statusCode, description); 16 | 17 | var propStatuses = xresponse.Root.LocalNameElements("response", StringComparison.OrdinalIgnoreCase) 18 | .SelectMany(MultiStatusParser.GetPropertyStatuses) 19 | .ToList(); 20 | return new ProppatchResponse(statusCode, description, propStatuses); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/ResourceType.cs: -------------------------------------------------------------------------------- 1 | namespace WebDav.Response 2 | { 3 | internal enum ResourceType 4 | { 5 | Collection, 6 | Other 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/WebDavResponse.cs: -------------------------------------------------------------------------------- 1 | namespace WebDav 2 | { 3 | /// 4 | /// Represents a response of a WebDAV operation. 5 | /// 6 | public class WebDavResponse 7 | { 8 | /// 9 | /// Initializes a new instance of the class. 10 | /// 11 | /// The status code of the operation. 12 | public WebDavResponse(int statusCode) 13 | { 14 | StatusCode = statusCode; 15 | } 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The status code of the response. 21 | /// The description of the response. 22 | public WebDavResponse(int statusCode, string description) 23 | { 24 | StatusCode = statusCode; 25 | Description = description; 26 | } 27 | 28 | /// 29 | /// Gets the status code of the response. 30 | /// 31 | public int StatusCode { get; private set; } 32 | 33 | /// 34 | /// Gets the description of the response. 35 | /// 36 | public string Description { get; private set; } 37 | 38 | /// 39 | /// Gets a value indicating whether the operation was successful. 40 | /// 41 | /// 42 | /// true if the operation was successful; otherwise, false. 43 | /// 44 | public virtual bool IsSuccessful => StatusCode >= 200 && StatusCode <= 299; 45 | 46 | public override string ToString() 47 | { 48 | return string.Format("WebDAV response - StatusCode: {0}, Description: {1}", StatusCode, Description); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/WebDAV-Client/Response/WebDavStreamResponse.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace WebDav 4 | { 5 | /// 6 | /// Represents a response of the GET operation. 7 | /// 8 | public class WebDavStreamResponse : WebDavResponse 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The status code of the operation. 14 | public WebDavStreamResponse(int statusCode) 15 | : this(statusCode, null, null) 16 | { 17 | } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// The status code of the response. 23 | /// The stream of resource's content. 24 | public WebDavStreamResponse(int statusCode, Stream stream) 25 | : this(statusCode, null, stream) 26 | { 27 | } 28 | 29 | /// 30 | /// Initializes a new instance of the class. 31 | /// 32 | /// The status code of the response. 33 | /// The description of the response. 34 | public WebDavStreamResponse(int statusCode, string description) 35 | : this(statusCode, description, null) 36 | { 37 | } 38 | 39 | /// 40 | /// Initializes a new instance of the class. 41 | /// 42 | /// The status code of the response. 43 | /// The description of the response. 44 | /// The stream of content of the resource. 45 | public WebDavStreamResponse(int statusCode, string description, Stream stream) 46 | : base(statusCode, description) 47 | { 48 | Stream = stream; 49 | } 50 | 51 | /// 52 | /// Gets the stream of content of the resource. 53 | /// 54 | public Stream Stream { get; private set; } 55 | 56 | public override string ToString() 57 | { 58 | return string.Format("WebDAV stream response - StatusCode: {0}, Description: {1}", StatusCode, Description); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/WebDAV-Client/System.ComponentModel/InvalidEnumArgumentException.cs: -------------------------------------------------------------------------------- 1 | #if NETSTANDARD1_1 || NETSTANDARD1_2 || PORTABLE 2 | // Copied from https://github.com/Microsoft/referencesource/blob/4fe4349175f4c5091d972a7e56ea12012f1e7170/System/compmod/system/componentmodel/InvalidEnumArgumentException.cs 3 | 4 | // ReSharper disable once CheckNamespace 5 | namespace System.ComponentModel 6 | { 7 | /// 8 | /// The exception that is thrown when using invalid arguments that are enumerators. 9 | /// 10 | public class InvalidEnumArgumentException : ArgumentException 11 | { 12 | /// 13 | /// Initializes a new instance of the class without a message. 14 | /// 15 | public InvalidEnumArgumentException() : this(null) 16 | { 17 | } 18 | 19 | /// 20 | /// Initializes a new instance of the class with 21 | /// the specified message. 22 | /// 23 | public InvalidEnumArgumentException(string message) 24 | : base(message) 25 | { 26 | } 27 | 28 | /// 29 | /// Initializes a new instance of the Exception class with a specified error message and a 30 | /// reference to the inner exception that is the cause of this exception. 31 | /// FxCop CA1032: Multiple constructors are required to correctly implement a custom exception. 32 | /// 33 | public InvalidEnumArgumentException(string message, Exception innerException) 34 | : base(message, innerException) 35 | { 36 | } 37 | 38 | /// 39 | /// Initializes a new instance of the class with a 40 | /// message generated from the argument, invalid value, and enumeration 41 | /// class. 42 | /// 43 | public InvalidEnumArgumentException(string argumentName, int invalidValue, Type enumClass) 44 | : base($"The value of argument '{argumentName}' ({invalidValue}) is invalid for Enum type '{enumClass.Name}'", argumentName) 45 | { 46 | } 47 | } 48 | } 49 | #endif -------------------------------------------------------------------------------- /src/WebDAV-Client/System/RuntimeUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace WebDav 5 | { 6 | internal static class RuntimeUtils 7 | { 8 | public static bool IsBlazorWASM => Type.GetType("Mono.Runtime") != null; 9 | } 10 | } -------------------------------------------------------------------------------- /src/WebDAV-Client/Validation/Check.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using JetBrains.Annotations; 9 | 10 | // Copied from https://github.com/aspnet/EntityFramework/blob/dev/src/Shared/Check.cs 11 | namespace WebDav 12 | { 13 | [DebuggerStepThrough] 14 | internal static class Check 15 | { 16 | [ContractAnnotation("value:null => halt")] 17 | public static T Condition([NoEnumeration] T value, [NotNull] Predicate condition, [InvokerParameterName] [NotNull] string parameterName) 18 | { 19 | NotNull(condition, nameof(condition)); 20 | NotNull(value, nameof(value)); 21 | 22 | if (!condition(value)) 23 | { 24 | NotEmpty(parameterName, nameof(parameterName)); 25 | 26 | throw new ArgumentOutOfRangeException(parameterName); 27 | } 28 | 29 | return value; 30 | } 31 | 32 | [ContractAnnotation("value:null => halt")] 33 | public static T NotNull([NoEnumeration] T value, [InvokerParameterName] [NotNull] string parameterName) 34 | { 35 | if (ReferenceEquals(value, null)) 36 | { 37 | NotEmpty(parameterName, nameof(parameterName)); 38 | 39 | throw new ArgumentNullException(parameterName); 40 | } 41 | 42 | return value; 43 | } 44 | 45 | [ContractAnnotation("value:null => halt")] 46 | public static T NotNull( 47 | [NoEnumeration] T value, 48 | [InvokerParameterName] [NotNull] string parameterName, 49 | [NotNull] string propertyName) 50 | { 51 | if (ReferenceEquals(value, null)) 52 | { 53 | NotEmpty(parameterName, nameof(parameterName)); 54 | NotEmpty(propertyName, nameof(propertyName)); 55 | 56 | throw new ArgumentException(CoreStrings.ArgumentPropertyNull(propertyName, parameterName)); 57 | } 58 | 59 | return value; 60 | } 61 | 62 | [ContractAnnotation("value:null => halt")] 63 | public static IList NotEmpty(IList value, [InvokerParameterName] [NotNull] string parameterName) 64 | { 65 | NotNull(value, parameterName); 66 | 67 | if (value.Count == 0) 68 | { 69 | NotEmpty(parameterName, nameof(parameterName)); 70 | 71 | throw new ArgumentException(CoreStrings.CollectionArgumentIsEmpty(parameterName)); 72 | } 73 | 74 | return value; 75 | } 76 | 77 | [ContractAnnotation("value:null => halt")] 78 | public static string NotEmpty(string value, [InvokerParameterName] [NotNull] string parameterName) 79 | { 80 | Exception e = null; 81 | if (ReferenceEquals(value, null)) 82 | { 83 | e = new ArgumentNullException(parameterName); 84 | } 85 | else if (value.Trim().Length == 0) 86 | { 87 | e = new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName)); 88 | } 89 | 90 | if (e != null) 91 | { 92 | NotEmpty(parameterName, nameof(parameterName)); 93 | 94 | throw e; 95 | } 96 | 97 | return value; 98 | } 99 | 100 | public static string NullButNotEmpty(string value, [InvokerParameterName] [NotNull] string parameterName) 101 | { 102 | if (!ReferenceEquals(value, null) 103 | && (value.Length == 0)) 104 | { 105 | NotEmpty(parameterName, nameof(parameterName)); 106 | 107 | throw new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName)); 108 | } 109 | 110 | return value; 111 | } 112 | 113 | public static IList HasNoNulls(IList value, [InvokerParameterName] [NotNull] string parameterName) 114 | where T : class 115 | { 116 | NotNull(value, parameterName); 117 | 118 | if (value.Any(e => e == null)) 119 | { 120 | NotEmpty(parameterName, nameof(parameterName)); 121 | 122 | throw new ArgumentException(parameterName); 123 | } 124 | 125 | return value; 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /src/WebDAV-Client/Validation/CoreStrings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using JetBrains.Annotations; 3 | 4 | // copied from https://github.com/aspnet/EntityFramework/blob/dev/src/Microsoft.EntityFrameworkCore/Properties/CoreStrings.resx 5 | namespace WebDav 6 | { 7 | internal static class CoreStrings 8 | { 9 | /// 10 | /// The property '{property}' of the argument '{argument}' cannot be null. 11 | /// 12 | public static string ArgumentPropertyNull([CanBeNull] string property, [CanBeNull] string argument) 13 | { 14 | return string.Format($"The property '{property}' of the argument '{argument}' cannot be null.", property, argument); 15 | } 16 | 17 | /// 18 | /// The string argument '{argumentName}' cannot be empty. 19 | /// 20 | public static string ArgumentIsEmpty([CanBeNull] string argumentName) 21 | { 22 | return string.Format($"The string argument '{argumentName}' cannot be empty.", argumentName); 23 | } 24 | 25 | /// 26 | /// The entity type '{type}' provided for the argument '{argumentName}' must be a reference type. 27 | /// 28 | public static string InvalidEntityType([CanBeNull] Type type, [CanBeNull] string argumentName) 29 | { 30 | return string.Format($"The entity type '{type}' provided for the argument '{argumentName}' must be a reference type.", type, argumentName); 31 | } 32 | 33 | /// 34 | /// The collection argument '{argumentName}' must contain at least one element. 35 | /// 36 | public static string CollectionArgumentIsEmpty([CanBeNull] string argumentName) 37 | { 38 | return string.Format($"The collection argument '{argumentName}' must contain at least one element.", argumentName); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/WebDAV-Client/WebDAV-Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | An easy-to-use async WebDAV client for .NET, .NETStandard, Blazor-WASM and Portable based on https://github.com/skazantsev/WebDavClient. 5 | WebDAV-Client 6 | WebDav 7 | 1.1.2.0 8 | Sergey Kazantsev;Stef Heyenrath 9 | net45;net46;netstandard1.1;netstandard1.2;netstandard2.0;netstandard2.1;net6.0;net7.0 10 | WebDAV-Client 11 | WebDAV-Client 12 | webdav;client;NETStandard;.NET;Portable;Blazor;WASM 13 | See CHANGELOG.md 14 | https://github.com/stefh/WebDAV-Client 15 | https://raw.githubusercontent.com/StefH/WebDAV-Client/master/LICENSE 16 | git 17 | https://github.com/stefh/WebDAV-Client 18 | true 19 | 20 | 21 | 22 | $(PackageTargetFallback);portable-net45+win8+wpa81;portable-net45+win8 23 | 24 | 25 | 26 | $(PackageTargetFallback);portable-net451+win81+wpa81;portable-win81+wpa81;portable-net451+win81 27 | 28 | 29 | 30 | 31 | All 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/Infrastructure/WebDavDispatcherTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NSubstitute; 3 | using System.Net.Http; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using WebDav.Infrastructure; 8 | using Xunit; 9 | 10 | namespace WebDav.Client.Tests.Infrastructure 11 | { 12 | public class WebDavDispatcherTests 13 | { 14 | [Fact] 15 | public async void When_RequestIsSent_Should_ReceiveResponseAndStatusCode200() 16 | { 17 | using (var dispatcher = new WebDavDispatcher(ConfigureHttpClient())) 18 | { 19 | var response = await dispatcher.Send(new Uri("http://example.com"), HttpMethod.Get, new RequestParameters(), CancellationToken.None); 20 | 21 | Assert.IsType(typeof(HttpResponse), response); 22 | Assert.Equal(200, response.StatusCode); 23 | } 24 | } 25 | 26 | [Fact] 27 | public async void When_ContentIsSent_Should_ReceiveResponseAndStatusCode200() 28 | { 29 | using (var dispatcher = new WebDavDispatcher(ConfigureHttpClient())) 30 | { 31 | var requestParams = new RequestParameters { Content = new StringContent("content", Encoding.UTF8, "application/xml") }; 32 | var response = await dispatcher.Send(new Uri("http://example.com"), HttpMethod.Put, requestParams, CancellationToken.None); 33 | 34 | Assert.IsType(typeof(HttpResponse), response); 35 | Assert.Equal(200, response.StatusCode); 36 | } 37 | } 38 | 39 | [Fact] 40 | public async void When_ResponseIsReceived_Should_ReadContent() 41 | { 42 | const string responseContent = "content"; 43 | using (var dispatcher = new WebDavDispatcher(ConfigureHttpClient(responseContent))) 44 | { 45 | var response = await dispatcher.Send(new Uri("http://example.com"), HttpMethod.Get, new RequestParameters(), CancellationToken.None); 46 | Assert.Equal(responseContent, await response.Content.ReadAsStringAsync()); 47 | } 48 | } 49 | 50 | [Fact] 51 | public async void When_CancellationIsRequested_Should_CancelRequest() 52 | { 53 | using (var dispatcher = new WebDavDispatcher(ConfigureHttpClient())) 54 | { 55 | var cts = new CancellationTokenSource(); 56 | cts.Cancel(); 57 | 58 | await Assert.ThrowsAsync( 59 | () => dispatcher.Send(new Uri("http://example.com"), HttpMethod.Get, new RequestParameters(), cts.Token)); 60 | } 61 | } 62 | 63 | [Fact] 64 | public async void When_DisposeIsCalled_Should_DisposeHttpClient() 65 | { 66 | var httpClient = ConfigureHttpClient(); 67 | using (var dispatcher = new WebDavDispatcher(httpClient)) 68 | { 69 | await dispatcher.Send(new Uri("http://example.com"), HttpMethod.Get, new RequestParameters(), CancellationToken.None); 70 | httpClient.DidNotReceive().Dispose(); 71 | } 72 | 73 | httpClient.Received().Dispose(); 74 | } 75 | 76 | private static HttpClient ConfigureHttpClient(string responseContent = "") 77 | { 78 | var httpClient = Substitute.For(); 79 | httpClient 80 | .SendAsync(Arg.Any(), Arg.Any()) 81 | .Returns(x => 82 | { 83 | x.Arg().ThrowIfCancellationRequested(); 84 | return Task.FromResult(new HttpResponseMessage { Content = new StringContent(responseContent, Encoding.UTF8, "application/xml") }); 85 | }); 86 | return httpClient; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WebDAV-Client.Tests.Net452")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WebDAV-Client.Tests.Net452")] 13 | [assembly: AssemblyCopyright("Copyright © Stef Heyenrath 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("df7de4b0-00dd-4b96-a6ef-7c7c83ce689d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/Response/LockResponseParserTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using WebDav.Response; 3 | using Xunit; 4 | 5 | namespace WebDav.Client.Tests.Response 6 | { 7 | public class LockResponseParserTests 8 | { 9 | [Fact] 10 | public void When_ResponseIsNull_Should_ReturnEmptyLocksCollection() 11 | { 12 | var parser = new LockResponseParser(); 13 | var response = parser.Parse(null, 207, "Multi-Status"); 14 | 15 | Assert.Equal(207, response.StatusCode); 16 | Assert.Equal("Multi-Status", response.Description); 17 | Assert.True(response.IsSuccessful); 18 | Assert.Empty(response.ActiveLocks); 19 | } 20 | 21 | [Fact] 22 | public void When_ResponseIsEmpty_Should_ReturnEmptyLocksCollection() 23 | { 24 | const string htmlresponse = ""; 25 | var parser = new LockResponseParser(); 26 | var response = parser.Parse(htmlresponse, 207, "Multi-Status"); 27 | 28 | Assert.Equal(207, response.StatusCode); 29 | Assert.Equal("Multi-Status", response.Description); 30 | Assert.True(response.IsSuccessful); 31 | Assert.Empty(response.ActiveLocks); 32 | } 33 | 34 | [Fact] 35 | public void When_NotValidXml_Should_ReturnEmptyLocksCollection() 36 | { 37 | const string htmlresponse = "(); 16 | dispatcher 17 | .Send(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) 18 | .Returns(x => Task.FromResult(new HttpResponse(new StringContent(content, Encoding.UTF8, "application/xml"), statusCode, description))); 19 | return dispatcher; 20 | } 21 | 22 | internal static IWebDavDispatcher MockFaulted() 23 | { 24 | var dispatcher = Substitute.For(); 25 | dispatcher 26 | .Send(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) 27 | .Returns(x => Task.FromResult(new HttpResponse(new StringContent(string.Empty), 500, "Internal Server Error"))); 28 | return dispatcher; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDAV-Client.Tests.Net452.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Debug 8 | AnyCPU 9 | {DF7DE4B0-00DD-4B96-A6EF-7C7C83CE689D} 10 | Library 11 | Properties 12 | WebDAV_Client.Tests.Net452 13 | WebDAV-Client.Tests.Net452 14 | v4.5.2 15 | 512 16 | 17 | 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\..\packages\NSubstitute.1.10.0.0\lib\net45\NSubstitute.dll 39 | True 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | ..\..\src\WebDAV-Client\bin\$(Configuration)\net45\WebDAV-Client.dll 49 | 50 | 51 | ..\..\packages\xunit.abstractions.2.0.2\lib\net35\xunit.abstractions.dll 52 | True 53 | 54 | 55 | ..\..\packages\xunit.assert.2.4.0\lib\netstandard1.1\xunit.assert.dll 56 | 57 | 58 | ..\..\packages\xunit.extensibility.core.2.4.0\lib\net452\xunit.core.dll 59 | 60 | 61 | ..\..\packages\xunit.extensibility.execution.2.4.0\lib\net452\xunit.execution.desktop.dll 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 97 | 98 | 99 | 100 | 101 | 102 | 103 | 110 | -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDavClientTests/CopyTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using System.Net.Http; 5 | using System.Threading; 6 | using NSubstitute; 7 | using WebDav.Client.Tests.TestDoubles; 8 | using Xunit; 9 | 10 | namespace WebDav.Client.Tests.WebDavClientTests 11 | { 12 | public class CopyTests 13 | { 14 | [Fact] 15 | public async void When_RequestIsSuccessfull_Should_ReturnStatusCode200() 16 | { 17 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.Mock()); 18 | var response1 = await client.Copy("http://example.com/old", "http://example.com/new"); 19 | var response2 = await client.Copy(new Uri("http://example.com/old"), new Uri("http://example.com/new")); 20 | var response3 = await client.Copy("http://example.com/old", "http://example.com/new", new CopyParameters()); 21 | var response4 = await client.Copy(new Uri("http://example.com/old"), new Uri("http://example.com/new"), new CopyParameters()); 22 | 23 | Assert.Equal(200, response1.StatusCode); 24 | Assert.Equal(200, response2.StatusCode); 25 | Assert.Equal(200, response3.StatusCode); 26 | Assert.Equal(200, response4.StatusCode); 27 | } 28 | 29 | [Fact] 30 | public async void When_RequestIsFailed_Should_ReturnStatusCode500() 31 | { 32 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.MockFaulted()); 33 | var response = await client.Copy("http://example.com/old", "http://example.com/new"); 34 | Assert.Equal(500, response.StatusCode); 35 | } 36 | 37 | [Fact] 38 | public async void When_IsCalled_Should_SendCopyRequest() 39 | { 40 | var sourceUri = new Uri("http://example.com/old"); 41 | var dispatcher = Dispatcher.Mock(); 42 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 43 | 44 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 45 | await client.Copy(sourceUri, new Uri("http://example.com/new")); 46 | await dispatcher.Received(1) 47 | .Send(sourceUri, WebDavMethod.Copy, Arg.Is(CheckCopyRequestParameters()), CancellationToken.None); 48 | } 49 | 50 | [Fact] 51 | public async void When_IsCalled_Should_SendDestinationHeader() 52 | { 53 | var sourceUri = new Uri("http://example.com/old"); 54 | var dispatcher = Dispatcher.Mock(); 55 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 56 | 57 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 58 | await client.Copy(sourceUri, new Uri("http://example.com/new")); 59 | await dispatcher.Received(1) 60 | .Send(sourceUri, WebDavMethod.Copy, Arg.Is(Predicates.CompareHeader("Destination", "http://example.com/new")), CancellationToken.None); 61 | } 62 | 63 | [Fact] 64 | public async void When_IsCalledWithDefaultParameters_Should_SendOverwriteHeaderEqualsT() 65 | { 66 | var sourceUri = new Uri("http://example.com/old"); 67 | var dispatcher = Dispatcher.Mock(); 68 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 69 | 70 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 71 | await client.Copy(sourceUri, new Uri("http://example.com/new")); 72 | await dispatcher.Received(1) 73 | .Send(sourceUri, WebDavMethod.Copy, Arg.Is(Predicates.CompareHeader("Overwrite", "T")), CancellationToken.None); 74 | } 75 | 76 | [Fact] 77 | public async void When_IsCalledWithDefaultParameters_Should_SendDepthHeaderEqualsInfinity() 78 | { 79 | var sourceUri = new Uri("http://example.com/old"); 80 | var dispatcher = Dispatcher.Mock(); 81 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 82 | 83 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 84 | await client.Copy(sourceUri, new Uri("http://example.com/new")); 85 | await dispatcher.Received(1) 86 | .Send(sourceUri, WebDavMethod.Copy, Arg.Is(Predicates.CompareHeader("Depth", "infinity")), CancellationToken.None); 87 | } 88 | 89 | [Fact] 90 | public async void When_IsCalledWithOverwriteOff_Should_SendOverwriteHeaderEqualsF() 91 | { 92 | var sourceUri = new Uri("http://example.com/old"); 93 | var dispatcher = Dispatcher.Mock(); 94 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 95 | 96 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 97 | await client.Copy(sourceUri, new Uri("http://example.com/new"), new CopyParameters { Overwrite = false }); 98 | await dispatcher.Received(1) 99 | .Send(sourceUri, WebDavMethod.Copy, Arg.Is(Predicates.CompareHeader("Overwrite", "F")), CancellationToken.None); 100 | } 101 | 102 | [Fact] 103 | public async void When_IsCalledWithOverwriteOn_Should_SendOverwriteHeaderEqualsT() 104 | { 105 | var sourceUri = new Uri("http://example.com/old"); 106 | var dispatcher = Dispatcher.Mock(); 107 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 108 | 109 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 110 | await client.Copy(sourceUri, new Uri("http://example.com/new"), new CopyParameters { Overwrite = true }); 111 | await dispatcher.Received(1) 112 | .Send(sourceUri, WebDavMethod.Copy, Arg.Is(Predicates.CompareHeader("Overwrite", "T")), CancellationToken.None); 113 | } 114 | 115 | [Fact] 116 | public async void When_IsCalledWithCancellationToken_Should_SendRequestWithIt() 117 | { 118 | var cts = new CancellationTokenSource(); 119 | var dispatcher = Dispatcher.Mock(); 120 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 121 | 122 | await client.Copy("http://example.com/old", "http://example.com/new", new CopyParameters { CancellationToken = cts.Token }); 123 | await dispatcher.Received(1) 124 | .Send(Arg.Any(), WebDavMethod.Copy, Arg.Is(CheckCopyRequestParameters()), cts.Token); 125 | } 126 | 127 | [Fact] 128 | public async void When_IsAppliedToResourceAndAncestors_Should_SendDepthHeaderEqualsInfinity() 129 | { 130 | var sourceUri = new Uri("http://example.com/old"); 131 | var dispatcher = Dispatcher.Mock(); 132 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 133 | 134 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 135 | await client.Copy(sourceUri, new Uri("http://example.com/new"), new CopyParameters { ApplyTo = ApplyTo.Copy.ResourceAndAncestors}); 136 | await dispatcher.Received(1) 137 | .Send(sourceUri, WebDavMethod.Copy, Arg.Is(Predicates.CompareHeader("Depth", "infinity")), CancellationToken.None); 138 | } 139 | 140 | [Fact] 141 | public async void When_IsAppliedToResourceOnly_Should_SendDepthHeaderEqualsZero() 142 | { 143 | var sourceUri = new Uri("http://example.com/old"); 144 | var dispatcher = Dispatcher.Mock(); 145 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 146 | 147 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 148 | await client.Copy(sourceUri, new Uri("http://example.com/new"), new CopyParameters { ApplyTo = ApplyTo.Copy.ResourceOnly }); 149 | await dispatcher.Received(1) 150 | .Send(sourceUri, WebDavMethod.Copy, Arg.Is(Predicates.CompareHeader("Depth", "0")), CancellationToken.None); 151 | } 152 | 153 | [Fact] 154 | public async void When_IsCalledWithLockToken_Should_SetIfHeader() 155 | { 156 | var sourceUri = new Uri("http://example.com/old"); 157 | var dispatcher = Dispatcher.Mock(); 158 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 159 | 160 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 161 | await client.Copy(sourceUri, new Uri("http://example.com/new"), new CopyParameters { DestLockToken = "urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4" }); 162 | await dispatcher.Received(1) 163 | .Send(sourceUri, WebDavMethod.Copy, Arg.Is(Predicates.CompareHeader("If", "()")), CancellationToken.None); 164 | } 165 | 166 | internal Expression> CheckCopyRequestParameters() 167 | { 168 | return x => 169 | x.Headers.Any(h => h.Key == "Destination") && 170 | x.Headers.Any(h => h.Key == "Depth") && 171 | x.Headers.Any(h => h.Key == "Overwrite") && 172 | x.Content == null; 173 | } 174 | } 175 | } -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDavClientTests/DeleteTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using NSubstitute; 6 | using WebDav.Client.Tests.TestDoubles; 7 | using Xunit; 8 | 9 | namespace WebDav.Client.Tests.WebDavClientTests 10 | { 11 | public class DeleteTests 12 | { 13 | [Fact] 14 | public async void When_RequestIsSuccessfull_Should_ReturnStatusCode200() 15 | { 16 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.Mock()); 17 | var response1 = await client.Delete("http://example.com/file"); 18 | var response2 = await client.Delete(new Uri("http://example.com/file")); 19 | var response3 = await client.Delete("http://example.com/file", new DeleteParameters()); 20 | var response4 = await client.Delete(new Uri("http://example.com/file"), new DeleteParameters()); 21 | 22 | Assert.Equal(200, response1.StatusCode); 23 | Assert.Equal(200, response2.StatusCode); 24 | Assert.Equal(200, response3.StatusCode); 25 | Assert.Equal(200, response4.StatusCode); 26 | } 27 | 28 | [Fact] 29 | public async void When_RequestIsFailed_Should_ReturnStatusCode500() 30 | { 31 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.MockFaulted()); 32 | var response = await client.Delete("http://example.com/file"); 33 | Assert.Equal(500, response.StatusCode); 34 | } 35 | 36 | [Fact] 37 | public async void When_IsCalledWithDefaultArguments_Should_SendDeleteRequest() 38 | { 39 | var requestUri = new Uri("http://example.com/file"); 40 | var dispatcher = Dispatcher.Mock(); 41 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 42 | 43 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 44 | await client.Delete(requestUri); 45 | await dispatcher.Received(1) 46 | .Send(requestUri, HttpMethod.Delete, Arg.Is(x => !x.Headers.Any() && x.Content == null), CancellationToken.None); 47 | } 48 | 49 | [Fact] 50 | public async void When_IsCalledWithCancellationToken_Should_SendRequestWithIt() 51 | { 52 | var cts = new CancellationTokenSource(); 53 | var dispatcher = Dispatcher.Mock(); 54 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 55 | 56 | await client.Delete("http://example.com/file", new DeleteParameters { CancellationToken = cts.Token }); 57 | await dispatcher.Received(1) 58 | .Send(Arg.Any(), HttpMethod.Delete, Arg.Is(x => !x.Headers.Any() && x.Content == null), cts.Token); 59 | } 60 | 61 | [Fact] 62 | public async void When_IsCalledWithLockToken_Should_SetIfHeader() 63 | { 64 | var requestUri = new Uri("http://example.com/file"); 65 | var dispatcher = Dispatcher.Mock(); 66 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 67 | 68 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 69 | await client.Delete(requestUri, new DeleteParameters { LockToken = "urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4" }); 70 | await dispatcher.Received(1) 71 | .Send(requestUri, HttpMethod.Delete, Arg.Is(Predicates.CompareHeader("If", "()")), CancellationToken.None); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDavClientTests/GetFileTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using NSubstitute; 6 | using WebDav.Client.Tests.TestDoubles; 7 | using Xunit; 8 | 9 | namespace WebDav.Client.Tests.WebDavClientTests 10 | { 11 | public class GetFileTests 12 | { 13 | [Fact] 14 | public async void When_GetRawFileIsCalled_Should_ProxyCallToGetFile() 15 | { 16 | var client = Substitute.ForPartsOf().SetWebDavDispatcher(Dispatcher.Mock()); 17 | client.GetFile(Arg.Any(), Arg.Any(), Arg.Any()).Returns(new WebDavStreamResponse(200)); 18 | 19 | await client.GetRawFile(new Uri("http://example.com/file")); 20 | await client.GetRawFile("http://example.com/file"); 21 | await client.GetRawFile(new Uri("http://example.com/file"), new GetFileParameters()); 22 | await client.GetRawFile("http://example.com/file", new GetFileParameters()); 23 | 24 | await client.Received(4).GetFile(Arg.Is(x => x.ToString() == "http://example.com/file"), false, CancellationToken.None); 25 | } 26 | 27 | [Fact] 28 | public async void When_GetProcessedFileIsCalled_Should_ProxyCallToGetFile() 29 | { 30 | var client = Substitute.ForPartsOf().SetWebDavDispatcher(Dispatcher.Mock()); 31 | client.GetFile(Arg.Any(), Arg.Any(), Arg.Any()).Returns(new WebDavStreamResponse(200)); 32 | 33 | await client.GetProcessedFile(new Uri("http://example.com/file")); 34 | await client.GetProcessedFile("http://example.com/file"); 35 | await client.GetProcessedFile(new Uri("http://example.com/file"), new GetFileParameters()); 36 | await client.GetProcessedFile("http://example.com/file", new GetFileParameters()); 37 | 38 | await client.Received(4).GetFile(Arg.Is(x => x.ToString() == "http://example.com/file"), true, CancellationToken.None); 39 | } 40 | 41 | [Fact] 42 | public async void When_RequestIsSuccessfull_Should_ReturnStatusCode200() 43 | { 44 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.Mock()); 45 | var response1 = await client.GetFile(new Uri("http://example.com/file"), false, CancellationToken.None); 46 | var response2 = await client.GetFile(new Uri("http://example.com/file"), true, CancellationToken.None); 47 | 48 | Assert.Equal(200, response1.StatusCode); 49 | Assert.Equal(200, response2.StatusCode); 50 | } 51 | 52 | [Fact] 53 | public async void When_RequestIsFailed_Should_ReturnStatusCode500() 54 | { 55 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.MockFaulted()); 56 | var response1 = await client.GetFile(new Uri("http://example.com/file"), false, CancellationToken.None); 57 | var response2 = await client.GetFile(new Uri("http://example.com/file"), true, CancellationToken.None); 58 | 59 | Assert.Equal(500, response1.StatusCode); 60 | Assert.Equal(500, response2.StatusCode); 61 | } 62 | 63 | [Fact] 64 | public async void When_GetFile_Should_SendGetRequest() 65 | { 66 | var requestUri = new Uri("http://example.com/file"); 67 | var dispatcher = Dispatcher.Mock(); 68 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 69 | 70 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 71 | await client.GetFile(requestUri, false, CancellationToken.None); 72 | await client.GetFile(requestUri, true, CancellationToken.None); 73 | await dispatcher.Received(2) 74 | .Send(requestUri, HttpMethod.Get, Arg.Is(x => x.Content == null), CancellationToken.None); 75 | } 76 | 77 | [Fact] 78 | public async void When_IsCalledWithTranslateOff_Should_SendTranslateHeaderEqualsF() 79 | { 80 | var requestUri = new Uri("http://example.com/file"); 81 | var dispatcher = Dispatcher.Mock(); 82 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 83 | 84 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 85 | await client.GetFile(requestUri, false, CancellationToken.None); 86 | await dispatcher.Received(1) 87 | .Send(requestUri, HttpMethod.Get, Arg.Is(Predicates.CompareHeader("Translate", "f")), CancellationToken.None); 88 | } 89 | 90 | [Fact] 91 | public async void When_IsCalledWithTranslateOn_Should_SendTranslateHeaderEqualsT() 92 | { 93 | var requestUri = new Uri("http://example.com/file"); 94 | var dispatcher = Dispatcher.Mock(); 95 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 96 | 97 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 98 | await client.GetFile(requestUri, true, CancellationToken.None); 99 | await dispatcher.Received(1) 100 | .Send(requestUri, HttpMethod.Get, Arg.Is(Predicates.CompareHeader("Translate", "t")), CancellationToken.None); 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDavClientTests/LockTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using NSubstitute; 7 | using WebDav.Client.Tests.TestDoubles; 8 | using Xunit; 9 | 10 | namespace WebDav.Client.Tests.WebDavClientTests 11 | { 12 | public class LockTests 13 | { 14 | [Fact] 15 | public async void When_RequestIsSuccessfull_Should_ReturnStatusCode200() 16 | { 17 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.Mock()); 18 | var response1 = await client.Lock("http://example.com/new"); 19 | var response2 = await client.Lock(new Uri("http://example.com/new")); 20 | var response3 = await client.Lock("http://example.com/new", new LockParameters()); 21 | var response4 = await client.Lock(new Uri("http://example.com/new"), new LockParameters()); 22 | 23 | Assert.Equal(200, response1.StatusCode); 24 | Assert.Equal(200, response2.StatusCode); 25 | Assert.Equal(200, response3.StatusCode); 26 | Assert.Equal(200, response4.StatusCode); 27 | } 28 | 29 | [Fact] 30 | public async void When_RequestIsFailed_Should_ReturnStatusCode500() 31 | { 32 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.MockFaulted()); 33 | var response = await client.Lock("http://example.com/new"); 34 | Assert.Equal(500, response.StatusCode); 35 | } 36 | 37 | [Fact] 38 | public async void When_IsCalled_Should_SendLockRequest() 39 | { 40 | var requestUri = new Uri("http://example.com/new"); 41 | var dispatcher = Dispatcher.Mock(); 42 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 43 | 44 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 45 | await client.Lock(requestUri); 46 | await dispatcher.Received(1) 47 | .Send(requestUri, WebDavMethod.Lock, Arg.Any(), CancellationToken.None); 48 | } 49 | 50 | [Fact] 51 | public async void When_IsCalledWithDefaultArguments_Should_SendNoHeaders() 52 | { 53 | var requestUri = new Uri("http://example.com/new"); 54 | var dispatcher = Dispatcher.Mock(); 55 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 56 | 57 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 58 | await client.Lock(requestUri); 59 | await dispatcher.Received(1) 60 | .Send(requestUri, WebDavMethod.Lock, Arg.Is(x => !x.Headers.Any()), CancellationToken.None); 61 | } 62 | 63 | [Fact] 64 | public async void When_IsCalledWithCancellationToken_Should_SendRequestWithIt() 65 | { 66 | var cts = new CancellationTokenSource(); 67 | var dispatcher = Dispatcher.Mock(); 68 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 69 | 70 | await client.Lock("http://example.com/new", new LockParameters { CancellationToken = cts.Token }); 71 | await dispatcher.Received(1) 72 | .Send(Arg.Any(), WebDavMethod.Lock, Arg.Any(), cts.Token); 73 | } 74 | 75 | [Fact] 76 | public async void When_IsAppliedToResourceAndAncestors_Should_SendDepthHeaderEqualsInfinity() 77 | { 78 | var dispatcher = Dispatcher.Mock(); 79 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 80 | 81 | await client.Lock("http://example.com", new LockParameters { ApplyTo = ApplyTo.Lock.ResourceAndAncestors }); 82 | await dispatcher.Received(1) 83 | .Send(Arg.Any(), WebDavMethod.Lock, Arg.Is(Predicates.CompareHeader("Depth", "infinity")), CancellationToken.None); 84 | } 85 | 86 | [Fact] 87 | public async void When_IsAppliedToResourceOnly_Should_SendDepthHeaderEqualsZero() 88 | { 89 | var dispatcher = Dispatcher.Mock(); 90 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 91 | 92 | await client.Lock("http://example.com", new LockParameters { ApplyTo = ApplyTo.Lock.ResourceOnly }); 93 | await dispatcher.Received(1) 94 | .Send(Arg.Any(), WebDavMethod.Lock, Arg.Is(Predicates.CompareHeader("Depth", "0")), CancellationToken.None); 95 | } 96 | 97 | [Fact] 98 | public async void When_IsCalledWithTimeout_Should_SendTimeoutHeaderInSeconds() 99 | { 100 | var dispatcher = Dispatcher.Mock(); 101 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 102 | 103 | await client.Lock("http://example.com", new LockParameters { Timeout = TimeSpan.FromMinutes(2) }); 104 | await dispatcher.Received(1) 105 | .Send(Arg.Any(), WebDavMethod.Lock, Arg.Is(Predicates.CompareHeader("Timeout", "Second-120")), CancellationToken.None); 106 | } 107 | 108 | [Fact] 109 | public async void When_IsCalledWithDefaultArguments_Should_SendLockInfo() 110 | { 111 | const string expectedContent = 112 | @" 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | "; 121 | var dispatcher = Dispatcher.Mock(); 122 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 123 | 124 | await client.Lock("http://example.com"); 125 | await dispatcher.Received(1) 126 | .Send(Arg.Any(), WebDavMethod.Lock, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 127 | } 128 | 129 | [Fact] 130 | public async void When_IsCalledWithLockScopeShared_Should_AddSharedLockScopeToContent() 131 | { 132 | const string expectedContent = 133 | @" 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | "; 142 | var dispatcher = Dispatcher.Mock(); 143 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 144 | 145 | await client.Lock("http://example.com", new LockParameters { LockScope = LockScope.Shared}); 146 | await dispatcher.Received(1) 147 | .Send(Arg.Any(), WebDavMethod.Lock, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 148 | } 149 | 150 | [Fact] 151 | public async Task When_IsCalledWithLockScopeExclusive_Should_AddExclusiveLockScopeToContent() 152 | { 153 | const string expectedContent = 154 | @" 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | "; 163 | var dispatcher = Dispatcher.Mock(); 164 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 165 | 166 | await client.Lock("http://example.com", new LockParameters { LockScope = LockScope.Exclusive }); 167 | await dispatcher.Received(1) 168 | .Send(Arg.Any(), WebDavMethod.Lock, Arg.Is(x => x.Content.ReadAsStringAsync().Result == expectedContent), CancellationToken.None); 169 | } 170 | 171 | [Fact] 172 | public async void When_IsCalledWithPrincipalLockOwner_Should_AddOwnerToContent() 173 | { 174 | const string expectedContent = 175 | @" 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | James Bond 184 | "; 185 | var dispatcher = Dispatcher.Mock(); 186 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 187 | 188 | await client.Lock("http://example.com", new LockParameters { Owner = new PrincipalLockOwner("James Bond") }); 189 | await dispatcher.Received(1) 190 | .Send(Arg.Any(), WebDavMethod.Lock, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 191 | } 192 | 193 | [Fact] 194 | public async void When_IsCalledWithUriLockOwner_Should_AddOwnerToContent() 195 | { 196 | const string expectedContent = 197 | @" 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | http://example.com/owner 207 | 208 | "; 209 | var dispatcher = Dispatcher.Mock(); 210 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 211 | 212 | await client.Lock("http://example.com", new LockParameters { Owner = new UriLockOwner("http://example.com/owner") }); 213 | await dispatcher.Received(1) 214 | .Send(Arg.Any(), WebDavMethod.Lock, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 215 | } 216 | } 217 | } -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDavClientTests/MkcolTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using NSubstitute; 6 | using WebDav.Client.Tests.TestDoubles; 7 | using Xunit; 8 | 9 | namespace WebDav.Client.Tests.WebDavClientTests 10 | { 11 | public class MkcolTests 12 | { 13 | [Fact] 14 | public async void When_RequestIsSuccessfull_Should_ReturnStatusCode200() 15 | { 16 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.Mock()); 17 | var response1 = await client.Mkcol("http://example.com/new"); 18 | var response2 = await client.Mkcol(new Uri("http://example.com/new")); 19 | var response3 = await client.Mkcol("http://example.com/new", new MkColParameters()); 20 | var response4 = await client.Mkcol(new Uri("http://example.com/new"), new MkColParameters()); 21 | 22 | Assert.Equal(200, response1.StatusCode); 23 | Assert.Equal(200, response2.StatusCode); 24 | Assert.Equal(200, response3.StatusCode); 25 | Assert.Equal(200, response4.StatusCode); 26 | } 27 | 28 | [Fact] 29 | public async void When_RequestIsFailed_Should_ReturnStatusCode500() 30 | { 31 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.MockFaulted()); 32 | var response = await client.Mkcol("http://example.com/new"); 33 | Assert.Equal(500, response.StatusCode); 34 | } 35 | 36 | [Fact] 37 | public async void When_IsCalledWithDefaultArguments_Should_SendMkcolRequest() 38 | { 39 | var requestUri = new Uri("http://example.com/new"); 40 | var dispatcher = Dispatcher.Mock(); 41 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 42 | 43 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 44 | await client.Mkcol(requestUri); 45 | await dispatcher.Received(1) 46 | .Send(requestUri, WebDavMethod.Mkcol, Arg.Is(x => !x.Headers.Any() && x.Content == null), CancellationToken.None); 47 | } 48 | 49 | [Fact] 50 | public async void When_IsCalledWithCancellationToken_Should_SendRequestWithIt() 51 | { 52 | var cts = new CancellationTokenSource(); 53 | var dispatcher = Dispatcher.Mock(); 54 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 55 | 56 | await client.Mkcol("http://example.com/new", new MkColParameters { CancellationToken = cts.Token }); 57 | await dispatcher.Received(1) 58 | .Send(Arg.Any(), WebDavMethod.Mkcol, Arg.Is(x => !x.Headers.Any() && x.Content == null), cts.Token); 59 | } 60 | 61 | [Fact] 62 | public async void When_IsCalledWithLockToken_Should_SetIfHeader() 63 | { 64 | var requestUri = new Uri("http://example.com/new"); 65 | var dispatcher = Dispatcher.Mock(); 66 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 67 | 68 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 69 | await client.Mkcol(requestUri, new MkColParameters { LockToken = "urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4" }); 70 | await dispatcher.Received(1) 71 | .Send(requestUri, WebDavMethod.Mkcol, Arg.Is(Predicates.CompareHeader("If", "()")), CancellationToken.None); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDavClientTests/MoveTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using System.Net.Http; 5 | using System.Threading; 6 | using NSubstitute; 7 | using WebDav.Client.Tests.TestDoubles; 8 | using Xunit; 9 | 10 | namespace WebDav.Client.Tests.WebDavClientTests 11 | { 12 | public class MoveTests 13 | { 14 | [Fact] 15 | public async void When_RequestIsSuccessfull_Should_ReturnStatusCode200() 16 | { 17 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.Mock()); 18 | var response1 = await client.Move("http://example.com/old", "http://example.com/new"); 19 | var response2 = await client.Move(new Uri("http://example.com/old"), new Uri("http://example.com/new")); 20 | var response3 = await client.Move("http://example.com/old", "http://example.com/new", new MoveParameters()); 21 | var response4 = await client.Move(new Uri("http://example.com/old"), new Uri("http://example.com/new"), new MoveParameters()); 22 | 23 | Assert.Equal(200, response1.StatusCode); 24 | Assert.Equal(200, response2.StatusCode); 25 | Assert.Equal(200, response3.StatusCode); 26 | Assert.Equal(200, response4.StatusCode); 27 | } 28 | 29 | [Fact] 30 | public async void When_RequestIsFailed_Should_ReturnStatusCode500() 31 | { 32 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.MockFaulted()); 33 | var response = await client.Move("http://example.com/old", "http://example.com/new"); 34 | Assert.Equal(500, response.StatusCode); 35 | } 36 | 37 | [Fact] 38 | public async void When_IsCalled_Should_SendMoveRequest() 39 | { 40 | var sourceUri = new Uri("http://example.com/old"); 41 | var dispatcher = Dispatcher.Mock(); 42 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 43 | 44 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 45 | await client.Move(sourceUri, new Uri("http://example.com/new")); 46 | await dispatcher.Received(1) 47 | .Send(sourceUri, WebDavMethod.Move, Arg.Is(CheckMoveRequestParameters()), CancellationToken.None); 48 | } 49 | 50 | [Fact] 51 | public async void When_IsCalled_Should_SendDestinationHeader() 52 | { 53 | var sourceUri = new Uri("http://example.com/old"); 54 | var dispatcher = Dispatcher.Mock(); 55 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 56 | 57 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 58 | await client.Move(sourceUri, new Uri("http://example.com/new")); 59 | await dispatcher.Received(1) 60 | .Send(sourceUri, WebDavMethod.Move, Arg.Is(Predicates.CompareHeader("Destination", "http://example.com/new")), CancellationToken.None); 61 | } 62 | 63 | [Fact] 64 | public async void When_IsCalledWithDefaultParameters_Should_SendOverwriteHeaderEqualsT() 65 | { 66 | var sourceUri = new Uri("http://example.com/old"); 67 | var dispatcher = Dispatcher.Mock(); 68 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 69 | 70 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 71 | await client.Move(sourceUri, new Uri("http://example.com/new")); 72 | await dispatcher.Received(1) 73 | .Send(sourceUri, WebDavMethod.Move, Arg.Is(Predicates.CompareHeader("Overwrite", "T")), CancellationToken.None); 74 | } 75 | 76 | [Fact] 77 | public async void When_IsCalledWithOverwriteOff_Should_SendOverwriteHeaderEqualsF() 78 | { 79 | var sourceUri = new Uri("http://example.com/old"); 80 | var dispatcher = Dispatcher.Mock(); 81 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 82 | 83 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 84 | await client.Move(sourceUri, new Uri("http://example.com/new"), new MoveParameters { Overwrite = false }); 85 | await dispatcher.Received(1) 86 | .Send(sourceUri, WebDavMethod.Move, Arg.Is(Predicates.CompareHeader("Overwrite", "F")), CancellationToken.None); 87 | } 88 | 89 | [Fact] 90 | public async void When_IsCalledWithOverwriteOn_Should_SendOverwriteHeaderEqualsT() 91 | { 92 | var sourceUri = new Uri("http://example.com/old"); 93 | var dispatcher = Dispatcher.Mock(); 94 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 95 | 96 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 97 | await client.Move(sourceUri, new Uri("http://example.com/new"), new MoveParameters { Overwrite = true }); 98 | await dispatcher.Received(1) 99 | .Send(sourceUri, WebDavMethod.Move, Arg.Is(Predicates.CompareHeader("Overwrite", "T")), CancellationToken.None); 100 | } 101 | 102 | [Fact] 103 | public async void When_IsCalledWithCancellationToken_Should_SendRequestWithIt() 104 | { 105 | var cts = new CancellationTokenSource(); 106 | var dispatcher = Dispatcher.Mock(); 107 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 108 | 109 | await client.Move("http://example.com/old", "http://example.com/new", new MoveParameters { CancellationToken = cts.Token }); 110 | await dispatcher.Received(1) 111 | .Send(Arg.Any(), WebDavMethod.Move, Arg.Is(CheckMoveRequestParameters()), cts.Token); 112 | } 113 | 114 | [Fact] 115 | public async void When_IsCalledWithDestLockToken_Should_SetIfHeader() 116 | { 117 | var sourceUri = new Uri("http://example.com/old"); 118 | var dispatcher = Dispatcher.Mock(); 119 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 120 | 121 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 122 | await client.Move(sourceUri, new Uri("http://example.com/new"), new MoveParameters { DestLockToken = "urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4" }); 123 | await dispatcher.Received(1) 124 | .Send(sourceUri, WebDavMethod.Move, Arg.Is(Predicates.CompareHeader("If", "()")), CancellationToken.None); 125 | } 126 | 127 | [Fact] 128 | public async void When_IsCalledWithSourceLockToken_Should_SetIfHeader() 129 | { 130 | var sourceUri = new Uri("http://example.com/old"); 131 | var dispatcher = Dispatcher.Mock(); 132 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 133 | 134 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 135 | await client.Move(sourceUri, new Uri("http://example.com/new"), new MoveParameters { SourceLockToken = "urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6" }); 136 | await dispatcher.Received(1) 137 | .Send(sourceUri, WebDavMethod.Move, Arg.Is(Predicates.CompareHeader("If", "()")), CancellationToken.None); 138 | } 139 | 140 | [Fact] 141 | public async void When_IsCalledWithBothLockTokens_Should_SetIfHeaderWithBothTokens() 142 | { 143 | var sourceUri = new Uri("http://example.com/old"); 144 | var dispatcher = Dispatcher.Mock(); 145 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 146 | 147 | await dispatcher.DidNotReceiveWithAnyArgs().Send(sourceUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 148 | await client.Move(sourceUri, new Uri("http://example.com/new"), 149 | new MoveParameters 150 | { 151 | SourceLockToken = "urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6", 152 | DestLockToken = "urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4" 153 | }); 154 | await dispatcher.Received(1) 155 | .Send(sourceUri, WebDavMethod.Move, Arg.Is(CheckIfHeader()), CancellationToken.None); 156 | } 157 | 158 | internal Expression> CheckIfHeader() 159 | { 160 | return x => x.Headers.Any(h => h.Key == "If" && h.Value == "()") && 161 | x.Headers.Any(h => h.Key == "If" && h.Value == "()"); 162 | } 163 | 164 | internal Expression> CheckMoveRequestParameters() 165 | { 166 | return x => 167 | x.Headers.Any(h => h.Key == "Destination") && 168 | x.Headers.Any(h => h.Key == "Overwrite") && 169 | x.Content == null; 170 | } 171 | } 172 | } -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDavClientTests/Predicates.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | 5 | namespace WebDav.Client.Tests.WebDavClientTests 6 | { 7 | internal static class Predicates 8 | { 9 | public static Expression> CompareHeader(string headerName, string headerValue) 10 | { 11 | return x => x.Headers.Any(h => h.Key == headerName && h.Value == headerValue); 12 | } 13 | 14 | public static Expression> CompareRequestContent(string expectedContent) 15 | { 16 | return x => expectedContent == x.Content.ReadAsStringAsync().Result; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDavClientTests/PropfindTests.cs: -------------------------------------------------------------------------------- 1 | using NSubstitute; 2 | using System; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using System.Xml.Linq; 7 | using WebDav.Client.Tests.TestDoubles; 8 | using WebDav.Response; 9 | using Xunit; 10 | 11 | namespace WebDav.Client.Tests.WebDavClientTests 12 | { 13 | public class PropfindTests 14 | { 15 | [Fact] 16 | public async void When_RequestIsSuccessfull_Should_ReturnStatusCode200() 17 | { 18 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.Mock()); 19 | var response1 = await client.Propfind("http://example.com"); 20 | var response2 = await client.Propfind(new Uri("http://example.com")); 21 | var response3 = await client.Propfind("http://example.com", new PropfindParameters()); 22 | var response4 = await client.Propfind(new Uri("http://example.com"), new PropfindParameters()); 23 | 24 | Assert.Equal(200, response1.StatusCode); 25 | Assert.Equal(200, response2.StatusCode); 26 | Assert.Equal(200, response3.StatusCode); 27 | Assert.Equal(200, response4.StatusCode); 28 | } 29 | 30 | [Fact] 31 | public async void When_RequestIsSuccessfull_Should_ParseResponse() 32 | { 33 | var dispatcher = Dispatcher.Mock("response", 207, "Multi-Status"); 34 | var propfindResponseParser = Substitute.For>(); 35 | var client = new WebDavClient() 36 | .SetWebDavDispatcher(dispatcher) 37 | .SetPropfindResponseParser(propfindResponseParser); 38 | 39 | propfindResponseParser.DidNotReceiveWithAnyArgs().Parse("", 0, ""); 40 | await client.Propfind("http://example"); 41 | propfindResponseParser.Received(1).Parse("response", 207, "Multi-Status"); 42 | } 43 | 44 | [Fact] 45 | public async void When_RequestIsFailed_Should_ReturnStatusCode500() 46 | { 47 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.MockFaulted()); 48 | var response = await client.Propfind("http://example.com"); 49 | Assert.Equal(500, response.StatusCode); 50 | } 51 | 52 | [Fact] 53 | public async void When_IsCalledWithDefaultArguments_Should_SendPropfindRequest() 54 | { 55 | var requestUri = new Uri("http://example.com"); 56 | var dispatcher = Dispatcher.Mock(); 57 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 58 | 59 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 60 | await client.Propfind(requestUri); 61 | await dispatcher.Received(1) 62 | .Send(requestUri, WebDavMethod.Propfind, Arg.Is(Predicates.CompareHeader("Depth", "1")), CancellationToken.None); 63 | } 64 | 65 | [Fact] 66 | public async void When_IsAppliedToResourceAndAncestors_Should_SendDepthHeaderEqualsInfinity() 67 | { 68 | var dispatcher = Dispatcher.Mock(); 69 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 70 | 71 | await client.Propfind("http://example.com", new PropfindParameters { ApplyTo = ApplyTo.Propfind.ResourceAndAncestors }); 72 | await dispatcher.Received(1) 73 | .Send(Arg.Any(), WebDavMethod.Propfind, Arg.Is(Predicates.CompareHeader("Depth", "infinity")), CancellationToken.None); 74 | } 75 | 76 | [Fact] 77 | public async void When_IsAppliedToResourceAndChildren_Should_SendDepthHeaderEqualsOne() 78 | { 79 | var dispatcher = Dispatcher.Mock(); 80 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 81 | 82 | await client.Propfind("http://example.com", new PropfindParameters { ApplyTo = ApplyTo.Propfind.ResourceAndChildren }); 83 | await dispatcher.Received(1) 84 | .Send(Arg.Any(), WebDavMethod.Propfind, Arg.Is(Predicates.CompareHeader("Depth", "1")), CancellationToken.None); 85 | } 86 | 87 | [Fact] 88 | public async void When_IsAppliedToResourceOnly_Should_SendDepthHeaderEqualsZero() 89 | { 90 | var dispatcher = Dispatcher.Mock(); 91 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 92 | 93 | await client.Propfind("http://example.com", new PropfindParameters { ApplyTo = ApplyTo.Propfind.ResourceOnly }); 94 | await dispatcher.Received(1) 95 | .Send(Arg.Any(), WebDavMethod.Propfind, Arg.Is(Predicates.CompareHeader("Depth", "0")), CancellationToken.None); 96 | } 97 | 98 | [Fact] 99 | public async void When_IsCalledWithCancellationToken_Should_SendRequestWithIt() 100 | { 101 | var cts = new CancellationTokenSource(); 102 | var dispatcher = Dispatcher.Mock(); 103 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 104 | 105 | await client.Propfind("http://example.com", new PropfindParameters { CancellationToken = cts.Token }); 106 | await dispatcher.Received(1) 107 | .Send(Arg.Any(), WebDavMethod.Propfind, Arg.Is(Predicates.CompareHeader("Depth", "1")), cts.Token); 108 | } 109 | 110 | [Fact] 111 | public async void When_IsCalledWithDefaultArguments_Should_SendAllPropRequest() 112 | { 113 | const string expectedContent = 114 | @" 115 | 116 | 117 | "; 118 | var dispatcher = Dispatcher.Mock(); 119 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 120 | 121 | await client.Propfind("http://example.com"); 122 | await dispatcher.Received(1) 123 | .Send(Arg.Any(), WebDavMethod.Propfind, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 124 | } 125 | 126 | [Fact] 127 | public async void When_IsCalledWithCustomProperties_Should_IncludeThemInRequest() 128 | { 129 | const string expectedContent = 130 | @" 131 | 132 | 133 | 134 | 135 | 136 | 137 | "; 138 | var dispatcher = Dispatcher.Mock(); 139 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 140 | 141 | await client.Propfind("http://example.com", 142 | new PropfindParameters 143 | { 144 | CustomProperties = new XName[] { "myprop1", "myprop2" } 145 | }); 146 | await dispatcher.Received(1) 147 | .Send(Arg.Any(), WebDavMethod.Propfind, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 148 | } 149 | 150 | [Fact] 151 | public async void When_CustomPropertiesHaveNamespaces_Should_IncludeThemInRequest() 152 | { 153 | const string expectedContent = 154 | @" 155 | 156 | 157 | 158 | 159 | 160 | 161 | "; 162 | var dispatcher = Dispatcher.Mock(); 163 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 164 | 165 | await client.Propfind("http://example.com", 166 | new PropfindParameters 167 | { 168 | CustomProperties = new XName[] { "{http://ns1.example.com}myprop1", "{http://ns2.example.com}myprop2" } 169 | }); 170 | await dispatcher.Received(1) 171 | .Send(Arg.Any(), WebDavMethod.Propfind, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 172 | } 173 | 174 | [Fact] 175 | public async void When_IsCalledWithDefaultNamespace_Should_IncludeItInRequest() 176 | { 177 | const string expectedContent = 178 | @" 179 | 180 | 181 | 182 | 183 | 184 | 185 | "; 186 | var dispatcher = Dispatcher.Mock(); 187 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 188 | 189 | await client.Propfind("http://example.com", 190 | new PropfindParameters 191 | { 192 | CustomProperties = new XName[] { "{http://ns.example.com}myprop1", "{http://ns.example.com}myprop2" }, 193 | Namespaces = new[] { new NamespaceAttr("http://ns.example.com") } 194 | }); 195 | await dispatcher.Received(1) 196 | .Send(Arg.Any(), WebDavMethod.Propfind, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 197 | } 198 | 199 | [Fact] 200 | public async void When_IsCalledWithMoreThanOneDefaultNamespace_Should_UseTheLastOne() 201 | { 202 | const string expectedContent = 203 | @" 204 | 205 | 206 | 207 | 208 | 209 | "; 210 | var dispatcher = Dispatcher.Mock(); 211 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 212 | 213 | await client.Propfind("http://example.com", 214 | new PropfindParameters 215 | { 216 | CustomProperties = new XName[] { "{http://ns2.example.com}myprop" }, 217 | Namespaces = new[] { new NamespaceAttr("http://ns1.example.com"), new NamespaceAttr("http://ns2.example.com") } 218 | }); 219 | await dispatcher.Received(1) 220 | .Send(Arg.Any(), WebDavMethod.Propfind, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 221 | } 222 | 223 | [Fact] 224 | public async Task When_IsCalledWithPrefixedNamespaces_Should_IncludeThemInRequest() 225 | { 226 | const string expectedContent = 227 | @" 228 | 229 | 230 | 231 | 232 | 233 | 234 | "; 235 | var dispatcher = Dispatcher.Mock(); 236 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 237 | 238 | await client.Propfind("http://example.com", 239 | new PropfindParameters 240 | { 241 | CustomProperties = new XName[] { "{http://p1.example.com}myprop1", "{http://p2.example.com}myprop2" }, 242 | Namespaces = new[] { new NamespaceAttr("P1", "http://p1.example.com"), new NamespaceAttr("P2", "http://p2.example.com") } 243 | }); 244 | await dispatcher.Received(1) 245 | .Send(Arg.Any(), WebDavMethod.Propfind, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 246 | } 247 | } 248 | } -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDavClientTests/ProppatchTests.cs: -------------------------------------------------------------------------------- 1 | using NSubstitute; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net.Http; 6 | using System.Threading; 7 | using System.Xml.Linq; 8 | using WebDav.Client.Tests.TestDoubles; 9 | using WebDav.Response; 10 | using Xunit; 11 | 12 | namespace WebDav.Client.Tests.WebDavClientTests 13 | { 14 | public class ProppatchTests 15 | { 16 | [Fact] 17 | public async void When_RequestIsSuccessfull_Should_ReturnStatusCode200() 18 | { 19 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.Mock()); 20 | var response1 = await client.Proppatch("http://example.com", new ProppatchParameters()); 21 | var response2 = await client.Proppatch(new Uri("http://example.com"), new ProppatchParameters()); 22 | 23 | Assert.Equal(200, response1.StatusCode); 24 | Assert.Equal(200, response2.StatusCode); 25 | } 26 | 27 | [Fact] 28 | public async void When_RequestIsSuccessfull_Should_ParseResponse() 29 | { 30 | var dispatcher = Dispatcher.Mock("response", 207, "Multi-Status"); 31 | var proppatchResponseParser = Substitute.For>(); 32 | var client = new WebDavClient() 33 | .SetWebDavDispatcher(dispatcher) 34 | .SetProppatchResponseParser(proppatchResponseParser); 35 | 36 | proppatchResponseParser.DidNotReceiveWithAnyArgs().Parse("", 0, ""); 37 | await client.Proppatch("http://example", new ProppatchParameters()); 38 | proppatchResponseParser.Received(1).Parse("response", 207, "Multi-Status"); 39 | } 40 | 41 | [Fact] 42 | public async void When_RequestIsFailed_Should_ReturnStatusCode500() 43 | { 44 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.MockFaulted()); 45 | var response = await client.Proppatch("http://example", new ProppatchParameters()); 46 | Assert.Equal(500, response.StatusCode); 47 | } 48 | 49 | [Fact] 50 | public async void When_IsCalledWithDefaultArguments_Should_SendProppatchRequest() 51 | { 52 | var requestUri = new Uri("http://example.com"); 53 | var dispatcher = Dispatcher.Mock(); 54 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 55 | 56 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 57 | await client.Proppatch(requestUri, new ProppatchParameters()); 58 | await dispatcher.Received(1) 59 | .Send(requestUri, WebDavMethod.Proppatch, Arg.Is(x => !x.Headers.Any()), CancellationToken.None); 60 | } 61 | 62 | [Fact] 63 | public async void When_IsCalledWithCancellationToken_Should_SendRequestWithIt() 64 | { 65 | var cts = new CancellationTokenSource(); 66 | var dispatcher = Dispatcher.Mock(); 67 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 68 | 69 | await client.Proppatch("http://example.com", new ProppatchParameters { CancellationToken = cts.Token }); 70 | await dispatcher.Received(1) 71 | .Send(Arg.Any(), WebDavMethod.Proppatch, Arg.Is(x => !x.Headers.Any()), cts.Token); 72 | } 73 | 74 | [Fact] 75 | public async void When_IsCalledWithDefaultArguments_Should_SendPropertyUpdateRequest() 76 | { 77 | const string expectedContent = 78 | @" 79 | "; 80 | var dispatcher = Dispatcher.Mock(); 81 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 82 | 83 | await client.Proppatch("http://example.com", new ProppatchParameters()); 84 | await dispatcher.Received(1) 85 | .Send(Arg.Any(), WebDavMethod.Proppatch, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 86 | } 87 | 88 | [Fact] 89 | public async void When_SetProperties_Should_IncludeThemInSetTag() 90 | { 91 | const string expectedContent = 92 | @" 93 | 94 | 95 | 96 | value1 97 | 98 | 99 | value2 100 | 101 | 102 | "; 103 | var dispatcher = Dispatcher.Mock(); 104 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 105 | 106 | var propertiesToSet = new Dictionary 107 | { 108 | {"prop1", "value1"}, 109 | {"prop2", "value2"} 110 | }; 111 | await client.Proppatch("http://example.com", new ProppatchParameters { PropertiesToSet = propertiesToSet }); 112 | await dispatcher.Received(1) 113 | .Send(Arg.Any(), WebDavMethod.Proppatch, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 114 | } 115 | 116 | [Fact] 117 | public async void When_SetPropertiesWithNamespaces_Should_IncludeXmlnsTagAndUsePrefixes() 118 | { 119 | const string expectedContent = 120 | @" 121 | 122 | 123 | 124 | value1 125 | 126 | 127 | value2 128 | 129 | 130 | "; 131 | var dispatcher = Dispatcher.Mock(); 132 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 133 | 134 | var propertiesToSet = new Dictionary 135 | { 136 | {"{http://x.example.com/}prop1", "value1"}, 137 | {"{http://y.example.com/}prop2", "value2"} 138 | }; 139 | var ns = new[] 140 | { 141 | new NamespaceAttr("X", "http://x.example.com/"), 142 | new NamespaceAttr("http://y.example.com/") 143 | }; 144 | await client.Proppatch("http://example.com", new ProppatchParameters { PropertiesToSet = propertiesToSet, Namespaces = ns}); 145 | await dispatcher.Received(1) 146 | .Send(Arg.Any(), WebDavMethod.Proppatch, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 147 | } 148 | 149 | [Fact] 150 | public async void When_RemoveProperties_Should_IncludeThemInRemoveTag() 151 | { 152 | const string expectedContent = 153 | @" 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | "; 164 | var dispatcher = Dispatcher.Mock(); 165 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 166 | 167 | await client.Proppatch("http://example.com", new ProppatchParameters { PropertiesToRemove = new XName[] { "prop1", "prop2" } }); 168 | await dispatcher.Received(1) 169 | .Send(Arg.Any(), WebDavMethod.Proppatch, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 170 | } 171 | 172 | [Fact] 173 | public async void When_RemovePropertiesWithNamespaces_Should_IncludeXmlnsTagAndUsePrefixes() 174 | { 175 | const string expectedContent = 176 | @" 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | "; 187 | var dispatcher = Dispatcher.Mock(); 188 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 189 | 190 | var propertiesToRemove = new XName[] 191 | { 192 | "{http://x.example.com/}prop1", 193 | "{http://y.example.com/}prop2" 194 | }; 195 | var ns = new[] 196 | { 197 | new NamespaceAttr("X", "http://x.example.com/"), 198 | new NamespaceAttr("http://y.example.com/") 199 | }; 200 | await client.Proppatch("http://example.com", new ProppatchParameters { PropertiesToRemove = propertiesToRemove, Namespaces = ns}); 201 | await dispatcher.Received(1) 202 | .Send(Arg.Any(), WebDavMethod.Proppatch, Arg.Is(Predicates.CompareRequestContent(expectedContent)), CancellationToken.None); 203 | } 204 | } 205 | } -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDavClientTests/PutFileTests.cs: -------------------------------------------------------------------------------- 1 | using NSubstitute; 2 | using System; 3 | using System.IO; 4 | using System.Net.Http; 5 | using System.Text; 6 | using System.Threading; 7 | using WebDav.Client.Tests.TestDoubles; 8 | using Xunit; 9 | 10 | namespace WebDav.Client.Tests.WebDavClientTests 11 | { 12 | public class PutFileTests 13 | { 14 | [Fact] 15 | public async void When_RequestIsSuccessfull_Should_ReturnStatusCode200() 16 | { 17 | var stream = new MemoryStream(Encoding.UTF8.GetBytes("")); 18 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.Mock()); 19 | 20 | var response1 = await client.PutFile("http://example.com/file", stream); 21 | var response2 = await client.PutFile(new Uri("http://example.com/file"), stream); 22 | var response3 = await client.PutFile("http://example.com/file", stream, "text/xml"); 23 | var response4 = await client.PutFile(new Uri("http://example.com/file"), stream, "text/xml"); 24 | var response5 = await client.PutFile(new Uri("http://example.com/file"), stream, new PutFileParameters()); 25 | var response6 = await client.PutFile(new Uri("http://example.com/file"), stream, new PutFileParameters()); 26 | 27 | Assert.Equal(200, response1.StatusCode); 28 | Assert.Equal(200, response2.StatusCode); 29 | Assert.Equal(200, response3.StatusCode); 30 | Assert.Equal(200, response4.StatusCode); 31 | Assert.Equal(200, response5.StatusCode); 32 | Assert.Equal(200, response6.StatusCode); 33 | } 34 | 35 | [Fact] 36 | public async void When_RequestIsFailed_Should_ReturnStatusCode500() 37 | { 38 | var stream = new MemoryStream(Encoding.UTF8.GetBytes("")); 39 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.MockFaulted()); 40 | var response = await client.PutFile("http://example.com/file", stream); 41 | Assert.Equal(500, response.StatusCode); 42 | } 43 | 44 | [Fact] 45 | public async void When_IsCalled_Should_SendPutRequestWithContent() 46 | { 47 | var stream = new MemoryStream(Encoding.UTF8.GetBytes("")); 48 | var requestUri = new Uri("http://example.com/file"); 49 | var dispatcher = Dispatcher.Mock(); 50 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 51 | 52 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 53 | await client.PutFile(requestUri, stream); 54 | await dispatcher.Received(1) 55 | .Send(requestUri, HttpMethod.Put, Arg.Is(Predicates.CompareRequestContent("")), CancellationToken.None); 56 | } 57 | 58 | [Fact] 59 | public async void When_IsCalledWithCancellationToken_Should_SendRequestWithIt() 60 | { 61 | var stream = new MemoryStream(Encoding.UTF8.GetBytes("")); 62 | var cts = new CancellationTokenSource(); 63 | var dispatcher = Dispatcher.Mock(); 64 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 65 | 66 | await client.PutFile("http://example.com/file", stream, new PutFileParameters { CancellationToken = cts.Token }); 67 | await dispatcher.Received(1) 68 | .Send(Arg.Any(), HttpMethod.Put, Arg.Is(Predicates.CompareRequestContent("")), cts.Token); 69 | } 70 | 71 | [Fact] 72 | public async void When_IsCalledWithLockToken_Should_SetIfHeader() 73 | { 74 | var stream = new MemoryStream(Encoding.UTF8.GetBytes("")); 75 | var requestUri = new Uri("http://example.com/file"); 76 | var dispatcher = Dispatcher.Mock(); 77 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 78 | 79 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 80 | await client.PutFile(requestUri, stream, new PutFileParameters { LockToken = "urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4" }); 81 | await dispatcher.Received(1) 82 | .Send(requestUri, HttpMethod.Put, Arg.Is(Predicates.CompareHeader("If", "()")), CancellationToken.None); 83 | } 84 | 85 | [Fact] 86 | public async void When_IsCalledWithContentType_Should_SetPassItToDispatcher() 87 | { 88 | var stream = new MemoryStream(Encoding.UTF8.GetBytes("")); 89 | var requestUri = new Uri("http://example.com/file"); 90 | var dispatcher = Dispatcher.Mock(); 91 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 92 | 93 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 94 | await client.PutFile(requestUri, stream, new PutFileParameters { ContentType = "text/xml" }); 95 | await dispatcher.Received(1) 96 | .Send(requestUri, HttpMethod.Put, Arg.Is(x => x.ContentType == "text/xml"), CancellationToken.None); 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/WebDavClientTests/UnlockTests.cs: -------------------------------------------------------------------------------- 1 | using NSubstitute; 2 | using System; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using WebDav.Client.Tests.TestDoubles; 6 | using Xunit; 7 | 8 | namespace WebDav.Client.Tests.WebDavClientTests 9 | { 10 | public class UnlockTests 11 | { 12 | [Fact] 13 | public async void When_RequestIsSuccessfull_Should_ReturnStatusCode200() 14 | { 15 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.Mock()); 16 | var response1 = await client.Unlock("http://example.com/file", "lock-token"); 17 | var response2 = await client.Unlock(new Uri("http://example.com/file"), "lock-token"); 18 | var response3 = await client.Unlock("http://example.com/file", new UnlockParameters("lock-token")); 19 | var response4 = await client.Unlock(new Uri("http://example.com/file"), new UnlockParameters("lock-token")); 20 | 21 | Assert.Equal(200, response1.StatusCode); 22 | Assert.Equal(200, response2.StatusCode); 23 | Assert.Equal(200, response3.StatusCode); 24 | Assert.Equal(200, response4.StatusCode); 25 | } 26 | 27 | [Fact] 28 | public async void When_RequestIsFailed_Should_ReturnStatusCode500() 29 | { 30 | var client = new WebDavClient().SetWebDavDispatcher(Dispatcher.MockFaulted()); 31 | var response = await client.Unlock("http://example.com/file", "lock-token"); 32 | Assert.Equal(500, response.StatusCode); 33 | } 34 | 35 | [Fact] 36 | public async void When_IsCalledWithDefaultArguments_Should_SendUnlockRequest() 37 | { 38 | var requestUri = new Uri("http://example.com/file"); 39 | var dispatcher = Dispatcher.Mock(); 40 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 41 | 42 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 43 | await client.Unlock(requestUri, "lock-token"); 44 | await dispatcher.Received(1) 45 | .Send(requestUri, WebDavMethod.Unlock, Arg.Is(x => x.Content == null), CancellationToken.None); 46 | } 47 | 48 | [Fact] 49 | public async void When_IsCalledWithCancellationToken_Should_SendRequestWithIt() 50 | { 51 | var cts = new CancellationTokenSource(); 52 | var dispatcher = Dispatcher.Mock(); 53 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 54 | 55 | await client.Unlock("http://example.com/file", new UnlockParameters("lock-token") { CancellationToken = cts.Token }); 56 | await dispatcher.Received(1) 57 | .Send(Arg.Any(), WebDavMethod.Unlock, Arg.Is(x => x.Content == null), cts.Token); 58 | } 59 | 60 | [Fact] 61 | public async void When_IsCalledWithLockToken_Should_SendLockTokenHeader() 62 | { 63 | var requestUri = new Uri("http://example.com/file"); 64 | var dispatcher = Dispatcher.Mock(); 65 | var client = new WebDavClient().SetWebDavDispatcher(dispatcher); 66 | 67 | await dispatcher.DidNotReceiveWithAnyArgs().Send(requestUri, Arg.Any(), new RequestParameters(), CancellationToken.None); 68 | 69 | await client.Unlock(requestUri, "urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4"); 70 | await client.Unlock(requestUri, new UnlockParameters("urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6")); 71 | 72 | await dispatcher.Received(1) 73 | .Send(requestUri, WebDavMethod.Unlock, Arg.Is(Predicates.CompareHeader("Lock-Token", "")), CancellationToken.None); 74 | 75 | await dispatcher.Received(1) 76 | .Send(requestUri, WebDavMethod.Unlock, Arg.Is(Predicates.CompareHeader("Lock-Token", "")), CancellationToken.None); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests.Net452/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/WebDAV-Client.Tests/WebDAV-Client.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Stef Heyenrath 5 | net452;netcoreapp1.1;netcoreapp2.1;net6.0;net7.0 6 | WebDAV-Client.Tests 7 | WebDAV-Client.Tests 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | all 27 | runtime; build; native; contentfiles; analyzers 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | --------------------------------------------------------------------------------