Added treehash calculation
[pithos-ms-client] / trunk / Pithos.Network / docs / restclient.html
1 <!DOCTYPE html />
2
3 <html>
4 <head>
5         <title>RestClient.cs</title>
6         <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
7         <link href="focco.css" rel="stylesheet" media="all" type="text/css" />
8         <script src="prettify.js" type="text/javascript"></script>
9 </head>
10 <body onload="prettyPrint()">
11         <div id="container">
12                 <div id="background"></div>
13                         <div id="jump_to">
14                                 Jump To &hellip;
15                                 <div id="jump_wrapper">
16                                         <div id="jump_page">
17                                                         <a class="source" href="cloudfilesclient.html">
18                                                                 CloudFilesClient.cs
19                                                         </a>
20                                                         <a class="source" href="restclient.html">
21                                                                 RestClient.cs
22                                                         </a>
23                                                         <a class="source" href="timeoutretrycondition.html">
24                                                                 TimeoutRetryCondition.cs
25                                                         </a>
26                                                         <a class="source" href="properties/assemblyinfo.html">
27                                                                 Properties\AssemblyInfo.cs
28                                                         </a>
29                                         </div>
30                                 </div>
31                         </div>
32                 <table cellpadding="0" cellspacing="0">
33                         <thead>
34                                 <tr>
35                                         <th class="docs">
36                                                 <h1>RestClient.cs</h1>
37                                         </th>
38                                         <th class="code"></th>
39                                 </tr>
40                         </thead>
41                         <tbody>
42                                         <tr id="section_1">
43                                                 <td class="docs">
44                                                         <div class="pilwrap">
45                                                                 <a class="pilcrow" href="#section_1">&#182;</a>
46                                                         </div>
47                                                         <hr />
48
49 <p><copyright file="RestClient.cs" company="Microsoft">
50 TODO: Update copyright text.</p>
51
52 <h2></copyright></h2>
53
54                                                 </td>
55                                                 <td class="code">
56                                                         <pre><code class='prettyprint'>
57 using System.Collections.Specialized;
58 using System.Diagnostics;
59 using System.Diagnostics.Contracts;
60 using System.IO;
61 using System.Net;
62 using System.Runtime.Serialization;
63 using System.Threading.Tasks;
64
65 namespace Pithos.Network
66 {
67     using System;
68     using System.Collections.Generic;
69     using System.Linq;
70     using System.Text;
71
72 </code></pre>
73                                                 </td>
74                                         </tr>
75                                         <tr id="section_2">
76                                                 <td class="docs">
77                                                         <div class="pilwrap">
78                                                                 <a class="pilcrow" href="#section_2">&#182;</a>
79                                                         </div>
80                                                         <p>/ <summary>
81 / TODO: Update summary.
82 / </summary></p>
83
84                                                 </td>
85                                                 <td class="code">
86                                                         <pre><code class='prettyprint'>    public class RestClient:WebClient
87     {
88         public int Timeout { get; set; }
89
90         public bool TimedOut { get; set; }
91
92         public HttpStatusCode StatusCode { get; private set; }
93
94         public string StatusDescription { get; set; }
95
96
97         public int Retries { get; set; }
98
99         private readonly Dictionary&lt;string, string&gt; _parameters=new Dictionary&lt;string, string&gt;();
100         public Dictionary&lt;string, string&gt; Parameters
101         {
102             get { return _parameters; }            
103         }
104
105         public RestClient():base()
106         {
107             
108         }
109
110        
111         public RestClient(RestClient other)
112             : base()
113         {
114             CopyHeaders(other);
115             Timeout = other.Timeout;
116             Retries = other.Retries;
117             BaseAddress = other.BaseAddress;             
118
119             foreach (var parameter in other.Parameters)
120             {
121                 Parameters.Add(parameter.Key,parameter.Value);
122             }
123
124             this.Proxy = other.Proxy;
125         }
126
127         protected override WebRequest GetWebRequest(Uri address)
128         {
129             TimedOut = false;
130             var webRequest = base.GetWebRequest(address);
131             var request = webRequest as HttpWebRequest;
132             if (IfModifiedSince.HasValue)
133                 request.IfModifiedSince = IfModifiedSince.Value;
134             request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
135             if(Timeout&gt;0)
136                 request.Timeout = Timeout;
137             return request; 
138         }
139
140         public DateTime? IfModifiedSince { get; set; }
141
142         protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
143         {
144             var response = (HttpWebResponse) base.GetWebResponse(request, result);            
145             StatusCode=response.StatusCode;
146             StatusDescription=response.StatusDescription;
147             return response;
148         }
149
150
151
152         protected override WebResponse GetWebResponse(WebRequest request)
153         {
154             try
155             {                
156                 var response = (HttpWebResponse)base.GetWebResponse(request);
157                 StatusCode = response.StatusCode;
158                 StatusDescription = response.StatusDescription;
159                 return response;
160             }
161             catch (WebException exc)
162             {
163                 if (exc.Response!=null &amp;&amp; exc.Response.ContentLength &gt; 0)
164                 {
165                     string content = GetContent(exc.Response);
166                     Trace.TraceError(content);
167                 }
168                 throw;
169             }
170         }
171
172         private static string GetContent(WebResponse webResponse)
173         {
174             string content;
175             using (var stream = webResponse.GetResponseStream())
176             using (var reader = new StreamReader(stream))
177             {
178                 content = reader.ReadToEnd();
179             }
180             return content;
181         }
182
183         public string DownloadStringWithRetry(string address,int retries=0)
184         {
185             if (address == null)
186                 throw new ArgumentNullException(&quot;address&quot;);
187
188             var actualAddress = GetActualAddress(address);
189
190             TraceStart(&quot;GET&quot;,actualAddress);            
191             
192             var actualRetries = (retries == 0) ? Retries : retries;
193             
194
195             
196             var task = Retry(() =&gt;
197             {
198                 var uriString = String.Join(&quot;/&quot;, BaseAddress.TrimEnd(&#39;/&#39;), actualAddress);                
199                 var content = base.DownloadString(uriString);
200
201                 if (StatusCode == HttpStatusCode.NoContent)
202                     return String.Empty;
203                 return content;
204
205             }, actualRetries);
206
207             var result = task.Result;
208             return result;
209         }
210
211         public void Head(string address,int retries=0)
212         {
213             RetryWithoutContent(address, retries, &quot;HEAD&quot;);
214         }
215
216         public void PutWithRetry(string address, int retries = 0)
217         {
218             RetryWithoutContent(address, retries, &quot;PUT&quot;);
219         }
220
221         public void DeleteWithRetry(string address,int retries=0)
222         {
223             RetryWithoutContent(address, retries, &quot;DELETE&quot;);
224         }
225
226         public string GetHeaderValue(string headerName)
227         {
228             var values=this.ResponseHeaders.GetValues(headerName);
229             if (values == null)
230                 throw new WebException(String.Format(&quot;The {0}  header is missing&quot;, headerName));
231             else
232                 return values[0];
233         }
234
235         private void RetryWithoutContent(string address, int retries, string method)
236         {
237             if (address == null)
238                 throw new ArgumentNullException(&quot;address&quot;);
239
240             var actualAddress = GetActualAddress(address);            
241             var actualRetries = (retries == 0) ? Retries : retries;
242
243             var task = Retry(() =&gt;
244             {
245                 var uriString = String.Join(&quot;/&quot;,BaseAddress ,actualAddress);
246                 var uri = new Uri(uriString);
247                 var request =  GetWebRequest(uri);
248                 request.Method = method;
249                 if (ResponseHeaders!=null)
250                     ResponseHeaders.Clear();
251
252                 TraceStart(method, uriString);
253
254                 var response = (HttpWebResponse)GetWebResponse(request);
255                 StatusCode = response.StatusCode;
256                 StatusDescription = response.StatusDescription;                
257                 
258
259                 return 0;
260             }, actualRetries);
261
262             task.Wait();
263         }
264         
265         /*private string RetryWithContent(string address, int retries, string method)
266         {
267             if (address == null)
268                 throw new ArgumentNullException(&quot;address&quot;);
269
270             var actualAddress = GetActualAddress(address);            
271             var actualRetries = (retries == 0) ? Retries : retries;
272
273             var task = Retry(() =&gt;
274             {
275                 var uriString = String.Join(&quot;/&quot;,BaseAddress ,actualAddress);
276                 var uri = new Uri(uriString);
277                 
278                 var request =  GetWebRequest(uri);
279                 request.Method = method;                
280
281                 if (ResponseHeaders!=null)
282                     ResponseHeaders.Clear();
283
284                 TraceStart(method, uriString);
285
286                 var getResponse = request.GetResponseAsync();
287                 
288                 var setStatus= getResponse.ContinueWith(t =&gt;
289                 {
290                     var response = (HttpWebResponse)t.Result;                    
291                     StatusCode = response.StatusCode;
292                     StatusDescription = response.StatusDescription;                
293                     return response;
294                 });
295
296                 var getData = setStatus.ContinueWith(t =&gt;
297                 {
298                     var response = t.Result;
299                     return response.GetResponseStream()
300                         .ReadAllBytesAsync();
301                 }).Unwrap();
302
303                 var data = getData.Result;
304                 var content=Encoding.UTF8.GetString(data);
305
306 </code></pre>
307                                                 </td>
308                                         </tr>
309                                         <tr id="section_3">
310                                                 <td class="docs">
311                                                         <div class="pilwrap">
312                                                                 <a class="pilcrow" href="#section_3">&#182;</a>
313                                                         </div>
314                                                         <pre><code>           var response = (HttpWebResponse)GetWebResponse(request);
315 </code></pre>
316
317                                                 </td>
318                                                 <td class="code">
319                                                         <pre><code class='prettyprint'>                
320                 
321 /*
322                 StatusCode = response.StatusCode;
323                 StatusDescription = response.StatusDescription;                
324 #1#
325                 
326
327                 return content;
328             }, actualRetries);
329
330             return task.Result;
331         }*/
332
333         private static void TraceStart(string method, string actualAddress)
334         {
335             Trace.WriteLine(String.Format(&quot;[{0}] {1} {2}&quot;, method, DateTime.Now, actualAddress));
336         }
337
338         private string GetActualAddress(string address)
339         {
340             if (Parameters.Count == 0)
341                 return address;
342             var addressBuilder=new StringBuilder(address);            
343
344             bool isFirst = true;
345             foreach (var parameter in Parameters)
346             {
347                 if(isFirst)
348                     addressBuilder.AppendFormat(&quot;?{0}={1}&quot;, parameter.Key, parameter.Value);
349                 else
350                     addressBuilder.AppendFormat(&quot;&amp;{0}={1}&quot;, parameter.Key, parameter.Value);
351                 isFirst = false;
352             }
353             return addressBuilder.ToString();
354         }
355
356         public string DownloadStringWithRetry(Uri address,int retries=0)
357         {
358             if (address == null)
359                 throw new ArgumentNullException(&quot;address&quot;);
360
361             var actualRetries = (retries == 0) ? Retries : retries;            
362             var task = Retry(() =&gt;
363             {
364                 var content = base.DownloadString(address);
365
366                 if (StatusCode == HttpStatusCode.NoContent)
367                     return String.Empty;
368                 return content;
369
370             }, actualRetries);
371
372             var result = task.Result;
373             return result;
374         }
375
376       
377 </code></pre>
378                                                 </td>
379                                         </tr>
380                                         <tr id="section_4">
381                                                 <td class="docs">
382                                                         <div class="pilwrap">
383                                                                 <a class="pilcrow" href="#section_4">&#182;</a>
384                                                         </div>
385                                                         <p>/ <summary>
386 / Copies headers from another RestClient
387 / </summary>
388 / <param name="source">The RestClient from which the headers are copied</param></p>
389
390                                                 </td>
391                                                 <td class="code">
392                                                         <pre><code class='prettyprint'>        public void CopyHeaders(RestClient source)
393         {
394             Contract.Requires(source != null, &quot;source can&#39;t be null&quot;);
395             if (source == null)
396                 throw new ArgumentNullException(&quot;source&quot;, &quot;source can&#39;t be null&quot;);
397             CopyHeaders(source.Headers,Headers);
398         }
399         
400 </code></pre>
401                                                 </td>
402                                         </tr>
403                                         <tr id="section_5">
404                                                 <td class="docs">
405                                                         <div class="pilwrap">
406                                                                 <a class="pilcrow" href="#section_5">&#182;</a>
407                                                         </div>
408                                                         <p>/ <summary>
409 / Copies headers from one header collection to another
410 / </summary>
411 / <param name="source">The source collection from which the headers are copied</param>
412 / <param name="target">The target collection to which the headers are copied</param></p>
413
414                                                 </td>
415                                                 <td class="code">
416                                                         <pre><code class='prettyprint'>        public static void CopyHeaders(WebHeaderCollection source,WebHeaderCollection target)
417         {
418             Contract.Requires(source != null, &quot;source can&#39;t be null&quot;);
419             Contract.Requires(target != null, &quot;target can&#39;t be null&quot;);
420             if (source == null)
421                 throw new ArgumentNullException(&quot;source&quot;, &quot;source can&#39;t be null&quot;);
422             if (target == null)
423                 throw new ArgumentNullException(&quot;target&quot;, &quot;target can&#39;t be null&quot;);
424             for (int i = 0; i &lt; source.Count; i++)
425             {
426                 target.Add(source.GetKey(i), source[i]);
427             }            
428         }
429
430         public void AssertStatusOK(string message)
431         {
432             if (StatusCode &gt;= HttpStatusCode.BadRequest)
433                 throw new WebException(String.Format(&quot;{0} with code {1} - {2}&quot;, message, StatusCode, StatusDescription));
434         }
435
436
437         private Task&lt;T&gt; Retry&lt;T&gt;(Func&lt;T&gt; original, int retryCount, TaskCompletionSource&lt;T&gt; tcs = null)
438         {
439             if (tcs == null)
440                 tcs = new TaskCompletionSource&lt;T&gt;();
441             Task.Factory.StartNew(original).ContinueWith(_original =&gt;
442                 {
443                     if (!_original.IsFaulted)
444                         tcs.SetFromTask(_original);
445                     else 
446                     {
447                         var e = _original.Exception.InnerException;
448                         var we = (e as WebException);
449                         if (we==null)
450                             tcs.SetException(e);
451                         else
452                         {
453                             var statusCode = GetStatusCode(we);
454
455 </code></pre>
456                                                 </td>
457                                         </tr>
458                                         <tr id="section_6">
459                                                 <td class="docs">
460                                                         <div class="pilwrap">
461                                                                 <a class="pilcrow" href="#section_6">&#182;</a>
462                                                         </div>
463                                                         <p>Return null for 404</p>
464
465                                                 </td>
466                                                 <td class="code">
467                                                         <pre><code class='prettyprint'>                            if (statusCode == HttpStatusCode.NotFound)
468                                 tcs.SetResult(default(T));
469 </code></pre>
470                                                 </td>
471                                         </tr>
472                                         <tr id="section_7">
473                                                 <td class="docs">
474                                                         <div class="pilwrap">
475                                                                 <a class="pilcrow" href="#section_7">&#182;</a>
476                                                         </div>
477                                                         <p>Retry for timeouts and service unavailable</p>
478
479                                                 </td>
480                                                 <td class="code">
481                                                         <pre><code class='prettyprint'>                            else if (we.Status == WebExceptionStatus.Timeout ||
482                                 (we.Status == WebExceptionStatus.ProtocolError &amp;&amp; statusCode == HttpStatusCode.ServiceUnavailable))
483                             {
484                                 TimedOut = true;
485                                 if (retryCount == 0)
486                                 {
487                                     Trace.TraceError(&quot;[ERROR] Timed out too many times. {0}\n&quot;, e);
488                                     tcs.SetException(new RetryException(&quot;Timed out too many times.&quot;, e));                                    
489                                 }
490                                 else
491                                 {
492                                     Trace.TraceError(
493                                         &quot;[RETRY] Timed out after {0} ms. Will retry {1} more times\n{2}&quot;, Timeout,
494                                         retryCount, e);
495                                     Retry(original, retryCount - 1, tcs);
496                                 }
497                             }
498                             else
499                                 tcs.SetException(e);
500                         }
501                     };
502                 });
503             return tcs.Task;
504         }
505
506         private HttpStatusCode GetStatusCode(WebException we)
507         {
508             var statusCode = HttpStatusCode.RequestTimeout;
509             if (we.Response != null)
510             {
511                 statusCode = ((HttpWebResponse) we.Response).StatusCode;
512                 this.StatusCode = statusCode;
513             }
514             return statusCode;
515         }
516     }
517
518     public class RetryException:Exception
519     {
520         public RetryException()
521             :base()
522         {
523             
524         }
525
526         public RetryException(string message)
527             :base(message)
528         {
529             
530         }
531
532         public RetryException(string message,Exception innerException)
533             :base(message,innerException)
534         {
535             
536         }
537
538         public RetryException(SerializationInfo info,StreamingContext context)
539             :base(info,context)
540         {
541             
542         }
543     }
544 }
545 </code></pre>
546                                                 </td>
547                                         </tr>
548                         </tbody>
549                 </table>
550         </div>
551 </body>
552 </html>