Statistics
| Branch: | Revision:

root / trunk / Pithos.Network / CloudFilesClient.cs @ c945b450

History | View | Annotate | Download (61.1 kB)

1 255f5f86 Panagiotis Kanavos
#region
2 255f5f86 Panagiotis Kanavos
/* -----------------------------------------------------------------------
3 255f5f86 Panagiotis Kanavos
 * <copyright file="CloudFilesClient.cs" company="GRNet">
4 255f5f86 Panagiotis Kanavos
 * 
5 255f5f86 Panagiotis Kanavos
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6 255f5f86 Panagiotis Kanavos
 *
7 255f5f86 Panagiotis Kanavos
 * Redistribution and use in source and binary forms, with or
8 255f5f86 Panagiotis Kanavos
 * without modification, are permitted provided that the following
9 255f5f86 Panagiotis Kanavos
 * conditions are met:
10 255f5f86 Panagiotis Kanavos
 *
11 255f5f86 Panagiotis Kanavos
 *   1. Redistributions of source code must retain the above
12 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
13 255f5f86 Panagiotis Kanavos
 *      disclaimer.
14 255f5f86 Panagiotis Kanavos
 *
15 255f5f86 Panagiotis Kanavos
 *   2. Redistributions in binary form must reproduce the above
16 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
17 255f5f86 Panagiotis Kanavos
 *      disclaimer in the documentation and/or other materials
18 255f5f86 Panagiotis Kanavos
 *      provided with the distribution.
19 255f5f86 Panagiotis Kanavos
 *
20 255f5f86 Panagiotis Kanavos
 *
21 255f5f86 Panagiotis Kanavos
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 255f5f86 Panagiotis Kanavos
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 255f5f86 Panagiotis Kanavos
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 255f5f86 Panagiotis Kanavos
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 255f5f86 Panagiotis Kanavos
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 255f5f86 Panagiotis Kanavos
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 255f5f86 Panagiotis Kanavos
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 255f5f86 Panagiotis Kanavos
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 255f5f86 Panagiotis Kanavos
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 255f5f86 Panagiotis Kanavos
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 255f5f86 Panagiotis Kanavos
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 255f5f86 Panagiotis Kanavos
 * POSSIBILITY OF SUCH DAMAGE.
33 255f5f86 Panagiotis Kanavos
 *
34 255f5f86 Panagiotis Kanavos
 * The views and conclusions contained in the software and
35 255f5f86 Panagiotis Kanavos
 * documentation are those of the authors and should not be
36 255f5f86 Panagiotis Kanavos
 * interpreted as representing official policies, either expressed
37 255f5f86 Panagiotis Kanavos
 * or implied, of GRNET S.A.
38 255f5f86 Panagiotis Kanavos
 * </copyright>
39 255f5f86 Panagiotis Kanavos
 * -----------------------------------------------------------------------
40 255f5f86 Panagiotis Kanavos
 */
41 255f5f86 Panagiotis Kanavos
#endregion
42 f3d080df Panagiotis Kanavos
43 f3d080df Panagiotis Kanavos
// **CloudFilesClient** provides a simple client interface to CloudFiles and Pithos
44 5ce54458 Panagiotis Kanavos
//
45 5ce54458 Panagiotis Kanavos
// The class provides methods to upload/download files, delete files, manage containers
46 5ce54458 Panagiotis Kanavos
47 5ce54458 Panagiotis Kanavos
48 5ce54458 Panagiotis Kanavos
using System;
49 d78cbf09 Panagiotis Kanavos
using System.Collections.Generic;
50 aba9e6d9 Panagiotis Kanavos
using System.Collections.Specialized;
51 d78cbf09 Panagiotis Kanavos
using System.ComponentModel.Composition;
52 692ec33b Panagiotis Kanavos
using System.Diagnostics;
53 d78cbf09 Panagiotis Kanavos
using System.Diagnostics.Contracts;
54 d78cbf09 Panagiotis Kanavos
using System.IO;
55 d78cbf09 Panagiotis Kanavos
using System.Linq;
56 d78cbf09 Panagiotis Kanavos
using System.Net;
57 db8a9589 Panagiotis Kanavos
using System.Reflection;
58 d78cbf09 Panagiotis Kanavos
using System.Security.Cryptography;
59 d78cbf09 Panagiotis Kanavos
using System.Text;
60 2341c603 pkanavos
using System.Threading;
61 b5061ac8 Panagiotis Kanavos
using System.Threading.Tasks;
62 d78cbf09 Panagiotis Kanavos
using Newtonsoft.Json;
63 d78cbf09 Panagiotis Kanavos
using Pithos.Interfaces;
64 5120f3cb Panagiotis Kanavos
using log4net;
65 d78cbf09 Panagiotis Kanavos
66 d78cbf09 Panagiotis Kanavos
namespace Pithos.Network
67 d78cbf09 Panagiotis Kanavos
{
68 d78cbf09 Panagiotis Kanavos
    [Export(typeof(ICloudClient))]
69 d78cbf09 Panagiotis Kanavos
    public class CloudFilesClient:ICloudClient
70 d78cbf09 Panagiotis Kanavos
    {
71 db8a9589 Panagiotis Kanavos
        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
72 db8a9589 Panagiotis Kanavos
73 5ce54458 Panagiotis Kanavos
        //CloudFilesClient uses *_baseClient* internally to communicate with the server
74 5ce54458 Panagiotis Kanavos
        //RestClient provides a REST-friendly interface over the standard WebClient.
75 9c4346c9 Panagiotis Kanavos
        private RestClient _baseClient;
76 5ce54458 Panagiotis Kanavos
        
77 c53aa229 Panagiotis Kanavos
78 5ce54458 Panagiotis Kanavos
        //During authentication the client provides a UserName 
79 d78cbf09 Panagiotis Kanavos
        public string UserName { get; set; }
80 5ce54458 Panagiotis Kanavos
        
81 5ce54458 Panagiotis Kanavos
        //and and ApiKey to the server
82 5ce54458 Panagiotis Kanavos
        public string ApiKey { get; set; }
83 5ce54458 Panagiotis Kanavos
        
84 5ce54458 Panagiotis Kanavos
        //And receives an authentication Token. This token must be provided in ALL other operations,
85 5ce54458 Panagiotis Kanavos
        //in the X-Auth-Token header
86 c53aa229 Panagiotis Kanavos
        private string _token;
87 c53aa229 Panagiotis Kanavos
        public string Token
88 c53aa229 Panagiotis Kanavos
        {
89 c53aa229 Panagiotis Kanavos
            get { return _token; }
90 c53aa229 Panagiotis Kanavos
            set
91 c53aa229 Panagiotis Kanavos
            {
92 c53aa229 Panagiotis Kanavos
                _token = value;
93 c53aa229 Panagiotis Kanavos
                _baseClient.Headers["X-Auth-Token"] = value;
94 c53aa229 Panagiotis Kanavos
            }
95 c53aa229 Panagiotis Kanavos
        }
96 c53aa229 Panagiotis Kanavos
97 5ce54458 Panagiotis Kanavos
        //The client also receives a StorageUrl after authentication. All subsequent operations must
98 5ce54458 Panagiotis Kanavos
        //use this url
99 5ce54458 Panagiotis Kanavos
        public Uri StorageUrl { get; set; }
100 cfed7823 Panagiotis Kanavos
101 c53aa229 Panagiotis Kanavos
102 496595a5 pkanavos
        public Uri RootAddressUri { get; set; }
103 cfed7823 Panagiotis Kanavos
104 34bdb91d Panagiotis Kanavos
       /* private WebProxy _proxy;
105 65282d58 Panagiotis Kanavos
        public WebProxy Proxy
106 65282d58 Panagiotis Kanavos
        {
107 65282d58 Panagiotis Kanavos
            get { return _proxy; }
108 65282d58 Panagiotis Kanavos
            set
109 65282d58 Panagiotis Kanavos
            {
110 65282d58 Panagiotis Kanavos
                _proxy = value;
111 65282d58 Panagiotis Kanavos
                if (_baseClient != null)
112 65282d58 Panagiotis Kanavos
                    _baseClient.Proxy = value;                
113 65282d58 Panagiotis Kanavos
            }
114 65282d58 Panagiotis Kanavos
        }
115 34bdb91d Panagiotis Kanavos
*/
116 65282d58 Panagiotis Kanavos
117 65282d58 Panagiotis Kanavos
        /* private Uri _proxy;
118 c53aa229 Panagiotis Kanavos
        public Uri Proxy
119 c53aa229 Panagiotis Kanavos
        {
120 c53aa229 Panagiotis Kanavos
            get { return _proxy; }
121 c53aa229 Panagiotis Kanavos
            set
122 c53aa229 Panagiotis Kanavos
            {
123 c53aa229 Panagiotis Kanavos
                _proxy = value;
124 c53aa229 Panagiotis Kanavos
                if (_baseClient != null)
125 c53aa229 Panagiotis Kanavos
                    _baseClient.Proxy = new WebProxy(value);                
126 c53aa229 Panagiotis Kanavos
            }
127 65282d58 Panagiotis Kanavos
        }*/
128 b5061ac8 Panagiotis Kanavos
129 b5061ac8 Panagiotis Kanavos
        public double DownloadPercentLimit { get; set; }
130 b5061ac8 Panagiotis Kanavos
        public double UploadPercentLimit { get; set; }
131 79736291 Panagiotis Kanavos
132 79736291 Panagiotis Kanavos
        public string AuthenticationUrl { get; set; }
133 79736291 Panagiotis Kanavos
134 1482f9ad Panagiotis Kanavos
 
135 1482f9ad Panagiotis Kanavos
        public string VersionPath
136 1482f9ad Panagiotis Kanavos
        {
137 1482f9ad Panagiotis Kanavos
            get { return UsePithos ? "v1" : "v1.0"; }
138 1482f9ad Panagiotis Kanavos
        }
139 2c053915 Panagiotis Kanavos
140 2c053915 Panagiotis Kanavos
        public bool UsePithos { get; set; }
141 d78cbf09 Panagiotis Kanavos
142 3c43ec9b Panagiotis Kanavos
143 5120f3cb Panagiotis Kanavos
144 c53aa229 Panagiotis Kanavos
        public CloudFilesClient(string userName, string apiKey)
145 d78cbf09 Panagiotis Kanavos
        {
146 c53aa229 Panagiotis Kanavos
            UserName = userName;
147 c53aa229 Panagiotis Kanavos
            ApiKey = apiKey;
148 c53aa229 Panagiotis Kanavos
        }
149 c53aa229 Panagiotis Kanavos
150 c53aa229 Panagiotis Kanavos
        public CloudFilesClient(AccountInfo accountInfo)
151 c53aa229 Panagiotis Kanavos
        {
152 c53aa229 Panagiotis Kanavos
            if (accountInfo==null)
153 c53aa229 Panagiotis Kanavos
                throw new ArgumentNullException("accountInfo");
154 c53aa229 Panagiotis Kanavos
            Contract.Ensures(!String.IsNullOrWhiteSpace(Token));
155 c53aa229 Panagiotis Kanavos
            Contract.Ensures(StorageUrl != null);
156 cfed7823 Panagiotis Kanavos
            Contract.Ensures(_baseClient != null);
157 c53aa229 Panagiotis Kanavos
            Contract.Ensures(RootAddressUri != null);
158 422c9598 Panagiotis Kanavos
            Contract.EndContractBlock();          
159 cfed7823 Panagiotis Kanavos
160 c53aa229 Panagiotis Kanavos
            _baseClient = new RestClient
161 c53aa229 Panagiotis Kanavos
            {
162 c53aa229 Panagiotis Kanavos
                BaseAddress = accountInfo.StorageUri.ToString(),
163 c53aa229 Panagiotis Kanavos
                Timeout = 10000,
164 65282d58 Panagiotis Kanavos
                Retries = 3,
165 c53aa229 Panagiotis Kanavos
            };
166 c53aa229 Panagiotis Kanavos
            StorageUrl = accountInfo.StorageUri;
167 c53aa229 Panagiotis Kanavos
            Token = accountInfo.Token;
168 c53aa229 Panagiotis Kanavos
            UserName = accountInfo.UserName;
169 c53aa229 Panagiotis Kanavos
170 c53aa229 Panagiotis Kanavos
            //Get the root address (StorageUrl without the account)
171 c53aa229 Panagiotis Kanavos
            var storageUrl = StorageUrl.AbsoluteUri;
172 c53aa229 Panagiotis Kanavos
            var usernameIndex = storageUrl.LastIndexOf(UserName);
173 c53aa229 Panagiotis Kanavos
            var rootUrl = storageUrl.Substring(0, usernameIndex);
174 c53aa229 Panagiotis Kanavos
            RootAddressUri = new Uri(rootUrl);
175 c53aa229 Panagiotis Kanavos
        }
176 d78cbf09 Panagiotis Kanavos
177 3c43ec9b Panagiotis Kanavos
178 c53aa229 Panagiotis Kanavos
        public AccountInfo Authenticate()
179 c53aa229 Panagiotis Kanavos
        {
180 c53aa229 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(UserName))
181 c53aa229 Panagiotis Kanavos
                throw new InvalidOperationException("UserName is empty");
182 c53aa229 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(ApiKey))
183 c53aa229 Panagiotis Kanavos
                throw new InvalidOperationException("ApiKey is empty");
184 c53aa229 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(AuthenticationUrl))
185 c53aa229 Panagiotis Kanavos
                throw new InvalidOperationException("AuthenticationUrl is empty");
