~ubuntu-branches/ubuntu/trusty/smuxi/trusty-proposed

« back to all changes in this revision

Viewing changes to lib/ServiceStack/src/ServiceStack.Common/ServiceClient.Web/AsyncServiceClient.cs

  • Committer: Package Import Robot
  • Author(s): Mirco Bauer
  • Date: 2013-05-25 22:11:31 UTC
  • mfrom: (1.2.12)
  • Revision ID: package-import@ubuntu.com-20130525221131-nd2mc0kzubuwyx20
Tags: 0.8.11-1
* [22d13d5] Imported Upstream version 0.8.11
* [6d2b95a] Refreshed patches
* [89eb66e] Added ServiceStack libraries to smuxi-engine package
* [848ab10] Enable Campfire engine
* [c6dbdc7] Always build db4o for predictable build result
* [13ec489] Exclude OS X specific libraries from dh_clideps

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
using System;
 
2
using System.IO;
 
3
using System.Net;
 
4
using System.Text;
 
5
using System.Threading;
 
6
using ServiceStack.Logging;
 
7
using ServiceStack.ServiceHost;
 
8
using ServiceStack.Text;
 
9
using ServiceStack.Common.Web;
 
10
 
 
11
namespace ServiceStack.ServiceClient.Web
 
12
{
 
13
    /**
 
14
     * Need to provide async request options
 
15
     * http://msdn.microsoft.com/en-us/library/86wf6409(VS.71).aspx
 
16
     */
 
17
 
 
18
    public class AsyncServiceClient
 
19
    {
 
20
        private static readonly ILog Log = LogManager.GetLogger(typeof(AsyncServiceClient));
 
21
        private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(60);
 
22
        private HttpWebRequest _webRequest = null;
 
23
 
 
24
        /// <summary>
 
25
        /// The request filter is called before any request.
 
26
        /// This request filter is executed globally.
 
27
        /// </summary>
 
28
        public static Action<HttpWebRequest> HttpWebRequestFilter { get; set; }
 
29
 
 
30
        /// <summary>
 
31
        /// The response action is called once the server response is available.
 
32
        /// It will allow you to access raw response information. 
 
33
        /// This response action is executed globally.
 
34
        /// Note that you should NOT consume the response stream as this is handled by ServiceStack
 
35
        /// </summary>
 
36
        public static Action<HttpWebResponse> HttpWebResponseFilter { get; set; }
 
37
 
 
38
        /// <summary>
 
39
        /// Called before request resend, when the initial request required authentication
 
40
        /// </summary>
 
41
        public Action<WebRequest> OnAuthenticationRequired { get; set; }
 
42
 
 
43
        const int BufferSize = 4096;
 
44
 
 
45
        public ICredentials Credentials { get; set; }
 
46
 
 
47
        public bool StoreCookies { get; set; }
 
48
 
 
49
        public CookieContainer CookieContainer { get; set; }
 
50
 
 
51
        /// <summary>
 
52
        /// The request filter is called before any request.
 
53
        /// This request filter only works with the instance where it was set (not global).
 
54
        /// </summary>
 
55
        public Action<HttpWebRequest> LocalHttpWebRequestFilter { get; set; }
 
56
 
 
57
        /// <summary>
 
58
        /// The response action is called once the server response is available.
 
59
        /// It will allow you to access raw response information. 
 
60
        /// Note that you should NOT consume the response stream as this is handled by ServiceStack
 
61
        /// </summary>
 
62
        public Action<HttpWebResponse> LocalHttpWebResponseFilter { get; set; }
 
63
 
 
64
        public string BaseUri { get; set; }
 
65
 
 
66
        internal class RequestState<TResponse> : IDisposable
 
67
        {
 
68
            private bool _timedOut; // Pass the correct error back even on Async Calls
 
69
 
 
70
            public RequestState()
 
71
            {
 
72
                BufferRead = new byte[BufferSize];
 
73
                TextData = new StringBuilder();
 
74
                BytesData = new MemoryStream(BufferSize);
 
75
                WebRequest = null;
 
76
                ResponseStream = null;
 
77
            }
 
78
 
 
79
            public string HttpMethod;
 
80
 
 
81
            public string Url;
 
82
 
 
83
            public StringBuilder TextData;
 
84
 
 
85
            public MemoryStream BytesData;
 
86
 
 
87
            public byte[] BufferRead;
 
88
 
 
89
            public object Request;
 
90
 
 
91
            public HttpWebRequest WebRequest;
 
92
 
 
93
            public HttpWebResponse WebResponse;
 
94
 
 
95
            public Stream ResponseStream;
 
96
 
 
97
            public int Completed;
 
98
 
 
99
            public int RequestCount;
 
100
 
 
101
            public Timer Timer;
 
102
 
 
103
            public Action<TResponse> OnSuccess;
 
104
 
 
105
            public Action<TResponse, Exception> OnError;
 
106
 
 
107
#if SILVERLIGHT
 
108
            public bool HandleCallbackOnUIThread { get; set; }
 
109
#endif
 
110
 
 
111
            public void HandleSuccess(TResponse response)
 
112
            {
 
113
                if (this.OnSuccess == null)
 
114
                    return;
 
115
 
 
116
#if SILVERLIGHT
 
117
                if (this.HandleCallbackOnUIThread)
 
118
                    System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => this.OnSuccess(response));
 
119
                else
 
120
                    this.OnSuccess(response);
 
121
#else
 
122
                this.OnSuccess(response);
 
123
#endif
 
124
            }
 
125
            
 
126
            public void HandleError(TResponse response, Exception ex)
 
127
            {
 
128
                if (this.OnError == null)
 
129
                    return;
 
130
 
 
131
                Exception toReturn = ex;
 
132
                if (_timedOut)
 
133
                {
 
134
#if SILVERLIGHT
 
135
                    WebException we = new WebException("The request timed out", ex, WebExceptionStatus.RequestCanceled, null);
 
136
#else
 
137
                    WebException we = new WebException("The request timed out", ex, WebExceptionStatus.Timeout, null);
 
138
#endif
 
139
                    toReturn = we;
 
140
                }
 
141
 
 
142
#if SILVERLIGHT
 
143
                if (this.HandleCallbackOnUIThread)
 
144
                    System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => this.OnError(response, toReturn));
 
145
                else
 
146
                    this.OnError(response, toReturn);
 
147
#else
 
148
                OnError(response, toReturn);
 
149
#endif
 
150
            }
 
151
 
 
152
            public void StartTimer(TimeSpan timeOut)
 
153
            {
 
154
                this.Timer = new Timer(this.TimedOut, this, (int)timeOut.TotalMilliseconds, System.Threading.Timeout.Infinite);
 
155
            }
 
156
 
 
157
            public void TimedOut(object state)
 
158
            {
 
159
                if (Interlocked.Increment(ref Completed) == 1)
 
160
                {
 
161
                    if (this.WebRequest != null)
 
162
                    {
 
163
                        _timedOut = true;
 
164
                        this.WebRequest.Abort();
 
165
                    }
 
166
                }
 
167
                this.Timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
 
168
                this.Timer.Dispose();
 
169
                this.Dispose();
 
170
            }
 
171
 
 
172
            public void Dispose()
 
173
            {
 
174
                if (this.BytesData == null) return;
 
175
                this.BytesData.Dispose();
 
176
                this.BytesData = null;
 
177
            }
 
178
        }
 
