Merge pull request #214 from QuickJack/cd2c570c5543963d987f51080218715407c5d4b9
[mono.git] / mcs / class / System.Net.Http / System.Net.Http / HttpClient.cs
1 //
2 // HttpClient.cs
3 //
4 // Authors:
5 //      Marek Safar  <marek.safar@gmail.com>
6 //
7 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System.Threading;
30 using System.Net.Http.Headers;
31
32 namespace System.Net.Http
33 {
34         public class HttpClient : IDisposable
35         {
36                 static readonly TimeSpan TimeoutDefault = TimeSpan.FromSeconds (100);
37
38                 Uri base_address;
39                 CancellationTokenSource cancellation_token;
40                 bool disposed;
41                 readonly HttpMessageHandler handler;
42                 HttpRequestHeaders headers;
43                 int buffer_size;
44                 TimeSpan timeout;
45
46                 public HttpClient ()
47                         : this (null)
48                 {
49                 }
50
51                 public HttpClient (HttpMessageHandler handler)
52                 {
53                         this.handler = handler ?? new HttpClientHandler ();
54                         buffer_size = 0x10000;
55                         timeout = TimeoutDefault;
56                 }
57
58                 public Uri BaseAddress {
59                         get {
60                                 return base_address;
61                         }
62                         set {
63                                 base_address = value;
64                         }
65                 }
66
67                 public HttpRequestHeaders DefaultRequestHeaders {
68                         get {
69                                 return headers ?? (headers = new HttpRequestHeaders ());
70                         }
71                 }
72
73                 public int MaxResponseContentBufferSize {
74                         get {
75                                 return buffer_size;
76                         }
77                         set {
78                                 if (value <= 0)
79                                         throw new ArgumentOutOfRangeException ();
80
81                                 buffer_size = value;
82                         }
83                 }
84
85                 public TimeSpan Timeout {
86                         get {
87                                 return timeout;
88                         }
89                         set {
90                                 if (value != System.Threading.Timeout.InfiniteTimeSpan && value < TimeSpan.Zero)
91                                         throw new ArgumentOutOfRangeException ();
92
93                                 timeout = value;
94                         }
95                 }
96
97                 public void CancelPendingRequests ()
98                 {
99                         if (cancellation_token != null)
100                                 cancellation_token.Cancel ();
101
102                         cancellation_token = new CancellationTokenSource ();
103                 }
104  
105                 public void Dispose ()
106                 {
107                         Dispose (true);
108                 }
109                 
110                 protected virtual void Dispose (bool disposing)
111                 {
112                         if (disposing && !disposed) {
113                                 disposed = true;
114
115                                 if (cancellation_token != null)
116                                         cancellation_token.Dispose ();
117                         }
118                 }
119
120                 public HttpResponseMessage Delete (string requestUri)
121                 {
122                         return Send (new HttpRequestMessage (HttpMethod.Delete, requestUri));
123                 }
124
125                 public HttpResponseMessage Delete (Uri requestUri)
126                 {
127                         return Send (new HttpRequestMessage (HttpMethod.Delete, requestUri));
128                 }
129
130                 public HttpResponseMessage Get (string requestUri)
131                 {
132                         return Send (new HttpRequestMessage (HttpMethod.Get, requestUri));
133                 }
134
135                 public HttpResponseMessage Get (Uri requestUri)
136                 {
137                         return Send (new HttpRequestMessage (HttpMethod.Get, requestUri));
138                 }
139
140                 public HttpResponseMessage Post (string requestUri, HttpContent content)
141                 {
142                         return Send (new HttpRequestMessage (HttpMethod.Post, requestUri) { Content = content });
143                 }
144
145                 public HttpResponseMessage Put (Uri requestUri, HttpContent content)
146                 {
147                         return Send (new HttpRequestMessage (HttpMethod.Put, requestUri) { Content = content });
148                 }
149
150                 public HttpResponseMessage Put (string requestUri, HttpContent content)
151                 {
152                         return Send (new HttpRequestMessage (HttpMethod.Put, requestUri) { Content = content });
153                 }
154
155                 public HttpResponseMessage Post (Uri requestUri, HttpContent content)
156                 {
157                         return Send (new HttpRequestMessage (HttpMethod.Post, requestUri) { Content = content });
158                 }
159
160                 public HttpResponseMessage Send (HttpRequestMessage request)
161                 {
162                         return Send (request, HttpCompletionOption.ResponseContentRead, CancellationToken.None);
163                 }
164
165                 public HttpResponseMessage Send (HttpRequestMessage request, HttpCompletionOption completionOption)
166                 {
167                         return Send (request, completionOption, CancellationToken.None);
168                 }
169
170                 public HttpResponseMessage Send (HttpRequestMessage request, CancellationToken cancellationToken)
171                 {
172                         return Send (request, HttpCompletionOption.ResponseContentRead, cancellationToken);
173                 }
174
175                 public HttpResponseMessage Send (HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
176                 {
177                         if (request == null)
178                                 throw new ArgumentNullException ("request");
179
180                         if (request.SetIsUsed ())
181                                 throw new InvalidOperationException ("Cannot send the same request message multiple times");
182
183                         if (request.RequestUri == null) {
184                                 if (base_address == null)
185                                         throw new InvalidOperationException ("The request URI must either be an absolute URI or BaseAddress must be set");
186
187                                 request.RequestUri = base_address;
188                         }
189
190                         try {
191                                 if (cancellation_token == null)
192                                         cancellation_token = new CancellationTokenSource ();
193
194                                 using (var cts = CancellationTokenSource.CreateLinkedTokenSource (cancellation_token.Token, cancellationToken)) {
195                                         cts.CancelAfter (timeout);
196
197                                         var response = handler.Send (request, cts.Token);
198                                         if (response == null)
199                                                 throw new InvalidOperationException ("Handler failed to return a response");
200
201                                         return response;
202                                 }
203                         } finally {
204                                 cancellation_token.Dispose ();
205                                 cancellation_token = null;
206                         }
207                 }
208         }
209 }