186 c53aa229 Panagiotis Kanavos
            Contract.Ensures(!String.IsNullOrWhiteSpace(Token));
187 c53aa229 Panagiotis Kanavos
            Contract.Ensures(StorageUrl != null);
188 c53aa229 Panagiotis Kanavos
            Contract.Ensures(_baseClient != null);
189 c53aa229 Panagiotis Kanavos
            Contract.Ensures(RootAddressUri != null);
190 c53aa229 Panagiotis Kanavos
            Contract.EndContractBlock();
191 c53aa229 Panagiotis Kanavos
192 c53aa229 Panagiotis Kanavos
193 c53aa229 Panagiotis Kanavos
            Log.InfoFormat("[AUTHENTICATE] Start for {0}", UserName);
194 d78cbf09 Panagiotis Kanavos
195 c92e02f3 Panagiotis Kanavos
            var groups = new List<Group>();
196 c92e02f3 Panagiotis Kanavos
197 9c4346c9 Panagiotis Kanavos
            using (var authClient = new RestClient{BaseAddress=AuthenticationUrl})
198 65282d58 Panagiotis Kanavos
            {                
199 34bdb91d Panagiotis Kanavos
               /* if (Proxy != null)
200 34bdb91d Panagiotis Kanavos
                    authClient.Proxy = Proxy;*/
201 d78cbf09 Panagiotis Kanavos
202 cfed7823 Panagiotis Kanavos
                Contract.Assume(authClient.Headers!=null);
203 cfed7823 Panagiotis Kanavos
204 4d301e8e Panagiotis Kanavos
                authClient.Headers.Add("X-Auth-User", UserName);
205 4d301e8e Panagiotis Kanavos
                authClient.Headers.Add("X-Auth-Key", ApiKey);
206 0eea575a Panagiotis Kanavos
207 cd7c162f Panagiotis Kanavos
                authClient.DownloadStringWithRetry(VersionPath, 3);
208 0eea575a Panagiotis Kanavos
209 4d301e8e Panagiotis Kanavos
                authClient.AssertStatusOK("Authentication failed");
210 0eea575a Panagiotis Kanavos
211 cd7c162f Panagiotis Kanavos
                var storageUrl = authClient.GetHeaderValue("X-Storage-Url");
212 0eea575a Panagiotis Kanavos
                if (String.IsNullOrWhiteSpace(storageUrl))
213 0eea575a Panagiotis Kanavos
                    throw new InvalidOperationException("Failed to obtain storage url");
214 c53aa229 Panagiotis Kanavos
                
215 c53aa229 Panagiotis Kanavos
                _baseClient = new RestClient
216 c53aa229 Panagiotis Kanavos
                {
217 c53aa229 Panagiotis Kanavos
                    BaseAddress = storageUrl,
218 c53aa229 Panagiotis Kanavos
                    Timeout = 10000,
219 65282d58 Panagiotis Kanavos
                    Retries = 3,
220 34bdb91d Panagiotis Kanavos
                    //Proxy=Proxy
221 c53aa229 Panagiotis Kanavos
                };
222 c53aa229 Panagiotis Kanavos
223 0eea575a Panagiotis Kanavos
                StorageUrl = new Uri(storageUrl);
224 d9643dd6 Panagiotis Kanavos
                
225 cfed7823 Panagiotis Kanavos
                //Get the root address (StorageUrl without the account)
226 cfed7823 Panagiotis Kanavos
                var usernameIndex=storageUrl.LastIndexOf(UserName);
227 cfed7823 Panagiotis Kanavos
                var rootUrl = storageUrl.Substring(0, usernameIndex);
228 cfed7823 Panagiotis Kanavos
                RootAddressUri = new Uri(rootUrl);
229 cfed7823 Panagiotis Kanavos
                
230 4d301e8e Panagiotis Kanavos
                var token = authClient.GetHeaderValue("X-Auth-Token");
231 b6c72f62 Panagiotis Kanavos
                if (String.IsNullOrWhiteSpace(token))
232 b6c72f62 Panagiotis Kanavos
                    throw new InvalidOperationException("Failed to obtain token url");
233 b6c72f62 Panagiotis Kanavos
                Token = token;
234 c53aa229 Panagiotis Kanavos
235 c92e02f3 Panagiotis Kanavos
               /* var keys = authClient.ResponseHeaders.AllKeys.AsQueryable();
236 c92e02f3 Panagiotis Kanavos
                groups = (from key in keys
237 c92e02f3 Panagiotis Kanavos
                            where key.StartsWith("X-Account-Group-")
238 c92e02f3 Panagiotis Kanavos
                            let name = key.Substring(16)
239 c92e02f3 Panagiotis Kanavos
                            select new Group(name, authClient.ResponseHeaders[key]))
240 c92e02f3 Panagiotis Kanavos
                        .ToList();
241 c92e02f3 Panagiotis Kanavos
                    
242 c92e02f3 Panagiotis Kanavos
*/
243 b6c72f62 Panagiotis Kanavos
            }
244 d78cbf09 Panagiotis Kanavos
245 c53aa229 Panagiotis Kanavos
            Log.InfoFormat("[AUTHENTICATE] End for {0}", UserName);
246 ebc37b0d pkanavos
            Debug.Assert(_baseClient!=null);
247 9c4346c9 Panagiotis Kanavos
248 c92e02f3 Panagiotis Kanavos
            return new AccountInfo {StorageUri = StorageUrl, Token = Token, UserName = UserName,Groups=groups};            
249 2c053915 Panagiotis Kanavos
250 b5061ac8 Panagiotis Kanavos
        }
251 d78cbf09 Panagiotis Kanavos
252 d78cbf09 Panagiotis Kanavos
253 cfed7823 Panagiotis Kanavos
254 cfed7823 Panagiotis Kanavos
        public IList<ContainerInfo> ListContainers(string account)
255 9c4346c9 Panagiotis Kanavos
        {
256 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
257 9c4346c9 Panagiotis Kanavos
            {
258 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
259 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
260 cfed7823 Panagiotis Kanavos
                
261 9c4346c9 Panagiotis Kanavos
                client.Parameters.Clear();
262 9c4346c9 Panagiotis Kanavos
                client.Parameters.Add("format", "json");
263 5ce54458 Panagiotis Kanavos
                var content = client.DownloadStringWithRetry("", 3);
264 9c4346c9 Panagiotis Kanavos
                client.AssertStatusOK("List Containers failed");
265 9c4346c9 Panagiotis Kanavos
266 9c4346c9 Panagiotis Kanavos
                if (client.StatusCode == HttpStatusCode.NoContent)
267 9c4346c9 Panagiotis Kanavos
                    return new List<ContainerInfo>();
268 9c4346c9 Panagiotis Kanavos
                var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(content);
269 5750d7cc Panagiotis Kanavos
                
270 5750d7cc Panagiotis Kanavos
                foreach (var info in infos)
271 5750d7cc Panagiotis Kanavos
                {
272 5750d7cc Panagiotis Kanavos
                    info.Account = account;
273 5750d7cc Panagiotis Kanavos
                }
274 9c4346c9 Panagiotis Kanavos
                return infos;
275 9c4346c9 Panagiotis Kanavos
            }
276 4d301e8e Panagiotis Kanavos
277 d78cbf09 Panagiotis Kanavos
        }
278 d78cbf09 Panagiotis Kanavos
279 cfed7823 Panagiotis Kanavos
        private string GetAccountUrl(string account)
280 cfed7823 Panagiotis Kanavos
        {
281 4f6d51d4 Panagiotis Kanavos
            return new Uri(RootAddressUri, new Uri(account,UriKind.Relative)).AbsoluteUri;
282 cfed7823 Panagiotis Kanavos
        }
283 cfed7823 Panagiotis Kanavos
284 cfed7823 Panagiotis Kanavos
        public IList<ShareAccountInfo> ListSharingAccounts(DateTime? since=null)
285 cfed7823 Panagiotis Kanavos
        {
286 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Share"].Push("List Accounts"))
287 cfed7823 Panagiotis Kanavos
            {
288 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
289 cfed7823 Panagiotis Kanavos
290 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
291 5120f3cb Panagiotis Kanavos
                {
292 5120f3cb Panagiotis Kanavos
                    client.Parameters.Clear();
293 5120f3cb Panagiotis Kanavos
                    client.Parameters.Add("format", "json");
294 5120f3cb Panagiotis Kanavos
                    client.IfModifiedSince = since;
295 cfed7823 Panagiotis Kanavos
296 5120f3cb Panagiotis Kanavos
                    //Extract the username from the base address
297 5120f3cb Panagiotis Kanavos
                    client.BaseAddress = RootAddressUri.AbsoluteUri;
298 cfed7823 Panagiotis Kanavos
299 5120f3cb Panagiotis Kanavos
                    var content = client.DownloadStringWithRetry(@"", 3);
300 cfed7823 Panagiotis Kanavos
301 5120f3cb Panagiotis Kanavos
                    client.AssertStatusOK("ListSharingAccounts failed");
302 5120f3cb Panagiotis Kanavos
303 5120f3cb Panagiotis Kanavos
                    //If the result is empty, return an empty list,
304 5120f3cb Panagiotis Kanavos
                    var infos = String.IsNullOrWhiteSpace(content)
305 5120f3cb Panagiotis Kanavos
                                    ? new List<ShareAccountInfo>()
306 5120f3cb Panagiotis Kanavos
                                //Otherwise deserialize the account list into a list of ShareAccountInfos
307 5120f3cb Panagiotis Kanavos
                                    : JsonConvert.DeserializeObject<IList<ShareAccountInfo>>(content);
308 5120f3cb Panagiotis Kanavos
309 5120f3cb Panagiotis Kanavos
                    Log.DebugFormat("END");
310 5120f3cb Panagiotis Kanavos
                    return infos;
311 5120f3cb Panagiotis Kanavos
                }
312 cfed7823 Panagiotis Kanavos
            }
313 cfed7823 Panagiotis Kanavos
        }
314 cfed7823 Panagiotis Kanavos
315 5ce54458 Panagiotis Kanavos
        //Request listing of all objects in a container modified since a specific time.
316 5ce54458 Panagiotis Kanavos
        //If the *since* value is missing, return all objects
317 cfed7823 Panagiotis Kanavos
        public IList<ObjectInfo> ListSharedObjects(DateTime? since = null)
318 cfed7823 Panagiotis Kanavos
        {
319 cfed7823 Panagiotis Kanavos
320 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Share"].Push("List Objects"))
321 cfed7823 Panagiotis Kanavos
            {
322 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
323 99e6329f Panagiotis Kanavos
                //'since' is not used here because we need to have ListObjects return a NoChange result
324 99e6329f Panagiotis Kanavos
                //for all shared accounts,containers
325 99e6329f Panagiotis Kanavos
                var accounts = ListSharingAccounts();
326 126f90b3 Panagiotis Kanavos
                var items = from account in accounts 
327 126f90b3 Panagiotis Kanavos
                            let containers = ListContainers(account.name) 
328 126f90b3 Panagiotis Kanavos
                            from container in containers 
329 99e6329f Panagiotis Kanavos
                            select ListObjects(account.name, container.Name,since);
330 126f90b3 Panagiotis Kanavos
                var objects=items.SelectMany(r=> r).ToList();
331 126f90b3 Panagiotis Kanavos
/*
332 126f90b3 Panagiotis Kanavos
                var objects = new List<ObjectInfo>();
333 126f90b3 Panagiotis Kanavos
                foreach (var containerObjects in items)
334 cfed7823 Panagiotis Kanavos
                {
335 126f90b3 Panagiotis Kanavos
                    objects.AddRange(containerObjects);
336 cfed7823 Panagiotis Kanavos
                }
337 126f90b3 Panagiotis Kanavos
*/
338 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("END");
339 5120f3cb Panagiotis Kanavos
                return objects;
340 cfed7823 Panagiotis Kanavos
            }
341 cfed7823 Panagiotis Kanavos
        }
342 cfed7823 Panagiotis Kanavos
343 ff26eb71 Panagiotis Kanavos
        public void SetTags(ObjectInfo target,IDictionary<string,string> tags)