179
 
 
180
        public bool DisableAutoCompression { get; set; }
 
181
 
 
182
        public string UserName { get; set; }
 
183
    
 
184
        public string Password { get; set; }
 
185
 
 
186
        public void SetCredentials(string userName, string password)
 
187
        {
 
188
            this.UserName = userName;
 
189
            this.Password = password;
 
190
        }
 
191
 
 
192
        public TimeSpan? Timeout { get; set; }
 
193
 
 
194
        public string ContentType { get; set; }
 
195
 
 
196
        public StreamSerializerDelegate StreamSerializer { get; set; }
 
197
 
 
198
        public StreamDeserializerDelegate StreamDeserializer { get; set; }
 
199
 
 
200
#if SILVERLIGHT
 
201
        public bool HandleCallbackOnUIThread { get; set; }
 
202
 
 
203
        public bool UseBrowserHttpHandling { get; set; }
 
204
 
 
205
        public bool ShareCookiesWithBrowser { get; set; }
 
206
#endif
 
207
 
 
208
        public void SendAsync<TResponse>(string httpMethod, string absoluteUrl, object request,
 
209
            Action<TResponse> onSuccess, Action<TResponse, Exception> onError)
 
210
        {
 
211
            SendWebRequest(httpMethod, absoluteUrl, request, onSuccess, onError);
 
212
        }
 
