Added hammock project to debug streaming issues
[pithos-ms-client] / trunk / hammock / src / net35 / Hammock / RestResponse.cs
1 using System;
2 using System.IO;
3 using System.Net;
4 using Hammock.Extensions;
5
6 #if SILVERLIGHT
7 using Hammock.Silverlight.Compat;
8 #else
9 using System.Collections.Specialized;
10 #endif
11
12 namespace Hammock
13 {
14 #if !Silverlight
15     [Serializable]
16 #endif
17     public class RestResponseBase : IDisposable
18     {
19         private string _content;
20         public virtual string Content
21         {
22             get
23             {
24                 if(_content == null && ContentStream != null)
25                 {
26                     ContentStream = ReplaceContentStreamWithMemoryStream();
27                     using (var reader = new StreamReader(ContentStream))
28                     {
29                         _content = reader.ReadToEnd();
30                     }
31                     if (ContentStream.CanSeek)
32                     {
33                         ContentStream.Position = 0;
34                     }
35                 }
36                 return _content;
37             }
38         }
39
40         private byte[] _contentBytes;
41         public virtual byte[] ContentBytes
42         {
43             get
44             {
45                 if(_contentBytes == null && ContentStream != null)
46                 {
47                     ContentStream = ReplaceContentStreamWithMemoryStream();
48                     _contentBytes = ReadFully(ContentStream);
49                     if(ContentStream.CanSeek)
50                     {
51                         ContentStream.Position = 0;
52                     }
53                 }
54                 return _contentBytes;
55             }
56         }
57
58         public virtual object ErrorContentEntity { get; set; }
59         public virtual Stream ContentStream { get; set; }
60         public virtual WebResponse InnerResponse { get; set; }
61         public virtual Exception InnerException { get; set; }
62         public virtual DateTime? RequestDate { get; set; }
63         public virtual DateTime? ResponseDate { get; set; }
64         public virtual string RequestMethod { get; set; }
65         public virtual bool RequestKeptAlive { get; set; }
66         public virtual HttpStatusCode StatusCode { get; set; }
67         public virtual string StatusDescription { get; set; }
68         public virtual string ContentType { get; set; }
69         public virtual long ContentLength { get; set; }
70         public virtual Uri RequestUri { get; set; }
71         public virtual Uri ResponseUri { get; set; }
72         public virtual bool IsMock { get; set; }
73         public virtual bool TimedOut { get; set; }
74         public virtual int TimesTried { get; set; }
75         public virtual object Tag { get; set; }
76         public virtual NameValueCollection Headers { get; set; }
77         public virtual NameValueCollection Cookies { get; set; }
78         public virtual bool SkippedDueToRateLimitingRule { get; set; }
79         public virtual bool IsFromCache
80         {
81             get
82             {
83                 return StatusCode == 0 && 
84                        StatusDescription.IsNullOrBlank() && 
85                        Content != null;
86             }
87         }
88
89         public RestResponseBase()
90         {
91             Initialize();
92         }
93
94         private void Initialize()
95         {
96             Headers = new NameValueCollection(0);
97             Cookies = new NameValueCollection(0);
98         }
99
100         // http://www.yoda.arachsys.com/csharp/readbinary.html
101         public static byte[] ReadFully(Stream stream)
102         {
103             const int initialLength = 32768;
104             var buffer = new byte[initialLength];
105             var read = 0;
106
107             int chunk;
108             while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0)
109             {
110                 read += chunk;
111                 if (read != buffer.Length)
112                 {
113                     continue;
114                 }
115                 var nextByte = stream.ReadByte();
116                 if (nextByte == -1)
117                 {
118                     return buffer;
119                 }
120                 var newBuffer = new byte[buffer.Length * 2];
121                 Array.Copy(buffer, newBuffer, buffer.Length);
122                 newBuffer[read] = (byte)nextByte;
123                 buffer = newBuffer;
124                 read++;
125             }
126             var ret = new byte[read];
127             Array.Copy(buffer, ret, read);
128             return ret;
129         }
130
131         private Stream ReplaceContentStreamWithMemoryStream()
132         {
133             if(ContentStream is DurableMemoryStream)
134             {
135                 return ContentStream;
136             }
137
138             var buffer = new byte[4096];
139             var stream = new MemoryStream();
140             var count = 0;
141             do
142             {
143                 if (ContentStream == null)
144                 {
145                     continue;
146                 }
147                 count = ContentStream.Read(buffer, 0, buffer.Length);
148                 stream.Write(buffer, 0, count);
149             } while (count != 0);
150
151             if (ContentStream != null)
152             {
153                 ContentStream.Close();
154                 ContentStream.Dispose();
155             }
156
157             if(stream.CanSeek)
158             {
159                 stream.Position = 0;
160             }
161
162             return new DurableMemoryStream(stream);
163         }
164
165         private class DurableMemoryStream : MemoryStream
166         {
167             private readonly Stream _stream;
168
169             public DurableMemoryStream(Stream stream)
170             {
171                 _stream = stream;
172             }
173
174             public override IAsyncResult BeginRead(byte[] buffer, int offset, int count,
175                                                    AsyncCallback callback, object state)
176             {
177                 return _stream.BeginRead(buffer, offset, count, callback, state);
178             }
179
180             public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count,
181                                                     AsyncCallback callback, object state)
182             {
183                 return _stream.BeginWrite(buffer, offset, count, callback, state);
184             }
185
186             public override bool CanRead
187             {
188                 get { return _stream.CanRead; }
189             }
190
191             public override bool CanSeek
192             {
193                 get { return _stream.CanSeek; }
194             }
195
196             public override bool CanWrite
197             {
198                 get { return _stream.CanWrite; }
199             }
200
201             public override void Close()
202             {
203                 _stream.Flush();
204             }
205
206             public override int EndRead(IAsyncResult asyncResult)
207             {
208                 return _stream.EndRead(asyncResult);
209             }
210
211             public override void EndWrite(IAsyncResult asyncResult)
212             {
213                 _stream.EndWrite(asyncResult);
214             }
215
216             public override void Flush()
217             {
218                 _stream.Flush();
219             }
220
221             public override long Length
222             {
223                 get
224                 {
225                     return _stream.Length;
226                 }
227             }
228
229             public override long Position
230             {
231                 get
232                 {
233                     return _stream.Position;
234                 }
235                 set
236                 {
237                     _stream.Position = value;
238                 }
239             }
240
241             public override int Read(byte[] buffer, int offset, int count)
242             {
243                 return _stream.Read(buffer, offset, count);
244             }
245
246             public override int ReadByte()
247             {
248                 return _stream.ReadByte();
249             }
250
251             public override long Seek(long offset, SeekOrigin origin)
252             {
253                 return _stream.Seek(offset, origin);
254             }
255
256             public override void SetLength(long value)
257             {
258                 _stream.SetLength(value);
259             }
260
261             public override void Write(byte[] buffer, int offset, int count)
262             {
263                 _stream.Write(buffer, offset, count);
264             }
265
266             public override void WriteByte(byte value)
267             {
268                 _stream.WriteByte(value);
269             }
270
271             protected override void Dispose(bool disposing)
272             {
273                 if(disposing)
274                 {
275                     _stream.Dispose();
276                 }
277                 base.Dispose(disposing);
278             }
279         }
280
281         public void SetContent(string content)
282         {
283             _content = content;
284         }
285
286         public void Dispose()
287         {
288             if(ContentStream != null)
289             {
290                 ContentStream.Dispose();
291             }
292         }
293     }
294
295 #if !Silverlight
296     [Serializable]
297 #endif
298     public class RestResponse : RestResponseBase
299     {
300         public virtual object ContentEntity { get; set; }
301     }
302
303 #if !Silverlight
304     [Serializable]
305 #endif
306     public class RestResponse<T> : RestResponseBase
307     {
308         public virtual T ContentEntity { get; set; }
309     }
310 }
311
312