344 ff26eb71 Panagiotis Kanavos
        {
345 ff26eb71 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
346 ff26eb71 Panagiotis Kanavos
                throw new InvalidOperationException("The Token is not set");
347 ff26eb71 Panagiotis Kanavos
            if (StorageUrl == null)
348 ff26eb71 Panagiotis Kanavos
                throw new InvalidOperationException("The StorageUrl is not set");
349 ff26eb71 Panagiotis Kanavos
            if (target == null)
350 ff26eb71 Panagiotis Kanavos
                throw new ArgumentNullException("target");
351 ff26eb71 Panagiotis Kanavos
            Contract.EndContractBlock();
352 ff26eb71 Panagiotis Kanavos
353 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Share"].Push("Share Object"))
354 ff26eb71 Panagiotis Kanavos
            {
355 ff26eb71 Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
356 ff26eb71 Panagiotis Kanavos
357 ff26eb71 Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
358 ff26eb71 Panagiotis Kanavos
                {
359 ff26eb71 Panagiotis Kanavos
360 ff26eb71 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(target.Account);
361 ff26eb71 Panagiotis Kanavos
362 ff26eb71 Panagiotis Kanavos
                    client.Parameters.Clear();
363 ff26eb71 Panagiotis Kanavos
                    client.Parameters.Add("update", "");
364 ff26eb71 Panagiotis Kanavos
365 ff26eb71 Panagiotis Kanavos
                    foreach (var tag in tags)
366 ff26eb71 Panagiotis Kanavos
                    {
367 ff26eb71 Panagiotis Kanavos
                        var headerTag = String.Format("X-Object-Meta-{0}", tag.Key);
368 ff26eb71 Panagiotis Kanavos
                        client.Headers.Add(headerTag, tag.Value);
369 ff26eb71 Panagiotis Kanavos
                    }
370 ff26eb71 Panagiotis Kanavos
                    
371 4f6d51d4 Panagiotis Kanavos
                    client.DownloadStringWithRetry(target.Container, 3);
372 ff26eb71 Panagiotis Kanavos
373 ff26eb71 Panagiotis Kanavos
                    
374 ff26eb71 Panagiotis Kanavos
                    client.AssertStatusOK("SetTags failed");
375 ff26eb71 Panagiotis Kanavos
                    //If the status is NOT ACCEPTED we have a problem
376 ff26eb71 Panagiotis Kanavos
                    if (client.StatusCode != HttpStatusCode.Accepted)
377 ff26eb71 Panagiotis Kanavos
                    {
378 ff26eb71 Panagiotis Kanavos
                        Log.Error("Failed to set tags");
379 ff26eb71 Panagiotis Kanavos
                        throw new Exception("Failed to set tags");
380 ff26eb71 Panagiotis Kanavos
                    }
381 ff26eb71 Panagiotis Kanavos
382 ff26eb71 Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
383 ff26eb71 Panagiotis Kanavos
                }
384 ff26eb71 Panagiotis Kanavos
            }
385 ff26eb71 Panagiotis Kanavos
386 ff26eb71 Panagiotis Kanavos
387 ff26eb71 Panagiotis Kanavos
        }
388 ff26eb71 Panagiotis Kanavos
389 cfed7823 Panagiotis Kanavos
        public void ShareObject(string account, string container, string objectName, string shareTo, bool read, bool write)
390 cfed7823 Panagiotis Kanavos
        {
391 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
392 cfed7823 Panagiotis Kanavos
                throw new InvalidOperationException("The Token is not set");
393 cfed7823 Panagiotis Kanavos
            if (StorageUrl==null)
394 cfed7823 Panagiotis Kanavos
                throw new InvalidOperationException("The StorageUrl is not set");
395 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
396 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("container");
397 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
398 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("objectName");
399 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(account))
400 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("account");
401 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(shareTo))
402 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("shareTo");
403 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
404 cfed7823 Panagiotis Kanavos
405 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Share"].Push("Share Object"))
406 cfed7823 Panagiotis Kanavos
            {
407 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
408 5120f3cb Panagiotis Kanavos
                
409 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
410 5120f3cb Panagiotis Kanavos
                {
411 cfed7823 Panagiotis Kanavos
412 5120f3cb Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
413 cfed7823 Panagiotis Kanavos
414 5120f3cb Panagiotis Kanavos
                    client.Parameters.Clear();
415 5120f3cb Panagiotis Kanavos
                    client.Parameters.Add("format", "json");
416 5120f3cb Panagiotis Kanavos
417 5120f3cb Panagiotis Kanavos
                    string permission = "";
418 5120f3cb Panagiotis Kanavos
                    if (write)
419 5120f3cb Panagiotis Kanavos
                        permission = String.Format("write={0}", shareTo);
420 5120f3cb Panagiotis Kanavos
                    else if (read)
421 5120f3cb Panagiotis Kanavos
                        permission = String.Format("read={0}", shareTo);
422 5120f3cb Panagiotis Kanavos
                    client.Headers.Add("X-Object-Sharing", permission);
423 cfed7823 Panagiotis Kanavos
424 5120f3cb Panagiotis Kanavos
                    var content = client.DownloadStringWithRetry(container, 3);
425 cfed7823 Panagiotis Kanavos
426 5120f3cb Panagiotis Kanavos
                    client.AssertStatusOK("ShareObject failed");
427 cfed7823 Panagiotis Kanavos
428 5120f3cb Panagiotis Kanavos
                    //If the result is empty, return an empty list,
429 5120f3cb Panagiotis Kanavos
                    var infos = String.IsNullOrWhiteSpace(content)
430 5120f3cb Panagiotis Kanavos
                                    ? new List<ObjectInfo>()
431 5120f3cb Panagiotis Kanavos
                                //Otherwise deserialize the object list into a list of ObjectInfos
432 5120f3cb Panagiotis Kanavos
                                    : JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
433 5120f3cb Panagiotis Kanavos
434 5120f3cb Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
435 5120f3cb Panagiotis Kanavos
                }
436 cfed7823 Panagiotis Kanavos
            }
437 cfed7823 Panagiotis Kanavos
438 5120f3cb Panagiotis Kanavos
439 cfed7823 Panagiotis Kanavos
        }
440 cfed7823 Panagiotis Kanavos
441 0bd56b7c Panagiotis Kanavos
        public AccountInfo GetAccountPolicies(AccountInfo accountInfo)
442 0bd56b7c Panagiotis Kanavos
        {
443 0bd56b7c Panagiotis Kanavos
            if (accountInfo==null)
444 0bd56b7c Panagiotis Kanavos
                throw new ArgumentNullException("accountInfo");
445 0bd56b7c Panagiotis Kanavos
            Contract.EndContractBlock();
446 0bd56b7c Panagiotis Kanavos
447 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Account"].Push("GetPolicies"))
448 0bd56b7c Panagiotis Kanavos
            {
449 0bd56b7c Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
450 0bd56b7c Panagiotis Kanavos
451 0bd56b7c Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
452 0bd56b7c Panagiotis Kanavos
                {
453 0bd56b7c Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(accountInfo.UserName))
454 0bd56b7c Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(accountInfo.UserName);
455 0bd56b7c Panagiotis Kanavos
456 0bd56b7c Panagiotis Kanavos
                    client.Parameters.Clear();
457 0bd56b7c Panagiotis Kanavos
                    client.Parameters.Add("format", "json");                    
458 0bd56b7c Panagiotis Kanavos
                    client.Head(String.Empty, 3);
459 0bd56b7c Panagiotis Kanavos
460 0bd56b7c Panagiotis Kanavos
                    var quotaValue=client.ResponseHeaders["X-Account-Policy-Quota"];
461 0bd56b7c Panagiotis Kanavos
                    var bytesValue= client.ResponseHeaders["X-Account-Bytes-Used"];
462 0bd56b7c Panagiotis Kanavos
463 0bd56b7c Panagiotis Kanavos
                    long quota, bytes;
464 0bd56b7c Panagiotis Kanavos
                    if (long.TryParse(quotaValue, out quota))
465 0bd56b7c Panagiotis Kanavos
                        accountInfo.Quota = quota;
466 0bd56b7c Panagiotis Kanavos
                    if (long.TryParse(bytesValue, out bytes))
467 0bd56b7c Panagiotis Kanavos
                        accountInfo.BytesUsed = bytes;
468 0bd56b7c Panagiotis Kanavos
                    
469 0bd56b7c Panagiotis Kanavos
                    return accountInfo;
470 0bd56b7c Panagiotis Kanavos
471 0bd56b7c Panagiotis Kanavos
                }
472 0bd56b7c Panagiotis Kanavos
473 0bd56b7c Panagiotis Kanavos
            }
474 0bd56b7c Panagiotis Kanavos
        }
475 0bd56b7c Panagiotis Kanavos
476 aba9e6d9 Panagiotis Kanavos
        public void UpdateMetadata(ObjectInfo objectInfo)
477 aba9e6d9 Panagiotis Kanavos
        {
478 aba9e6d9 Panagiotis Kanavos
            if (objectInfo == null)
479 aba9e6d9 Panagiotis Kanavos
                throw new ArgumentNullException("objectInfo");
480 aba9e6d9 Panagiotis Kanavos
            Contract.EndContractBlock();
481 aba9e6d9 Panagiotis Kanavos
482 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Objects"].Push("UpdateMetadata"))
483 aba9e6d9 Panagiotis Kanavos
            {
484 aba9e6d9 Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
485 aba9e6d9 Panagiotis Kanavos
486 aba9e6d9 Panagiotis Kanavos
487 aba9e6d9 Panagiotis Kanavos
                using(var client=new RestClient(_baseClient))
488 aba9e6d9 Panagiotis Kanavos
                {
489 aba9e6d9 Panagiotis Kanavos
490 aba9e6d9 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(objectInfo.Account);
491 aba9e6d9 Panagiotis Kanavos
                    
492 aba9e6d9 Panagiotis Kanavos
                    client.Parameters.Clear();
493 aba9e6d9 Panagiotis Kanavos
                    
494 aba9e6d9 Panagiotis Kanavos
495 aba9e6d9 Panagiotis Kanavos
                    //Set Tags
496 aba9e6d9 Panagiotis Kanavos
                    foreach (var tag in objectInfo.Tags)
497 aba9e6d9 Panagiotis Kanavos
                    {
498 aba9e6d9 Panagiotis Kanavos
                        var headerTag = String.Format("X-Object-Meta-{0}", tag.Key);
499 aba9e6d9 Panagiotis Kanavos
                        client.Headers.Add(headerTag, tag.Value);
500 aba9e6d9 Panagiotis Kanavos
                    }
501 aba9e6d9 Panagiotis Kanavos
502 aba9e6d9 Panagiotis Kanavos
                    //Set Permissions
503 aba9e6d9 Panagiotis Kanavos
504 aba9e6d9 Panagiotis Kanavos
                    var permissions=objectInfo.GetPermissionString();
505 aba9e6d9 Panagiotis Kanavos
                    client.SetNonEmptyHeaderValue("X-Object-Sharing",permissions);
506 aba9e6d9 Panagiotis Kanavos
507 aba9e6d9 Panagiotis Kanavos
                    client.SetNonEmptyHeaderValue("Content-Disposition",objectInfo.ContendDisposition);
508 aba9e6d9 Panagiotis Kanavos
                    client.SetNonEmptyHeaderValue("Content-Encoding",objectInfo.ContentEncoding);
509 aba9e6d9 Panagiotis Kanavos
                    client.SetNonEmptyHeaderValue("X-Object-Manifest",objectInfo.Manifest);
510 f0947233 Panagiotis Kanavos
                    var isPublic = objectInfo.IsPublic.ToString().ToLower();
511 f0947233 Panagiotis Kanavos
                    client.Headers.Add("X-Object-Public", isPublic);
512 aba9e6d9 Panagiotis Kanavos
513 aba9e6d9 Panagiotis Kanavos
514 bb7717f5 pkanavos
                    /*var uriBuilder = client.GetAddressBuilder(objectInfo.Container, objectInfo.Name);
515 bb7717f5 pkanavos
                    uriBuilder.Query = "update=";
516 bb7717f5 pkanavos
                    var uri = uriBuilder.Uri.MakeRelativeUri(this.RootAddressUri);*/
517 bb7717f5 pkanavos
                    var address = String.Format("{0}/{1}?update=",objectInfo.Container, objectInfo.Name);
518 bb7717f5 pkanavos
                    client.PostWithRetry(address,"application/xml");
519 bb7717f5 pkanavos
                    
520 bb7717f5 pkanavos
                    //client.UploadValues(uri,new NameValueCollection());
521 aba9e6d9 Panagiotis Kanavos
522 aba9e6d9 Panagiotis Kanavos
523 aba9e6d9 Panagiotis Kanavos
                    client.AssertStatusOK("UpdateMetadata failed");
524 aba9e6d9 Panagiotis Kanavos
                    //If the status is NOT ACCEPTED or OK we have a problem
525 aba9e6d9 Panagiotis Kanavos
                    if (!(client.StatusCode == HttpStatusCode.Accepted || client.StatusCode == HttpStatusCode.OK))
526 aba9e6d9 Panagiotis Kanavos
                    {
527 aba9e6d9 Panagiotis Kanavos
                        Log.Error("Failed to update metadata");
528 aba9e6d9 Panagiotis Kanavos
                        throw new Exception("Failed to update metadata");
529 aba9e6d9 Panagiotis Kanavos
                    }
530 aba9e6d9 Panagiotis Kanavos
531 aba9e6d9 Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
532 aba9e6d9 Panagiotis Kanavos
                }
533 aba9e6d9 Panagiotis Kanavos
            }
534 aba9e6d9 Panagiotis Kanavos
535 aba9e6d9 Panagiotis Kanavos
        }