213
 
 
214
        public void CancelAsync()
 
215
        {
 
216
            if (_webRequest != null)
 
217
            {
 
218
                // Request will be nulled after it throws an exception on its async methods
 
219
                // See - http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.abort
 
220
                _webRequest.Abort();
 
221
            }
 
222
        }
 
223
 
 
224
#if !SILVERLIGHT
 
225
        internal static void AllowAutoCompression(HttpWebRequest webRequest)
 
226
        {
 
227
            webRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
 
228
            webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;            
 
229
        }
 
230
#endif
 
231
 
 
232
        private RequestState<TResponse> SendWebRequest<TResponse>(string httpMethod, string absoluteUrl, object request, 
 
233
            Action<TResponse> onSuccess, Action<TResponse, Exception> onError)
 
234
        {
 
235
            if (httpMethod == null) throw new ArgumentNullException("httpMethod");
 
236
 
 
237
            var requestUri = absoluteUrl;
 
238
            var httpGetOrDelete = (httpMethod == "GET" || httpMethod == "DELETE");
 
239
            var hasQueryString = request != null && httpGetOrDelete;
 
240
            if (hasQueryString)
 
241
            {
 
242
                var queryString = QueryStringSerializer.SerializeToString(request);
 
243
                if (!string.IsNullOrEmpty(queryString))
 
244
                {
 
245
                    requestUri += "?" + queryString;
 
246
                }
 
247
            }
 
248
 
 
249
#if SILVERLIGHT
 
250
 
 
251
            var creator = this.UseBrowserHttpHandling
 
252
                            ? System.Net.Browser.WebRequestCreator.BrowserHttp
 
253
                            : System.Net.Browser.WebRequestCreator.ClientHttp;
 
254
 
 
255
            var webRequest = (HttpWebRequest) creator.Create(new Uri(requestUri));
 
256
 
 
257
            if (StoreCookies && !UseBrowserHttpHandling)
 
258
            {
 
259
                if (ShareCookiesWithBrowser)
 
260
                {
 
261
                    if (CookieContainer == null)
 
262
                        CookieContainer = new CookieContainer();
 
263
                    CookieContainer.SetCookies(new Uri(BaseUri), System.Windows.Browser.HtmlPage.Document.Cookies);
 
264
                }
 
265
                
 
266
                webRequest.CookieContainer = CookieContainer;   
 
267
            }
 
268
 
 
269
#else
 
270
            _webRequest = (HttpWebRequest)WebRequest.Create(requestUri);
 
271
 
 
272
            if (StoreCookies)
 
273
            {
 
274
                _webRequest.CookieContainer = CookieContainer;
 
275
            }
 
276
#endif
 
277
 
 
278
#if !SILVERLIGHT
 
279
            if (!DisableAutoCompression)
 
280
            {
 
281
                _webRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
 
282
                _webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;                
 
283
            }
 
284
#endif
 
285
 
 
286
            var requestState = new RequestState<TResponse>
 
287
            {
 
288
                HttpMethod = httpMethod,
 
289
                Url = requestUri,
 
290
#if SILVERLIGHT
 
291
                WebRequest = webRequest,
 
292
#else
 
293
                WebRequest = _webRequest,
 
294
#endif
 
295
                Request = request,
 
296
                OnSuccess = onSuccess,
 
297
                OnError = onError,
 
298
#if SILVERLIGHT
 
299
                HandleCallbackOnUIThread = HandleCallbackOnUIThread,
 
300
#endif
 
301
            };
 
302
            requestState.StartTimer(this.Timeout.GetValueOrDefault(DefaultTimeout));
 
303
 
 
304
#if SILVERLIGHT
 
305
            SendWebRequestAsync(httpMethod, request, requestState, webRequest);
 
306
#else
 
307
            SendWebRequestAsync(httpMethod, request, requestState, _webRequest);
 
308
#endif
 
309
 
 
310
            return requestState;
 
311
        }
 