536 aba9e6d9 Panagiotis Kanavos
537 c92e02f3 Panagiotis Kanavos
        public void UpdateMetadata(ContainerInfo containerInfo)
538 c92e02f3 Panagiotis Kanavos
        {
539 c92e02f3 Panagiotis Kanavos
            if (containerInfo == null)
540 c92e02f3 Panagiotis Kanavos
                throw new ArgumentNullException("containerInfo");
541 c92e02f3 Panagiotis Kanavos
            Contract.EndContractBlock();
542 c92e02f3 Panagiotis Kanavos
543 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Containers"].Push("UpdateMetadata"))
544 c92e02f3 Panagiotis Kanavos
            {
545 c92e02f3 Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
546 c92e02f3 Panagiotis Kanavos
547 c92e02f3 Panagiotis Kanavos
548 c92e02f3 Panagiotis Kanavos
                using(var client=new RestClient(_baseClient))
549 c92e02f3 Panagiotis Kanavos
                {
550 c92e02f3 Panagiotis Kanavos
551 c92e02f3 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(containerInfo.Account);
552 c92e02f3 Panagiotis Kanavos
                    
553 c92e02f3 Panagiotis Kanavos
                    client.Parameters.Clear();
554 c92e02f3 Panagiotis Kanavos
                    
555 c92e02f3 Panagiotis Kanavos
556 c92e02f3 Panagiotis Kanavos
                    //Set Tags
557 c92e02f3 Panagiotis Kanavos
                    foreach (var tag in containerInfo.Tags)
558 c92e02f3 Panagiotis Kanavos
                    {
559 c92e02f3 Panagiotis Kanavos
                        var headerTag = String.Format("X-Container-Meta-{0}", tag.Key);
560 c92e02f3 Panagiotis Kanavos
                        client.Headers.Add(headerTag, tag.Value);
561 c92e02f3 Panagiotis Kanavos
                    }
562 c92e02f3 Panagiotis Kanavos
563 c92e02f3 Panagiotis Kanavos
                    
564 c92e02f3 Panagiotis Kanavos
                    //Set Policies
565 c92e02f3 Panagiotis Kanavos
                    foreach (var policy in containerInfo.Policies)
566 c92e02f3 Panagiotis Kanavos
                    {
567 c92e02f3 Panagiotis Kanavos
                        var headerPolicy = String.Format("X-Container-Policy-{0}", policy.Key);
568 c92e02f3 Panagiotis Kanavos
                        client.Headers.Add(headerPolicy, policy.Value);
569 c92e02f3 Panagiotis Kanavos
                    }
570 c92e02f3 Panagiotis Kanavos
571 c92e02f3 Panagiotis Kanavos
572 c92e02f3 Panagiotis Kanavos
                    var uriBuilder = client.GetAddressBuilder(containerInfo.Name,"");
573 c92e02f3 Panagiotis Kanavos
                    var uri = uriBuilder.Uri;
574 c92e02f3 Panagiotis Kanavos
575 4f6d51d4 Panagiotis Kanavos
                    client.UploadValues(uri,new NameValueCollection());
576 c92e02f3 Panagiotis Kanavos
577 c92e02f3 Panagiotis Kanavos
578 c92e02f3 Panagiotis Kanavos
                    client.AssertStatusOK("UpdateMetadata failed");
579 c92e02f3 Panagiotis Kanavos
                    //If the status is NOT ACCEPTED or OK we have a problem
580 c92e02f3 Panagiotis Kanavos
                    if (!(client.StatusCode == HttpStatusCode.Accepted || client.StatusCode == HttpStatusCode.OK))
581 c92e02f3 Panagiotis Kanavos
                    {
582 c92e02f3 Panagiotis Kanavos
                        Log.Error("Failed to update metadata");
583 c92e02f3 Panagiotis Kanavos
                        throw new Exception("Failed to update metadata");
584 c92e02f3 Panagiotis Kanavos
                    }
585 c92e02f3 Panagiotis Kanavos
586 c92e02f3 Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
587 c92e02f3 Panagiotis Kanavos
                }
588 c92e02f3 Panagiotis Kanavos
            }
589 c92e02f3 Panagiotis Kanavos
590 c92e02f3 Panagiotis Kanavos
        }
591 c92e02f3 Panagiotis Kanavos
592 cfed7823 Panagiotis Kanavos
593 cfed7823 Panagiotis Kanavos
        public IList<ObjectInfo> ListObjects(string account, string container, DateTime? since = null)
594 d78cbf09 Panagiotis Kanavos
        {
595 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
596 9c4346c9 Panagiotis Kanavos
                throw new ArgumentNullException("container");
597 9c4346c9 Panagiotis Kanavos
            Contract.EndContractBlock();
598 d78cbf09 Panagiotis Kanavos
599 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Objects"].Push("List"))
600 9c4346c9 Panagiotis Kanavos
            {
601 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
602 cfed7823 Panagiotis Kanavos
603 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
604 5120f3cb Panagiotis Kanavos
                {
605 5120f3cb Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
606 5120f3cb Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
607 4d301e8e Panagiotis Kanavos
608 5120f3cb Panagiotis Kanavos
                    client.Parameters.Clear();
609 5120f3cb Panagiotis Kanavos
                    client.Parameters.Add("format", "json");
610 5120f3cb Panagiotis Kanavos
                    client.IfModifiedSince = since;
611 5120f3cb Panagiotis Kanavos
                    var content = client.DownloadStringWithRetry(container, 3);
612 4d301e8e Panagiotis Kanavos
613 5120f3cb Panagiotis Kanavos
                    client.AssertStatusOK("ListObjects failed");
614 d78cbf09 Panagiotis Kanavos
615 99e6329f Panagiotis Kanavos
                    if (client.StatusCode==HttpStatusCode.NotModified)
616 99e6329f Panagiotis Kanavos
                        return new[]{new NoModificationInfo(account,container)};
617 5120f3cb Panagiotis Kanavos
                    //If the result is empty, return an empty list,
618 5120f3cb Panagiotis Kanavos
                    var infos = String.IsNullOrWhiteSpace(content)
619 5120f3cb Panagiotis Kanavos
                                    ? new List<ObjectInfo>()
620 5120f3cb Panagiotis Kanavos
                                //Otherwise deserialize the object list into a list of ObjectInfos
621 5120f3cb Panagiotis Kanavos
                                    : JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
622 5120f3cb Panagiotis Kanavos
623 5120f3cb Panagiotis Kanavos
                    foreach (var info in infos)
624 5120f3cb Panagiotis Kanavos
                    {
625 5120f3cb Panagiotis Kanavos
                        info.Container = container;
626 5120f3cb Panagiotis Kanavos
                        info.Account = account;
627 759bd3c4 Panagiotis Kanavos
                        info.StorageUri = this.StorageUrl;
628 5120f3cb Panagiotis Kanavos
                    }
629 126f90b3 Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
630 5120f3cb Panagiotis Kanavos
                    return infos;
631 cfed7823 Panagiotis Kanavos
                }
632 9c4346c9 Panagiotis Kanavos
            }
633 d78cbf09 Panagiotis Kanavos
        }
634 d78cbf09 Panagiotis Kanavos
635 cfed7823 Panagiotis Kanavos
        public IList<ObjectInfo> ListObjects(string account, string container, string folder, DateTime? since = null)
636 637bc368 Panagiotis Kanavos
        {
637 637bc368 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
638 9c4346c9 Panagiotis Kanavos
                throw new ArgumentNullException("container");
639 93dc3a84 Panagiotis Kanavos
/*
640 9c4346c9 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(folder))
641 9c4346c9 Panagiotis Kanavos
                throw new ArgumentNullException("folder");
642 93dc3a84 Panagiotis Kanavos
*/
643 9c4346c9 Panagiotis Kanavos
            Contract.EndContractBlock();
644 637bc368 Panagiotis Kanavos
645 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Objects"].Push("List"))
646 9c4346c9 Panagiotis Kanavos
            {
647 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
648 cfed7823 Panagiotis Kanavos
649 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
650 5120f3cb Panagiotis Kanavos
                {
651 5120f3cb Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
652 5120f3cb Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
653 4d301e8e Panagiotis Kanavos
654 5120f3cb Panagiotis Kanavos
                    client.Parameters.Clear();
655 5120f3cb Panagiotis Kanavos
                    client.Parameters.Add("format", "json");
656 5120f3cb Panagiotis Kanavos
                    client.Parameters.Add("path", folder);
657 5120f3cb Panagiotis Kanavos
                    client.IfModifiedSince = since;
658 5120f3cb Panagiotis Kanavos
                    var content = client.DownloadStringWithRetry(container, 3);
659 5120f3cb Panagiotis Kanavos
                    client.AssertStatusOK("ListObjects failed");
660 5bcf6d70 Panagiotis Kanavos
661 99e6329f Panagiotis Kanavos
                    if (client.StatusCode==HttpStatusCode.NotModified)
662 99e6329f Panagiotis Kanavos
                        return new[]{new NoModificationInfo(account,container,folder)};
663 99e6329f Panagiotis Kanavos
664 5120f3cb Panagiotis Kanavos
                    var infos = JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
665 93dc3a84 Panagiotis Kanavos
                    foreach (var info in infos)
666 93dc3a84 Panagiotis Kanavos
                    {
667 93dc3a84 Panagiotis Kanavos
                        info.Account = account;
668 759bd3c4 Panagiotis Kanavos
                        if (info.Container == null)
669 759bd3c4 Panagiotis Kanavos
                            info.Container = container;
670 759bd3c4 Panagiotis Kanavos
                        info.StorageUri = this.StorageUrl;
671 93dc3a84 Panagiotis Kanavos
                    }
672 5120f3cb Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
673 5120f3cb Panagiotis Kanavos
                    return infos;
674 5120f3cb Panagiotis Kanavos
                }
675 9c4346c9 Panagiotis Kanavos
            }
676 5bcf6d70 Panagiotis Kanavos
        }
677 5bcf6d70 Panagiotis Kanavos
678 d15e99b4 Panagiotis Kanavos
 
679 cfed7823 Panagiotis Kanavos
        public bool ContainerExists(string account, string container)
680 d78cbf09 Panagiotis Kanavos
        {
681 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
682 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
683 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
684 cfed7823 Panagiotis Kanavos
685 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Containters"].Push("Exists"))
686 d78cbf09 Panagiotis Kanavos
            {
687 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
688 cfed7823 Panagiotis Kanavos
689 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
690 9c4346c9 Panagiotis Kanavos
                {
691 5120f3cb Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
692 5120f3cb Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
693 5120f3cb Panagiotis Kanavos
694 5120f3cb Panagiotis Kanavos
                    client.Parameters.Clear();
695 5120f3cb Panagiotis Kanavos
                    client.Head(container, 3);
696 5120f3cb Panagiotis Kanavos
                                        
697 5120f3cb Panagiotis Kanavos
                    bool result;
698 5120f3cb Panagiotis Kanavos
                    switch (client.StatusCode)
699 5120f3cb Panagiotis Kanavos
                    {
700 5120f3cb Panagiotis Kanavos
                        case HttpStatusCode.OK:
701 5120f3cb Panagiotis Kanavos
                        case HttpStatusCode.NoContent:
702 5120f3cb Panagiotis Kanavos
                            result=true;
703 5120f3cb Panagiotis Kanavos
                            break;
704 5120f3cb Panagiotis Kanavos
                        case HttpStatusCode.NotFound:
705 5120f3cb Panagiotis Kanavos
                            result=false;
706 5120f3cb Panagiotis Kanavos
                            break;
707 5120f3cb Panagiotis Kanavos
                        default:
708 5120f3cb Panagiotis Kanavos
                            throw CreateWebException("ContainerExists", client.StatusCode);
709 5120f3cb Panagiotis Kanavos
                    }
710 5120f3cb Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
711 5120f3cb Panagiotis Kanavos
712 5120f3cb Panagiotis Kanavos
                    return result;
713 9c4346c9 Panagiotis Kanavos
                }
714 5120f3cb Panagiotis Kanavos
                
715 d78cbf09 Panagiotis Kanavos
            }
716 d78cbf09 Panagiotis Kanavos
        }
717 d78cbf09 Panagiotis Kanavos
718 cfed7823 Panagiotis Kanavos
        public bool ObjectExists(string account, string container, string objectName)
719 d78cbf09 Panagiotis Kanavos
        {
720 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
721 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
722 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
723 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");
724 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
725 cfed7823 Panagiotis Kanavos
726 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
727 d78cbf09 Panagiotis Kanavos
            {
728 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
729 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
730 cfed7823 Panagiotis Kanavos
731 9c4346c9 Panagiotis Kanavos
                client.Parameters.Clear();
732 9c4346c9 Panagiotis Kanavos
                client.Head(container + "/" + objectName, 3);
733 9c4346c9 Panagiotis Kanavos
734 9c4346c9 Panagiotis Kanavos
                switch (client.StatusCode)
735 9c4346c9 Panagiotis Kanavos
                {
736 9c4346c9 Panagiotis Kanavos
                    case HttpStatusCode.OK:
737 9c4346c9 Panagiotis Kanavos
                    case HttpStatusCode.NoContent:
738 9c4346c9 Panagiotis Kanavos
                        return true;
739 9c4346c9 Panagiotis Kanavos
                    case HttpStatusCode.NotFound:
740 9c4346c9 Panagiotis Kanavos
                        return false;
741 9c4346c9 Panagiotis Kanavos
                    default:
742 9c4346c9 Panagiotis Kanavos
                        throw CreateWebException("ObjectExists", client.StatusCode);
743 9c4346c9 Panagiotis Kanavos
                }
744 d78cbf09 Panagiotis Kanavos
            }
745 9c4346c9 Panagiotis Kanavos
746 d78cbf09 Panagiotis Kanavos
        }
747 d78cbf09 Panagiotis Kanavos
748 cfed7823 Panagiotis Kanavos
        public ObjectInfo GetObjectInfo(string account, string container, string objectName)
749 d78cbf09 Panagiotis Kanavos
        {
750 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
751 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
752 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
753 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");
754 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
755 d78cbf09 Panagiotis Kanavos
756 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Objects"].Push("GetObjectInfo"))
757 5120f3cb Panagiotis Kanavos
            {                
758 5120f3cb Panagiotis Kanavos
759 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
760 9c4346c9 Panagiotis Kanavos
                {
761 5120f3cb Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
762 5120f3cb Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
763 5120f3cb Panagiotis Kanavos
                    try
764 5120f3cb Panagiotis Kanavos
                    {
765 5120f3cb Panagiotis Kanavos
                        client.Parameters.Clear();
766 d78cbf09 Panagiotis Kanavos
767 5120f3cb Panagiotis Kanavos
                        client.Head(container + "/" + objectName, 3);
768 d78cbf09 Panagiotis Kanavos
769 5120f3cb Panagiotis Kanavos
                        if (client.TimedOut)
770 5120f3cb Panagiotis Kanavos
                            return ObjectInfo.Empty;
771 9c4346c9 Panagiotis Kanavos
772 5120f3cb Panagiotis Kanavos
                        switch (client.StatusCode)
773 5120f3cb Panagiotis Kanavos
                        {
774 5120f3cb Panagiotis Kanavos
                            case HttpStatusCode.OK:
775 5120f3cb Panagiotis Kanavos
                            case HttpStatusCode.NoContent:
776 5120f3cb Panagiotis Kanavos
                                var keys = client.ResponseHeaders.AllKeys.AsQueryable();
777 c92e02f3 Panagiotis Kanavos
                                var tags = client.GetMeta("X-Object-Meta-");
778 5120f3cb Panagiotis Kanavos
                                var extensions = (from key in keys
779 5120f3cb Panagiotis Kanavos
                                                  where key.StartsWith("X-Object-") && !key.StartsWith("X-Object-Meta-")
780 5120f3cb Panagiotis Kanavos
                                                  select new {Name = key, Value = client.ResponseHeaders[key]})
781 5120f3cb Panagiotis Kanavos
                                    .ToDictionary(t => t.Name, t => t.Value);
782 f0947233 Panagiotis Kanavos
783 c92e02f3 Panagiotis Kanavos
                                var permissions=client.GetHeaderValue("X-Object-Sharing", true);
784 aba9e6d9 Panagiotis Kanavos
                                
785 aba9e6d9 Panagiotis Kanavos
                                
786 5120f3cb Panagiotis Kanavos
                                var info = new ObjectInfo
787 5120f3cb Panagiotis Kanavos
                                               {
788 7b0a5fec Panagiotis Kanavos
                                                   Account = account,
789 7b0a5fec Panagiotis Kanavos
                                                   Container = container,
790 5120f3cb Panagiotis Kanavos
                                                   Name = objectName,
791 43dd02a8 pkanavos
                                                   ETag = client.GetHeaderValue("ETag"),
792 43dd02a8 pkanavos
                                                   X_Object_Hash = client.GetHeaderValue("X-Object-Hash"),
793 5120f3cb Panagiotis Kanavos
                                                   Content_Type = client.GetHeaderValue("Content-Type"),
794 52e8e7d9 Panagiotis Kanavos
                                                   Bytes = Convert.ToInt64(client.GetHeaderValue("Content-Length",true)),
795 5120f3cb Panagiotis Kanavos
                                                   Tags = tags,
796 5120f3cb Panagiotis Kanavos
                                                   Last_Modified = client.LastModified,
797 aba9e6d9 Panagiotis Kanavos
                                                   Extensions = extensions,
798 aba9e6d9 Panagiotis Kanavos
                                                   ContentEncoding=client.GetHeaderValue("Content-Encoding",true),
799 aba9e6d9 Panagiotis Kanavos
                                                   ContendDisposition = client.GetHeaderValue("Content-Disposition",true),
800 aba9e6d9 Panagiotis Kanavos
                                                   Manifest=client.GetHeaderValue("X-Object-Manifest",true),
801 bb7717f5 pkanavos
                                                   PublicUrl=client.GetHeaderValue("X-Object-Public",true),  
802 bb7717f5 pkanavos
                                                   StorageUri=this.StorageUrl,
803 5120f3cb Panagiotis Kanavos
                                               };
804 f0947233 Panagiotis Kanavos
                                info.SetPermissions(permissions);
805 5120f3cb Panagiotis Kanavos
                                return info;
806 5120f3cb Panagiotis Kanavos
                            case HttpStatusCode.NotFound:
807 5120f3cb Panagiotis Kanavos
                                return ObjectInfo.Empty;
808 5120f3cb Panagiotis Kanavos
                            default:
809 5120f3cb Panagiotis Kanavos
                                throw new WebException(
810 5120f3cb Panagiotis Kanavos
                                    String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}",
811 5120f3cb Panagiotis Kanavos
                                                  objectName, client.StatusCode));
812 5120f3cb Panagiotis Kanavos
                        }
813 5120f3cb Panagiotis Kanavos
814 5120f3cb Panagiotis Kanavos
                    }
815 5120f3cb Panagiotis Kanavos
                    catch (RetryException)
816 9c4346c9 Panagiotis Kanavos
                    {
817 4f6d51d4 Panagiotis Kanavos
                        Log.WarnFormat("[RETRY FAIL] GetObjectInfo for {0} failed.",objectName);
818 5120f3cb Panagiotis Kanavos
                        return ObjectInfo.Empty;
819 9c4346c9 Panagiotis Kanavos
                    }
820 5120f3cb Panagiotis Kanavos
                    catch (WebException e)
821 5120f3cb Panagiotis Kanavos
                    {
822 5120f3cb Panagiotis Kanavos
                        Log.Error(
823 5120f3cb Panagiotis Kanavos
                            String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}",
824 5120f3cb Panagiotis Kanavos
                                          objectName, client.StatusCode), e);
825 5120f3cb Panagiotis Kanavos
                        throw;
826 5120f3cb Panagiotis Kanavos
                    }
827 5120f3cb Panagiotis Kanavos
                }                
828 d78cbf09 Panagiotis Kanavos
            }
829 9c4346c9 Panagiotis Kanavos
830 d78cbf09 Panagiotis Kanavos
        }
831 d78cbf09 Panagiotis Kanavos
832 cfed7823 Panagiotis Kanavos
        public void CreateFolder(string account, string container, string folder)
833 10523ad9 Panagiotis Kanavos
        {
834 10523ad9 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
835 10523ad9 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
836 10523ad9 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(folder))
837 10523ad9 Panagiotis Kanavos
                throw new ArgumentNullException("folder", "The folder property can't be empty");
838 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
839 10523ad9 Panagiotis Kanavos
840 10523ad9 Panagiotis Kanavos
            var folderUrl=String.Format("{0}/{1}",container,folder);
841 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
842 9c4346c9 Panagiotis Kanavos
            {
843 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
844 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
845 cfed7823 Panagiotis Kanavos
846 9c4346c9 Panagiotis Kanavos
                client.Parameters.Clear();
847 9c4346c9 Panagiotis Kanavos
                client.Headers.Add("Content-Type", @"application/directory");
848 9c4346c9 Panagiotis Kanavos
                client.Headers.Add("Content-Length", "0");
849 9c4346c9 Panagiotis Kanavos
                client.PutWithRetry(folderUrl, 3);
850 10523ad9 Panagiotis Kanavos
851 9c4346c9 Panagiotis Kanavos
                if (client.StatusCode != HttpStatusCode.Created && client.StatusCode != HttpStatusCode.Accepted)
852 9c4346c9 Panagiotis Kanavos
                    throw CreateWebException("CreateFolder", client.StatusCode);
853 9c4346c9 Panagiotis Kanavos
            }
854 10523ad9 Panagiotis Kanavos
        }
855 10523ad9 Panagiotis Kanavos
856 c92e02f3 Panagiotis Kanavos
     
857 c92e02f3 Panagiotis Kanavos
858 cfed7823 Panagiotis Kanavos
        public ContainerInfo GetContainerInfo(string account, string container)
859 d78cbf09 Panagiotis Kanavos
        {
860 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
861 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
862 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
863 cfed7823 Panagiotis Kanavos
864 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
865 d78cbf09 Panagiotis Kanavos
            {
866 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
867 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);                
868 cfed7823 Panagiotis Kanavos
869 9c4346c9 Panagiotis Kanavos
                client.Head(container);
870 9c4346c9 Panagiotis Kanavos
                switch (client.StatusCode)
871 9c4346c9 Panagiotis Kanavos
                {
872 5ce54458 Panagiotis Kanavos
                    case HttpStatusCode.OK:
873 9c4346c9 Panagiotis Kanavos
                    case HttpStatusCode.NoContent:
874 c92e02f3 Panagiotis Kanavos
                        var tags = client.GetMeta("X-Container-Meta-");
875 c92e02f3 Panagiotis Kanavos
                        var policies = client.GetMeta("X-Container-Policy-");
876 27361404 Panagiotis Kanavos
877 9c4346c9 Panagiotis Kanavos
                        var containerInfo = new ContainerInfo
878 9c4346c9 Panagiotis Kanavos
                                                {
879 42800be8 Panagiotis Kanavos
                                                    Account=account,
880 9c4346c9 Panagiotis Kanavos
                                                    Name = container,
881 ebc37b0d pkanavos
                                                    StorageUrl=this.StorageUrl.ToString(),
882 9c4346c9 Panagiotis Kanavos
                                                    Count =
883 9c4346c9 Panagiotis Kanavos
                                                        long.Parse(client.GetHeaderValue("X-Container-Object-Count")),
884 5ce54458 Panagiotis Kanavos
                                                    Bytes = long.Parse(client.GetHeaderValue("X-Container-Bytes-Used")),
885 5ce54458 Panagiotis Kanavos
                                                    BlockHash = client.GetHeaderValue("X-Container-Block-Hash"),
886 42800be8 Panagiotis Kanavos
                                                    BlockSize=int.Parse(client.GetHeaderValue("X-Container-Block-Size")),
887 27361404 Panagiotis Kanavos
                                                    Last_Modified=client.LastModified,
888 27361404 Panagiotis Kanavos
                                                    Tags=tags,
889 27361404 Panagiotis Kanavos
                                                    Policies=policies
890 9c4346c9 Panagiotis Kanavos
                                                };
891 27361404 Panagiotis Kanavos
                        
892 27361404 Panagiotis Kanavos
893 9c4346c9 Panagiotis Kanavos
                        return containerInfo;
894 9c4346c9 Panagiotis Kanavos
                    case HttpStatusCode.NotFound:
895 9c4346c9 Panagiotis Kanavos
                        return ContainerInfo.Empty;
896 9c4346c9 Panagiotis Kanavos
                    default:
897 9c4346c9 Panagiotis Kanavos
                        throw CreateWebException("GetContainerInfo", client.StatusCode);
898 9c4346c9 Panagiotis Kanavos
                }
899 d78cbf09 Panagiotis Kanavos
            }
900 d78cbf09 Panagiotis Kanavos
        }
901 d78cbf09 Panagiotis Kanavos
902 cfed7823 Panagiotis Kanavos
        public void CreateContainer(string account, string container)
903 b12f73e8 Panagiotis Kanavos
        {
904 b12f73e8 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(account))
905 b12f73e8 Panagiotis Kanavos
                throw new ArgumentNullException("account");
906 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
907 b12f73e8 Panagiotis Kanavos
                throw new ArgumentNullException("container");
908 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
909 cfed7823 Panagiotis Kanavos
910 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
911 9c4346c9 Panagiotis Kanavos
            {
912 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
913 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
914 cfed7823 Panagiotis Kanavos
915 9c4346c9 Panagiotis Kanavos
                client.PutWithRetry(container, 3);
916 9c4346c9 Panagiotis Kanavos
                var expectedCodes = new[] {HttpStatusCode.Created, HttpStatusCode.Accepted, HttpStatusCode.OK};
917 9c4346c9 Panagiotis Kanavos
                if (!expectedCodes.Contains(client.StatusCode))
918 9c4346c9 Panagiotis Kanavos
                    throw CreateWebException("CreateContainer", client.StatusCode);
919 9c4346c9 Panagiotis Kanavos
            }
920 d78cbf09 Panagiotis Kanavos
        }
921 d78cbf09 Panagiotis Kanavos
922 cfed7823 Panagiotis Kanavos
        public void DeleteContainer(string account, string container)