312
 
 
313
        private void SendWebRequestAsync<TResponse>(string httpMethod, object request, 
 
314
            RequestState<TResponse> requestState, HttpWebRequest webRequest)
 
315
        {
 
316
            var httpGetOrDelete = (httpMethod == "GET" || httpMethod == "DELETE");
 
317
            webRequest.Accept = string.Format("{0}, */*", ContentType);
 
318
 
 
319
#if !SILVERLIGHT 
 
320
            webRequest.Method = httpMethod;
 
321
#else
 
322
            //Methods others than GET and POST are only supported by Client request creator, see
 
323
            //http://msdn.microsoft.com/en-us/library/cc838250(v=vs.95).aspx
 
324
            
 
325
            if (this.UseBrowserHttpHandling && httpMethod != "GET" && httpMethod != "POST") 
 
326
            {
 
327
                webRequest.Method = "POST"; 
 
328
                webRequest.Headers[HttpHeaders.XHttpMethodOverride] = httpMethod;
 
329
            }
 
330
            else
 
331
            {
 
332
                webRequest.Method = httpMethod;
 
333
            }
 
334
#endif
 
335
 
 
336
            if (this.Credentials != null)
 
337
            {
 
338
                webRequest.Credentials = this.Credentials;
 
339
            }
 
340
 
 
341
            ApplyWebRequestFilters(webRequest);
 
342
 
 
343
            try
 
344
            {
 
345
                if (!httpGetOrDelete && request != null)
 
346
                {
 
347
                    webRequest.ContentType = ContentType;
 
348
                    webRequest.BeginGetRequestStream(RequestCallback<TResponse>, requestState);
 
349
                }
 
350
                else
 
351
                {
 
352
                    requestState.WebRequest.BeginGetResponse(ResponseCallback<TResponse>, requestState);
 
353
                }
 
354
            }
 
355
            catch (Exception ex)
 
356
            {
 
357
                // BeginGetRequestStream can throw if request was aborted
 
358
                HandleResponseError(ex, requestState);
 
359
            }
 
360
        }
 
361
 
 
362
        private void RequestCallback<T>(IAsyncResult asyncResult)
 
363
        {
 
364
            var requestState = (RequestState<T>)asyncResult.AsyncState;
 
365
            try
 
366
            {
 
367
                var req = requestState.WebRequest;
 
368
 
 
369
                var postStream = req.EndGetRequestStream(asyncResult);
 
370
                StreamSerializer(null, requestState.Request, postStream);
 
371
                postStream.Close();
 
372
                requestState.WebRequest.BeginGetResponse(ResponseCallback<T>, requestState);
 
373
            }
 
374
            catch (Exception ex)
 
375
            {
 
376
                HandleResponseError(ex, requestState);
 
377
            }
 
378
        }
 
379
 
 
380
        private void ResponseCallback<T>(IAsyncResult asyncResult)
 
381
        {
 
382
            var requestState = (RequestState<T>)asyncResult.AsyncState;
 
383
            try
 
384
            {
 
385
                var webRequest = requestState.WebRequest;
 
386
 
 
387
                requestState.WebResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult);
 
388
 
 
389
                ApplyWebResponseFilters(requestState.WebResponse);
 
390
 
 
391
                // Read the response into a Stream object.
 
392
                var responseStream = requestState.WebResponse.GetResponseStream();
 
393
                requestState.ResponseStream = responseStream;
 
394
 
 
395
                responseStream.BeginRead(requestState.BufferRead, 0, BufferSize, ReadCallBack<T>, requestState);
 
396
                return;
 
397
            }
 
398
            catch (Exception ex)
 
399
            {
 
400
                var firstCall = Interlocked.Increment(ref requestState.RequestCount) == 1;
 
401
                if (firstCall && WebRequestUtils.ShouldAuthenticate(ex, this.UserName, this.Password))
 
402
                {
 
403
                    try
 
404
                    {
 
405
                        requestState.WebRequest = (HttpWebRequest)WebRequest.Create(requestState.Url);
 
406
 
 
407
                        requestState.WebRequest.AddBasicAuth(this.UserName, this.Password);
 
408
 
 
409
                        if (OnAuthenticationRequired != null)
 
410
                        {
 
411
                            OnAuthenticationRequired(requestState.WebRequest);
 
412
                        }
 
413
 
 
414
                        SendWebRequestAsync(
 
415
                            requestState.HttpMethod, requestState.Request,
 
416
                            requestState, requestState.WebRequest);
 
417
                    }
 
418
                    catch (Exception /*subEx*/)
 
419
                    {
 
420
                        HandleResponseError(ex, requestState);
 
421
                    }
 
422
                    return;
 
423
                }
 
424
 
 
425
                HandleResponseError(ex, requestState);
 
426
            }
 
427
        }
 
428
 
 
429
        private void ReadCallBack<T>(IAsyncResult asyncResult)
 
430
        {
 
431
            var requestState = (RequestState<T>)asyncResult.AsyncState;
 
432
            try
 
433
            {
 
434
                var responseStream = requestState.ResponseStream;
 
435
                int read = responseStream.EndRead(asyncResult);
 
436
 
 
437
                if (read > 0)
 
438
                {
 
439
                    requestState.BytesData.Write(requestState.BufferRead, 0, read);
 
440
                    responseStream.BeginRead(
 
441
                        requestState.BufferRead, 0, BufferSize, ReadCallBack<T>, requestState);
 
442
 
 
443
                    return;
 
444
                }
 
445
 
 
446
                Interlocked.Increment(ref requestState.Completed);
 
447
 
 
448
                var response = default(T);
 
449
                try
 
450
                {
 
451
                    requestState.BytesData.Position = 0;
 
452
                    using (var reader = requestState.BytesData)
 
453
                    {
 
454
                        response = (T)this.StreamDeserializer(typeof(T), reader);
 
455
                    }
 
456
 
 
457
#if SILVERLIGHT
 
458
                    if (this.StoreCookies && this.ShareCookiesWithBrowser && !this.UseBrowserHttpHandling)
 
459
                    {
 
460
                        // browser cookies must be set on the ui thread
 
461
                        System.Windows.Deployment.Current.Dispatcher.BeginInvoke(
 
462
                            () =>
 
463
                                {
 
464
                                    var cookieHeader = this.CookieContainer.GetCookieHeader(new Uri(BaseUri));
 
465
                                    System.Windows.Browser.HtmlPage.Document.Cookies = cookieHeader;
 
466
                                });
 
467
                    }
 
468
#endif
 
469
 
 
470
                    requestState.HandleSuccess(response);
 
471
                }
 
472
                catch (Exception ex)
 
473
                {
 
474
                    Log.Debug(string.Format("Error Reading Response Error: {0}", ex.Message), ex);
 
475
                    requestState.HandleError(default(T), ex);
 
476
                }
 
477
                finally
 
478
                {
 
479
                    responseStream.Close();
 
480
                    _webRequest = null;
 
481
                }
 
482
            }
 
483
            catch (Exception ex)
 
484
            {
 
485
                HandleResponseError(ex, requestState);
 
486
            }
 
487
        }
 