923 2c053915 Panagiotis Kanavos
        {
924 2c053915 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
925 2c053915 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
926 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
927 cfed7823 Panagiotis Kanavos
928 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
929 9c4346c9 Panagiotis Kanavos
            {
930 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
931 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
932 cfed7823 Panagiotis Kanavos
933 9c4346c9 Panagiotis Kanavos
                client.DeleteWithRetry(container, 3);
934 9c4346c9 Panagiotis Kanavos
                var expectedCodes = new[] {HttpStatusCode.NotFound, HttpStatusCode.NoContent};
935 9c4346c9 Panagiotis Kanavos
                if (!expectedCodes.Contains(client.StatusCode))
936 9c4346c9 Panagiotis Kanavos
                    throw CreateWebException("DeleteContainer", client.StatusCode);
937 9c4346c9 Panagiotis Kanavos
            }
938 2c053915 Panagiotis Kanavos
939 2c053915 Panagiotis Kanavos
        }
940 2c053915 Panagiotis Kanavos
941 5bcf6d70 Panagiotis Kanavos
        /// <summary>
942 5bcf6d70 Panagiotis Kanavos
        /// 
943 5bcf6d70 Panagiotis Kanavos
        /// </summary>
944 cfed7823 Panagiotis Kanavos
        /// <param name="account"></param>
945 5bcf6d70 Panagiotis Kanavos
        /// <param name="container"></param>
946 5bcf6d70 Panagiotis Kanavos
        /// <param name="objectName"></param>
947 283809f3 Panagiotis Kanavos
        /// <param name="fileName"></param>
948 5bcf6d70 Panagiotis Kanavos
        /// <returns></returns>
949 5ce54458 Panagiotis Kanavos
        /// <remarks>This method should have no timeout or a very long one</remarks>
950 5ce54458 Panagiotis Kanavos
        //Asynchronously download the object specified by *objectName* in a specific *container* to 
951 5ce54458 Panagiotis Kanavos
        // a local file
952 2341c603 pkanavos
        public async Task GetObject(string account, string container, string objectName, string fileName,CancellationToken cancellationToken)
953 d78cbf09 Panagiotis Kanavos
        {
954 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
955 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
956 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
957 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");            
958 5ce54458 Panagiotis Kanavos
            Contract.EndContractBlock();
959 5ce54458 Panagiotis Kanavos
960 283809f3 Panagiotis Kanavos
            try
961 283809f3 Panagiotis Kanavos
            {
962 5ce54458 Panagiotis Kanavos
                //WebClient, and by extension RestClient, are not thread-safe. Create a new RestClient
963 5ce54458 Panagiotis Kanavos
                //object to avoid concurrency errors.
964 5ce54458 Panagiotis Kanavos
                //
965 5ce54458 Panagiotis Kanavos
                //Download operations take a long time therefore they have no timeout.
966 2341c603 pkanavos
                using(var client = new RestClient(_baseClient) { Timeout = 0 })
967 2341c603 pkanavos
                {
968 2341c603 pkanavos
                    if (!String.IsNullOrWhiteSpace(account))
969 2341c603 pkanavos
                        client.BaseAddress = GetAccountUrl(account);
970 cfed7823 Panagiotis Kanavos
971 2341c603 pkanavos
                    //The container and objectName are relative names. They are joined with the client's
972 2341c603 pkanavos
                    //BaseAddress to create the object's absolute address
973 2341c603 pkanavos
                    var builder = client.GetAddressBuilder(container, objectName);
974 2341c603 pkanavos
                    var uri = builder.Uri;
975 cfed7823 Panagiotis Kanavos
976 2341c603 pkanavos
                    //Download progress is reported to the Trace log
977 2341c603 pkanavos
                    Log.InfoFormat("[GET] START {0}", objectName);
978 2341c603 pkanavos
                    client.DownloadProgressChanged += (sender, args) =>
979 2341c603 pkanavos
                                                      Log.InfoFormat("[GET PROGRESS] {0} {1}% {2} of {3}",
980 2341c603 pkanavos
                                                                     fileName, args.ProgressPercentage,
981 2341c603 pkanavos
                                                                     args.BytesReceived,
982 2341c603 pkanavos
                                                                     args.TotalBytesToReceive);
983 5ce54458 Panagiotis Kanavos
984 2341c603 pkanavos
                    
985 2341c603 pkanavos
                    //Start downloading the object asynchronously
986 2341c603 pkanavos
                    await client.DownloadFileTaskAsync(uri, fileName,cancellationToken);
987 5ce54458 Panagiotis Kanavos
988 2341c603 pkanavos
                    //Once the download completes
989 2341c603 pkanavos
                    //Delete the local client object
990 2341c603 pkanavos
                }
991 2341c603 pkanavos
                //And report failure or completion
992 283809f3 Panagiotis Kanavos
            }
993 283809f3 Panagiotis Kanavos
            catch (Exception exc)
994 d78cbf09 Panagiotis Kanavos
            {
995 2341c603 pkanavos
                Log.ErrorFormat("[GET] FAIL {0} with {1}", objectName, exc);
996 283809f3 Panagiotis Kanavos
                throw;
997 d78cbf09 Panagiotis Kanavos
            }
998 283809f3 Panagiotis Kanavos
999 2341c603 pkanavos
            Log.InfoFormat("[GET] END {0}", objectName);                                             
1000 283809f3 Panagiotis Kanavos
1001 283809f3 Panagiotis Kanavos
1002 d78cbf09 Panagiotis Kanavos
        }
1003 d78cbf09 Panagiotis Kanavos
1004 cfed7823 Panagiotis Kanavos
        public Task<IList<string>> PutHashMap(string account, string container, string objectName, TreeHash hash)
1005 5ce54458 Panagiotis Kanavos
        {
1006 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
1007 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("container");
1008 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
1009 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("objectName");
1010 5ce54458 Panagiotis Kanavos
            if (hash==null)
1011 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("hash");
1012 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
1013 5ce54458 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Token");
1014 5ce54458 Panagiotis Kanavos
            if (StorageUrl == null)
1015 5ce54458 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Storage Url");
1016 5ce54458 Panagiotis Kanavos
            Contract.EndContractBlock();
1017 cfed7823 Panagiotis Kanavos
1018 cfed7823 Panagiotis Kanavos
1019 cfed7823 Panagiotis Kanavos
            //Don't use a timeout because putting the hashmap may be a long process
1020 692ec33b Panagiotis Kanavos
            var client = new RestClient(_baseClient) { Timeout = 0 };           
1021 cfed7823 Panagiotis Kanavos
            if (!String.IsNullOrWhiteSpace(account))
1022 cfed7823 Panagiotis Kanavos
                client.BaseAddress = GetAccountUrl(account);
1023 cfed7823 Panagiotis Kanavos
1024 5ce54458 Panagiotis Kanavos
            //The container and objectName are relative names. They are joined with the client's
1025 5ce54458 Panagiotis Kanavos
            //BaseAddress to create the object's absolute address
1026 cfed7823 Panagiotis Kanavos
            var builder = client.GetAddressBuilder(container, objectName);
1027 5ce54458 Panagiotis Kanavos
            builder.Query = "format=json&hashmap";
1028 5ce54458 Panagiotis Kanavos
            var uri = builder.Uri;
1029 5ce54458 Panagiotis Kanavos
1030 5ce54458 Panagiotis Kanavos
1031 5ce54458 Panagiotis Kanavos
            //Send the tree hash as Json to the server            
1032 5ce54458 Panagiotis Kanavos
            client.Headers[HttpRequestHeader.ContentType] = "application/octet-stream";
1033 692ec33b Panagiotis Kanavos
            var jsonHash = hash.ToJson();
1034 c945b450 pkanavos
                        
1035 c945b450 pkanavos
            client.Headers.Add("ETag",hash.MD5);
1036 692ec33b Panagiotis Kanavos
            var uploadTask=client.UploadStringTask(uri, "PUT", jsonHash);
1037 72174cd5 pkanavos
            if (Log.IsDebugEnabled)
1038 72174cd5 pkanavos
                Log.DebugFormat("Hashes:\r\n{0}", jsonHash);
1039 5ce54458 Panagiotis Kanavos
            return uploadTask.ContinueWith(t =>
1040 5ce54458 Panagiotis Kanavos
            {
1041 a27aa447 Panagiotis Kanavos
1042 a27aa447 Panagiotis Kanavos
                var empty = (IList<string>)new List<string>();
1043 5ce54458 Panagiotis Kanavos
                
1044 5ce54458 Panagiotis Kanavos
1045 5ce54458 Panagiotis Kanavos
                //The server will respond either with 201-created if all blocks were already on the server
1046 a27aa447 Panagiotis Kanavos
                if (client.StatusCode == HttpStatusCode.Created)                    
1047 a27aa447 Panagiotis Kanavos
                {
1048 5ce54458 Panagiotis Kanavos
                    //in which case we return an empty hash list
1049 a27aa447 Panagiotis Kanavos
                    return empty;
1050 a27aa447 Panagiotis Kanavos
                }
1051 5ce54458 Panagiotis Kanavos
                //or with a 409-conflict and return the list of missing parts
1052 5ce54458 Panagiotis Kanavos
                //A 409 will cause an exception so we need to check t.IsFaulted to avoid propagating the exception                
1053 5ce54458 Panagiotis Kanavos
                if (t.IsFaulted)
1054 5ce54458 Panagiotis Kanavos
                {
1055 5ce54458 Panagiotis Kanavos
                    var ex = t.Exception.InnerException;
1056 5ce54458 Panagiotis Kanavos
                    var we = ex as WebException;
1057 5ce54458 Panagiotis Kanavos
                    var response = we.Response as HttpWebResponse;
1058 5ce54458 Panagiotis Kanavos
                    if (response!=null && response.StatusCode==HttpStatusCode.Conflict)
1059 5ce54458 Panagiotis Kanavos
                    {
1060 5ce54458 Panagiotis Kanavos
                        //In case of 409 the missing parts will be in the response content                        
1061 5ce54458 Panagiotis Kanavos
                        using (var stream = response.GetResponseStream())
1062 ebc37b0d pkanavos
                        using(var reader=stream.GetLoggedReader(Log))
1063 5ce54458 Panagiotis Kanavos
                        {
1064 d9b1cbeb Panagiotis Kanavos
                            //We used to have to cleanup the content before returning it because it contains
1065 a27aa447 Panagiotis Kanavos
                            //error content after the list of hashes
1066 d9b1cbeb Panagiotis Kanavos
                            //
1067 d9b1cbeb Panagiotis Kanavos
                            //As of 30/1/2012, the result is a proper Json array so we don't need to read the content
1068 d9b1cbeb Panagiotis Kanavos
                            //line by line
1069 d9b1cbeb Panagiotis Kanavos
                            
1070 d9b1cbeb Panagiotis Kanavos
                            var serializer = new JsonSerializer();                            
1071 739664d2 pkanavos
                            serializer.Error += (sender, args) => Log.ErrorFormat("Deserialization error at [{0}] [{1}]", args.ErrorContext.Error, args.ErrorContext.Member);
1072 72174cd5 pkanavos
                            var hashes = (List<string>)serializer.Deserialize(reader, typeof(List<string>));
1073 72174cd5 pkanavos
                            return hashes;
1074 5ce54458 Panagiotis Kanavos
                        }                        
1075 4f6d51d4 Panagiotis Kanavos
                    }                    
1076 4f6d51d4 Panagiotis Kanavos
                    //Any other status code is unexpected and the exception should be rethrown
1077 72174cd5 pkanavos
                    Log.LogError(response);
1078 4f6d51d4 Panagiotis Kanavos
                    throw ex;
1079 5ce54458 Panagiotis Kanavos
                    
1080 5ce54458 Panagiotis Kanavos
                }
1081 d78d765c pkanavos
1082 5ce54458 Panagiotis Kanavos
                //Any other status code is unexpected but there was no exception. We can probably continue processing
1083 4f6d51d4 Panagiotis Kanavos
                Log.WarnFormat("Unexcpected status code when putting map: {0} - {1}",client.StatusCode,client.StatusDescription);                    
1084 4f6d51d4 Panagiotis Kanavos
                
1085 a27aa447 Panagiotis Kanavos
                return empty;
1086 5ce54458 Panagiotis Kanavos
            });
1087 5ce54458 Panagiotis Kanavos
1088 5ce54458 Panagiotis Kanavos
        }
1089 5ce54458 Panagiotis Kanavos
1090 2341c603 pkanavos
1091 2341c603 pkanavos
        public async Task<byte[]> GetBlock(string account, string container, Uri relativeUrl, long start, long? end, CancellationToken cancellationToken)