488
 
 
489
        private void HandleResponseError<TResponse>(Exception exception, RequestState<TResponse> requestState)
 
490
        {
 
491
            var webEx = exception as WebException;
 
492
            if (webEx != null
 
493
#if !SILVERLIGHT 
 
494
                && webEx.Status == WebExceptionStatus.ProtocolError
 
495
#endif
 
496
            )
 
497
            {
 
498
                var errorResponse = ((HttpWebResponse)webEx.Response);
 
499
                Log.Error(webEx);
 
500
                Log.DebugFormat("Status Code : {0}", errorResponse.StatusCode);
 
501
                Log.DebugFormat("Status Description : {0}", errorResponse.StatusDescription);
 
502
 
 
503
                var serviceEx = new WebServiceException(errorResponse.StatusDescription)
 
504
                {
 
505
                    StatusCode = (int)errorResponse.StatusCode,
 
506
                };
 
507
 
 
508
                try
 
509
                {
 
510
                    using (var stream = errorResponse.GetResponseStream())
 
511
                    {
 
512
                        //Uncomment to Debug exceptions:
 
513
                        //var strResponse = new StreamReader(stream).ReadToEnd();
 
514
                        //Console.WriteLine("Response: " + strResponse);
 
515
                        //stream.Position = 0;
 
516
 
 
517
                        serviceEx.ResponseDto = this.StreamDeserializer(typeof(TResponse), stream);
 
518
                        requestState.HandleError((TResponse)serviceEx.ResponseDto, serviceEx);
 
519
                    }
 
520
                }
 
521
                catch (Exception innerEx)
 
522
                {
 
523
                    // Oh, well, we tried
 
524
                    Log.Debug(string.Format("WebException Reading Response Error: {0}", innerEx.Message), innerEx);
 
525
                    requestState.HandleError(default(TResponse), new WebServiceException(errorResponse.StatusDescription, innerEx)
 
526
                        {
 
527
                            StatusCode = (int)errorResponse.StatusCode,
 
528
                        });
 
529
                }
 
530
                return;
 
531
            }
 
532
 
 
533
            var authEx = exception as AuthenticationException;
 
534
            if (authEx != null)
 
535
            {
 
536
                var customEx = WebRequestUtils.CreateCustomException(requestState.Url, authEx);
 
537
 
 
538
                Log.Debug(string.Format("AuthenticationException: {0}", customEx.Message), customEx);
 
539
                requestState.HandleError(default(TResponse), authEx);
 
540
            }
 
541
 
 
542
            Log.Debug(string.Format("Exception Reading Response Error: {0}", exception.Message), exception);
 
543
            requestState.HandleError(default(TResponse), exception);
 
544
 
 
545
            _webRequest = null;
 
546
        }
 
547
 
 
548
        private void ApplyWebResponseFilters(WebResponse webResponse)
 
549
        {
 
550
            if (!(webResponse is HttpWebResponse)) return;
 
551
 
 
552
            if (HttpWebResponseFilter != null)
 
553
                HttpWebResponseFilter((HttpWebResponse)webResponse);
 
554
            if (LocalHttpWebResponseFilter != null)
 
555
                LocalHttpWebResponseFilter((HttpWebResponse)webResponse);
 
556
        }
 
557
 
 
558
        private void ApplyWebRequestFilters(HttpWebRequest client)
 
559
        {
 
560
            if (LocalHttpWebRequestFilter != null)
 
561
                LocalHttpWebRequestFilter(client);
 
562
 
 
563
            if (HttpWebRequestFilter != null)
 
564
                HttpWebRequestFilter(client);
 
565
        }
 
566
 
 
567
        public void Dispose() { }
 
568
    }
 
569
 
 
570
}
 
 
b'\\ No newline at end of file'