1092 a27aa447 Panagiotis Kanavos
        {
1093 a27aa447 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
1094 a27aa447 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Token");
1095 a27aa447 Panagiotis Kanavos
            if (StorageUrl == null)
1096 a27aa447 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Storage Url");
1097 a27aa447 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
1098 a27aa447 Panagiotis Kanavos
                throw new ArgumentNullException("container");
1099 2341c603 pkanavos
            if (relativeUrl == null)
1100 a27aa447 Panagiotis Kanavos
                throw new ArgumentNullException("relativeUrl");
1101 2341c603 pkanavos
            if (end.HasValue && end < 0)
1102 a27aa447 Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("end");
1103 2341c603 pkanavos
            if (start < 0)
1104 a27aa447 Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("start");
1105 a27aa447 Panagiotis Kanavos
            Contract.EndContractBlock();
1106 a27aa447 Panagiotis Kanavos
1107 a27aa447 Panagiotis Kanavos
            //Don't use a timeout because putting the hashmap may be a long process
1108 2341c603 pkanavos
            using (var client = new RestClient(_baseClient) {Timeout = 0, RangeFrom = start, RangeTo = end})
1109 2341c603 pkanavos
            {
1110 2341c603 pkanavos
                if (!String.IsNullOrWhiteSpace(account))
1111 2341c603 pkanavos
                    client.BaseAddress = GetAccountUrl(account);
1112 cfed7823 Panagiotis Kanavos
1113 2341c603 pkanavos
                var builder = client.GetAddressBuilder(container, relativeUrl.ToString());
1114 2341c603 pkanavos
                var uri = builder.Uri;
1115 97edb52f pkanavos
                
1116 97edb52f pkanavos
                client.DownloadProgressChanged += (sender, args) =>
1117 97edb52f pkanavos
                                  Log.DebugFormat("[GET PROGRESS] {0} {1}% {2} of {3}",
1118 97edb52f pkanavos
                                                 uri.Segments.Last(), args.ProgressPercentage,
1119 97edb52f pkanavos
                                                 args.BytesReceived,
1120 97edb52f pkanavos
                                                 args.TotalBytesToReceive);
1121 97edb52f pkanavos
1122 cfed7823 Panagiotis Kanavos
1123 2341c603 pkanavos
                var result = await client.DownloadDataTaskAsync(uri, cancellationToken);
1124 2341c603 pkanavos
                return result;
1125 2341c603 pkanavos
            }
1126 a27aa447 Panagiotis Kanavos
        }
1127 a27aa447 Panagiotis Kanavos
1128 a27aa447 Panagiotis Kanavos
1129 fbe71a05 pkanavos
        public async Task PostBlock(string account, string container, byte[] block, int offset, int count,CancellationToken token)
1130 a27aa447 Panagiotis Kanavos
        {
1131 a27aa447 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
1132 a27aa447 Panagiotis Kanavos
                throw new ArgumentNullException("container");
1133 a27aa447 Panagiotis Kanavos
            if (block == null)
1134 a27aa447 Panagiotis Kanavos
                throw new ArgumentNullException("block");
1135 0af3141d Panagiotis Kanavos
            if (offset < 0 || offset >= block.Length)
1136 0af3141d Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("offset");
1137 0af3141d Panagiotis Kanavos
            if (count < 0 || count > block.Length)
1138 0af3141d Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("count");
1139 a27aa447 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
1140 a27aa447 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Token");
1141 a27aa447 Panagiotis Kanavos
            if (StorageUrl == null)
1142 0af3141d Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Storage Url");                        
1143 a27aa447 Panagiotis Kanavos
            Contract.EndContractBlock();
1144 a27aa447 Panagiotis Kanavos
1145 cfed7823 Panagiotis Kanavos
1146 4f6d51d4 Panagiotis Kanavos
            try
1147 4f6d51d4 Panagiotis Kanavos
            {
1148 cfed7823 Panagiotis Kanavos
1149 fbe71a05 pkanavos
                //Don't use a timeout because putting the hashmap may be a long process
1150 4f6d51d4 Panagiotis Kanavos
                using (var client = new RestClient(_baseClient) { Timeout = 0 })
1151 fbe71a05 pkanavos
                {
1152 4f6d51d4 Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
1153 4f6d51d4 Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
1154 4f6d51d4 Panagiotis Kanavos
1155 fbe71a05 pkanavos
                    token.Register(client.CancelAsync);
1156 fbe71a05 pkanavos
1157 4f6d51d4 Panagiotis Kanavos
                    var builder = client.GetAddressBuilder(container, "");
1158 4f6d51d4 Panagiotis Kanavos
                    //We are doing an update
1159 4f6d51d4 Panagiotis Kanavos
                    builder.Query = "update";
1160 4f6d51d4 Panagiotis Kanavos
                    var uri = builder.Uri;
1161 a27aa447 Panagiotis Kanavos
1162 4f6d51d4 Panagiotis Kanavos
                    client.Headers[HttpRequestHeader.ContentType] = "application/octet-stream";
1163 a27aa447 Panagiotis Kanavos
1164 4f6d51d4 Panagiotis Kanavos
                    Log.InfoFormat("[BLOCK POST] START");
1165 a27aa447 Panagiotis Kanavos
1166 4f6d51d4 Panagiotis Kanavos
                    client.UploadProgressChanged += (sender, args) =>
1167 4f6d51d4 Panagiotis Kanavos
                                                    Log.InfoFormat("[BLOCK POST PROGRESS] {0}% {1} of {2}",
1168 4f6d51d4 Panagiotis Kanavos
                                                                   args.ProgressPercentage, args.BytesSent,
1169 4f6d51d4 Panagiotis Kanavos
                                                                   args.TotalBytesToSend);
1170 4f6d51d4 Panagiotis Kanavos
                    client.UploadFileCompleted += (sender, args) =>
1171 4f6d51d4 Panagiotis Kanavos
                                                  Log.InfoFormat("[BLOCK POST PROGRESS] Completed ");
1172 a27aa447 Panagiotis Kanavos
1173 4f6d51d4 Panagiotis Kanavos
                    var buffer = new byte[count];
1174 4f6d51d4 Panagiotis Kanavos
                    Buffer.BlockCopy(block, offset, buffer, 0, count);
1175 4f6d51d4 Panagiotis Kanavos
                    //Send the block
1176 fbe71a05 pkanavos
                    await client.UploadDataTaskAsync(uri, "POST", buffer);
1177 4f6d51d4 Panagiotis Kanavos
                    Log.InfoFormat("[BLOCK POST] END");
1178 a64c87c8 Panagiotis Kanavos
                }
1179 4f6d51d4 Panagiotis Kanavos
            }
1180 fbe71a05 pkanavos
            catch (TaskCanceledException )
1181 fbe71a05 pkanavos
            {
1182 fbe71a05 pkanavos
                Log.Info("Aborting block");
1183 fbe71a05 pkanavos
                throw;
1184 fbe71a05 pkanavos
            }
1185 4f6d51d4 Panagiotis Kanavos
            catch (Exception exc)
1186 4f6d51d4 Panagiotis Kanavos
            {
1187 fbe71a05 pkanavos
                Log.ErrorFormat("[BLOCK POST] FAIL with \r{0}", exc);
1188 4f6d51d4 Panagiotis Kanavos
                throw;
1189 4f6d51d4 Panagiotis Kanavos
            }
1190 a27aa447 Panagiotis Kanavos
        }
1191 a27aa447 Panagiotis Kanavos
1192 5ce54458 Panagiotis Kanavos
1193 a0dcfcc9 Panagiotis Kanavos
        public async Task<TreeHash> GetHashMap(string account, string container, string objectName)
1194 5ce54458 Panagiotis Kanavos
        {
1195 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
1196 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("container");
1197 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
1198 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("objectName");
1199 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
1200 5ce54458 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Token");
1201 5ce54458 Panagiotis Kanavos
            if (StorageUrl == null)
1202 5ce54458 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Storage Url");
1203 5ce54458 Panagiotis Kanavos
            Contract.EndContractBlock();
1204 5ce54458 Panagiotis Kanavos
1205 5ce54458 Panagiotis Kanavos
            try
1206 5ce54458 Panagiotis Kanavos
            {
1207 5ce54458 Panagiotis Kanavos
                //WebClient, and by extension RestClient, are not thread-safe. Create a new RestClient
1208 5ce54458 Panagiotis Kanavos
                //object to avoid concurrency errors.
1209 5ce54458 Panagiotis Kanavos
                //
1210 5ce54458 Panagiotis Kanavos
                //Download operations take a long time therefore they have no timeout.
1211 a0dcfcc9 Panagiotis Kanavos
                //TODO: Do they really? this is a hashmap operation, not a download
1212 cfed7823 Panagiotis Kanavos
                
1213 5ce54458 Panagiotis Kanavos
                //Start downloading the object asynchronously
1214 a0dcfcc9 Panagiotis Kanavos
                using (var client = new RestClient(_baseClient) { Timeout = 0 })
1215 5ce54458 Panagiotis Kanavos
                {
1216 a0dcfcc9 Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
1217 a0dcfcc9 Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
1218 a0dcfcc9 Panagiotis Kanavos
1219 a0dcfcc9 Panagiotis Kanavos
                    //The container and objectName are relative names. They are joined with the client's
1220 a0dcfcc9 Panagiotis Kanavos
                    //BaseAddress to create the object's absolute address
1221 a0dcfcc9 Panagiotis Kanavos
                    var builder = client.GetAddressBuilder(container, objectName);
1222 a0dcfcc9 Panagiotis Kanavos
                    builder.Query = "format=json&hashmap";
1223 a0dcfcc9 Panagiotis Kanavos
                    var uri = builder.Uri;
1224 a0dcfcc9 Panagiotis Kanavos
1225 a0dcfcc9 Panagiotis Kanavos
1226 a0dcfcc9 Panagiotis Kanavos
                    var json = await client.DownloadStringTaskAsync(uri);
1227 5ce54458 Panagiotis Kanavos
                    var treeHash = TreeHash.Parse(json);
1228 a0dcfcc9 Panagiotis Kanavos
                    Log.InfoFormat("[GET HASH] END {0}", objectName);
1229 5ce54458 Panagiotis Kanavos
                    return treeHash;
1230 a0dcfcc9 Panagiotis Kanavos
                }
1231 5ce54458 Panagiotis Kanavos
            }
1232 5ce54458 Panagiotis Kanavos
            catch (Exception exc)
1233 5ce54458 Panagiotis Kanavos
            {
1234 5120f3cb Panagiotis Kanavos
                Log.ErrorFormat("[GET HASH] END {0} with {1}", objectName, exc);
1235 5ce54458 Panagiotis Kanavos
                throw;
1236 5ce54458 Panagiotis Kanavos
            }
1237 5ce54458 Panagiotis Kanavos
1238 5ce54458 Panagiotis Kanavos
        }
1239 5ce54458 Panagiotis Kanavos
1240 5ce54458 Panagiotis Kanavos
1241 5bcf6d70 Panagiotis Kanavos
        /// <summary>
1242 5bcf6d70 Panagiotis Kanavos
        /// 
1243 5bcf6d70 Panagiotis Kanavos
        /// </summary>
1244 cfed7823 Panagiotis Kanavos
        /// <param name="account"></param>
1245 5bcf6d70 Panagiotis Kanavos
        /// <param name="container"></param>
1246 5bcf6d70 Panagiotis Kanavos
        /// <param name="objectName"></param>
1247 5bcf6d70 Panagiotis Kanavos
        /// <param name="fileName"></param>
1248 b5061ac8 Panagiotis Kanavos
        /// <param name="hash">Optional hash value for the file. If no hash is provided, the method calculates a new hash</param>
1249 5bcf6d70 Panagiotis Kanavos
        /// <remarks>>This method should have no timeout or a very long one</remarks>
1250 4f6d51d4 Panagiotis Kanavos
        public async Task PutObject(string account, string container, string objectName, string fileName, string hash = null, string contentType = "application/octet-stream")
1251 d78cbf09 Panagiotis Kanavos
        {
1252 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
1253 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
1254 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
1255 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");
1256 b6c72f62 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(fileName))
1257 b6c72f62 Panagiotis Kanavos
                throw new ArgumentNullException("fileName", "The fileName property can't be empty");
1258 4f6d51d4 Panagiotis Kanavos
/*
1259 4f6d51d4 Panagiotis Kanavos
            if (!File.Exists(fileName) && !Directory.Exists(fileName))
1260 4f6d51d4 Panagiotis Kanavos
                throw new FileNotFoundException("The file or directory does not exist",fileName);
1261 4f6d51d4 Panagiotis Kanavos
*/
1262 b6c72f62 Panagiotis Kanavos
            
1263 b5061ac8 Panagiotis Kanavos
            try
1264 b5061ac8 Panagiotis Kanavos
            {
1265 cfed7823 Panagiotis Kanavos
1266 4f6d51d4 Panagiotis Kanavos
                using (var client = new RestClient(_baseClient) { Timeout = 0 })
1267 0eea575a Panagiotis Kanavos
                {
1268 4f6d51d4 Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
1269 4f6d51d4 Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
1270 bfc13ed8 Panagiotis Kanavos
1271 4f6d51d4 Panagiotis Kanavos
                    var builder = client.GetAddressBuilder(container, objectName);
1272 4f6d51d4 Panagiotis Kanavos
                    var uri = builder.Uri;
1273 0eea575a Panagiotis Kanavos
1274 4f6d51d4 Panagiotis Kanavos
                    string etag = hash ?? CalculateHash(fileName);
1275 4f6d51d4 Panagiotis Kanavos
1276 4f6d51d4 Panagiotis Kanavos
                    client.Headers.Add("Content-Type", contentType);
1277 4f6d51d4 Panagiotis Kanavos
                    client.Headers.Add("ETag", etag);
1278 4f6d51d4 Panagiotis Kanavos
1279 4f6d51d4 Panagiotis Kanavos
1280 4f6d51d4 Panagiotis Kanavos
                    Log.InfoFormat("[PUT] START {0}", objectName);
1281 4f6d51d4 Panagiotis Kanavos
                    client.UploadProgressChanged += (sender, args) =>
1282 4f6d51d4 Panagiotis Kanavos
                                                        {
1283 4f6d51d4 Panagiotis Kanavos
                                                            using (ThreadContext.Stacks["PUT"].Push("Progress"))
1284 4f6d51d4 Panagiotis Kanavos
                                                            {
1285 4f6d51d4 Panagiotis Kanavos
                                                                Log.InfoFormat("{0} {1}% {2} of {3}", fileName,
1286 4f6d51d4 Panagiotis Kanavos
                                                                               args.ProgressPercentage,
1287 4f6d51d4 Panagiotis Kanavos
                                                                               args.BytesSent, args.TotalBytesToSend);
1288 4f6d51d4 Panagiotis Kanavos
                                                            }
1289 4f6d51d4 Panagiotis Kanavos
                                                        };
1290 4f6d51d4 Panagiotis Kanavos
1291 4f6d51d4 Panagiotis Kanavos
                    client.UploadFileCompleted += (sender, args) =>
1292 4f6d51d4 Panagiotis Kanavos
                                                      {
1293 4f6d51d4 Panagiotis Kanavos
                                                          using (ThreadContext.Stacks["PUT"].Push("Progress"))
1294 4f6d51d4 Panagiotis Kanavos
                                                          {
1295 4f6d51d4 Panagiotis Kanavos
                                                              Log.InfoFormat("Completed {0}", fileName);
1296 4f6d51d4 Panagiotis Kanavos
                                                          }
1297 2341c603 pkanavos
                                                      };                    
1298 4f6d51d4 Panagiotis Kanavos
                    if (contentType=="application/directory")
1299 4f6d51d4 Panagiotis Kanavos
                        await client.UploadDataTaskAsync(uri, "PUT", new byte[0]);
1300 4f6d51d4 Panagiotis Kanavos
                    else
1301 4f6d51d4 Panagiotis Kanavos
                        await client.UploadFileTaskAsync(uri, "PUT", fileName);
1302 4f6d51d4 Panagiotis Kanavos
                }
1303 4f6d51d4 Panagiotis Kanavos
1304 4f6d51d4 Panagiotis Kanavos
                Log.InfoFormat("[PUT] END {0}", objectName);
1305 b5061ac8 Panagiotis Kanavos
            }
1306 b5061ac8 Panagiotis Kanavos
            catch (Exception exc)
1307 b5061ac8 Panagiotis Kanavos
            {
1308 5120f3cb Panagiotis Kanavos
                Log.ErrorFormat("[PUT] END {0} with {1}", objectName, exc);
1309 b5061ac8 Panagiotis Kanavos
                throw;
1310 b5061ac8 Panagiotis Kanavos
            }                
1311 b5061ac8 Panagiotis Kanavos
1312 0eea575a Panagiotis Kanavos
        }
1313 0050438e Panagiotis Kanavos
       
1314 4d301e8e Panagiotis Kanavos
        
1315 b6c72f62 Panagiotis Kanavos
        private static string CalculateHash(string fileName)
1316 d78cbf09 Panagiotis Kanavos
        {
1317 0bd56b7c Panagiotis Kanavos
            Contract.Requires(!String.IsNullOrWhiteSpace(fileName));
1318 0bd56b7c Panagiotis Kanavos
            Contract.EndContractBlock();
1319 0bd56b7c Panagiotis Kanavos
1320 d78cbf09 Panagiotis Kanavos
            string hash;
1321 d78cbf09 Panagiotis Kanavos
            using (var hasher = MD5.Create())
1322 b6c72f62 Panagiotis Kanavos
            using(var stream=File.OpenRead(fileName))
1323 d78cbf09 Panagiotis Kanavos
            {
1324 d78cbf09 Panagiotis Kanavos
                var hashBuilder=new StringBuilder();
1325 b6c72f62 Panagiotis Kanavos
                foreach (byte b in hasher.ComputeHash(stream))
1326 d78cbf09 Panagiotis Kanavos
                    hashBuilder.Append(b.ToString("x2").ToLower());
1327 d78cbf09 Panagiotis Kanavos
                hash = hashBuilder.ToString();                
1328 d78cbf09 Panagiotis Kanavos
            }
1329 d78cbf09 Panagiotis Kanavos
            return hash;
1330 d78cbf09 Panagiotis Kanavos
        }
1331 0bd56b7c Panagiotis Kanavos
        
1332 cfed7823 Panagiotis Kanavos
        public void MoveObject(string account, string sourceContainer, string oldObjectName, string targetContainer, string newObjectName)
1333 d78cbf09 Panagiotis Kanavos
        {
1334 3c43ec9b Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(sourceContainer))
1335 3c43ec9b Panagiotis Kanavos
                throw new ArgumentNullException("sourceContainer", "The container property can't be empty");
1336 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(oldObjectName))
1337 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("oldObjectName", "The oldObjectName property can't be empty");
1338 3c43ec9b Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(targetContainer))
1339 3c43ec9b Panagiotis Kanavos
                throw new ArgumentNullException("targetContainer", "The container property can't be empty");
1340 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(newObjectName))
1341 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("newObjectName", "The newObjectName property can't be empty");
1342 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
1343 d78cbf09 Panagiotis Kanavos
1344 3c43ec9b Panagiotis Kanavos
            var targetUrl = targetContainer + "/" + newObjectName;
1345 3c43ec9b Panagiotis Kanavos
            var sourceUrl = String.Format("/{0}/{1}", sourceContainer, oldObjectName);
1346 3c43ec9b Panagiotis Kanavos
1347 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
1348 d78cbf09 Panagiotis Kanavos
            {
1349 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
1350 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
1351 cfed7823 Panagiotis Kanavos
1352 0af3141d Panagiotis Kanavos
                client.Headers.Add("X-Move-From", sourceUrl);
1353 9c4346c9 Panagiotis Kanavos
                client.PutWithRetry(targetUrl, 3);
1354 9c4346c9 Panagiotis Kanavos
1355 9c4346c9 Panagiotis Kanavos
                var expectedCodes = new[] {HttpStatusCode.OK, HttpStatusCode.NoContent, HttpStatusCode.Created};
1356 0af3141d Panagiotis Kanavos
                if (!expectedCodes.Contains(client.StatusCode))
1357 9c4346c9 Panagiotis Kanavos
                    throw CreateWebException("MoveObject", client.StatusCode);
1358 9c4346c9 Panagiotis Kanavos
            }
1359 d78cbf09 Panagiotis Kanavos
        }
1360 d78cbf09 Panagiotis Kanavos
1361 c53aa229 Panagiotis Kanavos
        public void DeleteObject(string account, string sourceContainer, string objectName)
1362 0af3141d Panagiotis Kanavos
        {            
1363 0af3141d Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(sourceContainer))
1364 0af3141d Panagiotis Kanavos
                throw new ArgumentNullException("sourceContainer", "The container property can't be empty");
1365 0af3141d Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
1366 0af3141d Panagiotis Kanavos
                throw new ArgumentNullException("objectName", "The oldObjectName property can't be empty");
1367 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
1368 0af3141d Panagiotis Kanavos
1369 c53aa229 Panagiotis Kanavos
            var targetUrl = FolderConstants.TrashContainer + "/" + objectName;
1370 0af3141d Panagiotis Kanavos
            var sourceUrl = String.Format("/{0}/{1}", sourceContainer, objectName);
1371 0af3141d Panagiotis Kanavos
1372 0af3141d Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
1373 0af3141d Panagiotis Kanavos
            {
1374 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
1375 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
1376 cfed7823 Panagiotis Kanavos
1377 0af3141d Panagiotis Kanavos
                client.Headers.Add("X-Move-From", sourceUrl);
1378 c53aa229 Panagiotis Kanavos
                client.AllowedStatusCodes.Add(HttpStatusCode.NotFound);
1379 6f03d6e1 Panagiotis Kanavos
                Log.InfoFormat("[TRASH] [{0}] to [{1}]",sourceUrl,targetUrl);
1380 0af3141d Panagiotis Kanavos
                client.PutWithRetry(targetUrl, 3);
1381 0af3141d Panagiotis Kanavos
1382 0af3141d Panagiotis Kanavos
                var expectedCodes = new[] {HttpStatusCode.OK, HttpStatusCode.NoContent, HttpStatusCode.Created,HttpStatusCode.NotFound};
1383 0af3141d Panagiotis Kanavos
                if (!expectedCodes.Contains(client.StatusCode))
1384 0af3141d Panagiotis Kanavos
                    throw CreateWebException("DeleteObject", client.StatusCode);
1385 0af3141d Panagiotis Kanavos
            }
1386 0af3141d Panagiotis Kanavos
        }
1387 0af3141d Panagiotis Kanavos
1388 4d301e8e Panagiotis Kanavos
      
1389 3c43ec9b Panagiotis Kanavos
        private static WebException CreateWebException(string operation, HttpStatusCode statusCode)
1390 3c43ec9b Panagiotis Kanavos
        {
1391 3c43ec9b Panagiotis Kanavos
            return new WebException(String.Format("{0} failed with unexpected status code {1}", operation, statusCode));
1392 3c43ec9b Panagiotis Kanavos
        }
1393 3c43ec9b Panagiotis Kanavos
1394 93dc3a84 Panagiotis Kanavos
1395 93dc3a84 Panagiotis Kanavos
/*
1396 93dc3a84 Panagiotis Kanavos
        public IEnumerable<ObjectInfo> ListDirectories(ContainerInfo container)
1397 93dc3a84 Panagiotis Kanavos
        {
1398 93dc3a84 Panagiotis Kanavos
            var directories=this.ListObjects(container.Account, container.Name, "/");
1399 93dc3a84 Panagiotis Kanavos
        }
1400 93dc3a84 Panagiotis Kanavos
*/
1401 8f918cb0 pkanavos
1402 8f918cb0 pkanavos
        public bool CanUpload(string account, ObjectInfo cloudFile)
1403 8f918cb0 pkanavos
        {
1404 8f918cb0 pkanavos
            Contract.Requires(!String.IsNullOrWhiteSpace(account));
1405 8f918cb0 pkanavos
            Contract.Requires(cloudFile!=null);
1406 8f918cb0 pkanavos
1407 8f918cb0 pkanavos
            using (var client = new RestClient(_baseClient))
1408 8f918cb0 pkanavos
            {
1409 8f918cb0 pkanavos
                if (!String.IsNullOrWhiteSpace(account))
1410 8f918cb0 pkanavos
                    client.BaseAddress = GetAccountUrl(account);
1411 8f918cb0 pkanavos
1412 8f918cb0 pkanavos
1413 8f918cb0 pkanavos
                var parts = cloudFile.Name.Split('/');
1414 8f918cb0 pkanavos
                var folder = String.Join("/", parts,0,parts.Length-1);
1415 8f918cb0 pkanavos
1416 8f918cb0 pkanavos
                var fileUrl=String.Format("{0}/{1}/{2}.pithos.ignore",cloudFile.Container,folder,Guid.NewGuid());
1417 8f918cb0 pkanavos
1418 8f918cb0 pkanavos
                client.Parameters.Clear();
1419 8f918cb0 pkanavos
                try
1420 8f918cb0 pkanavos
                {
1421 8f918cb0 pkanavos
                    client.PutWithRetry(fileUrl, 3, @"application/octet-stream");
1422 8f918cb0 pkanavos
1423 8f918cb0 pkanavos
                    var expectedCodes = new[] { HttpStatusCode.OK, HttpStatusCode.NoContent, HttpStatusCode.Created};
1424 69588a95 pkanavos
                    var result=(expectedCodes.Contains(client.StatusCode));
1425 69588a95 pkanavos
                    DeleteObject(account, cloudFile.Container, fileUrl);
1426 69588a95 pkanavos
                    return result;
1427 8f918cb0 pkanavos
                }
1428 8f918cb0 pkanavos
                catch
1429 8f918cb0 pkanavos
                {
1430 8f918cb0 pkanavos
                    return false;
1431 8f918cb0 pkanavos
                }
1432 8f918cb0 pkanavos
            }
1433 8f918cb0 pkanavos
        }
1434 d78cbf09 Panagiotis Kanavos
    }
1435 cfed7823 Panagiotis Kanavos
1436 cfed7823 Panagiotis Kanavos
    public class ShareAccountInfo
1437 cfed7823 Panagiotis Kanavos
    {
1438 cfed7823 Panagiotis Kanavos
        public DateTime? last_modified { get; set; }
1439 cfed7823 Panagiotis Kanavos
        public string name { get; set; }
1440 cfed7823 Panagiotis Kanavos
    }
1441 d78cbf09 Panagiotis Kanavos
}