aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Communications/RestClient.cs
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Framework/Communications/RestClient.cs
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Framework/Communications/RestClient.cs')
-rw-r--r--OpenSim/Framework/Communications/RestClient.cs438
1 files changed, 0 insertions, 438 deletions
diff --git a/OpenSim/Framework/Communications/RestClient.cs b/OpenSim/Framework/Communications/RestClient.cs
deleted file mode 100644
index 97b3b60..0000000
--- a/OpenSim/Framework/Communications/RestClient.cs
+++ /dev/null
@@ -1,438 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Reflection;
33using System.Text;
34using System.Threading;
35using System.Web;
36using log4net;
37
38namespace OpenSim.Framework.Communications
39{
40 /// <summary>
41 /// Implementation of a generic REST client
42 /// </summary>
43 /// <remarks>
44 /// This class is a generic implementation of a REST (Representational State Transfer) web service. This
45 /// class is designed to execute both synchronously and asynchronously.
46 ///
47 /// Internally the implementation works as a two stage asynchronous web-client.
48 /// When the request is initiated, RestClient will query asynchronously for for a web-response,
49 /// sleeping until the initial response is returned by the server. Once the initial response is retrieved
50 /// the second stage of asynchronous requests will be triggered, in an attempt to read of the response
51 /// object into a memorystream as a sequence of asynchronous reads.
52 ///
53 /// The asynchronisity of RestClient is designed to move as much processing into the back-ground, allowing
54 /// other threads to execute, while it waits for a response from the web-service. RestClient itself can be
55 /// invoked by the caller in either synchronous mode or asynchronous modes.
56 /// </remarks>
57 public class RestClient
58 {
59 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60
61 // private string realuri;
62
63 #region member variables
64
65 /// <summary>
66 /// The base Uri of the web-service e.g. http://www.google.com
67 /// </summary>
68 private string _url;
69
70 /// <summary>
71 /// Path elements of the query
72 /// </summary>
73 private List<string> _pathElements = new List<string>();
74
75 /// <summary>
76 /// Parameter elements of the query, e.g. min=34
77 /// </summary>
78 private Dictionary<string, string> _parameterElements = new Dictionary<string, string>();
79
80 /// <summary>
81 /// Request method. E.g. GET, POST, PUT or DELETE
82 /// </summary>
83 private string _method;
84
85 /// <summary>
86 /// Temporary buffer used to store bytes temporarily as they come in from the server
87 /// </summary>
88 private byte[] _readbuf;
89
90 /// <summary>
91 /// MemoryStream representing the resultiong resource
92 /// </summary>
93 private Stream _resource;
94
95 /// <summary>
96 /// WebRequest object, held as a member variable
97 /// </summary>
98 private HttpWebRequest _request;
99
100 /// <summary>
101 /// WebResponse object, held as a member variable, so we can close it
102 /// </summary>
103 private HttpWebResponse _response;
104
105 /// <summary>
106 /// This flag will help block the main synchroneous method, in case we run in synchroneous mode
107 /// </summary>
108 //public static ManualResetEvent _allDone = new ManualResetEvent(false);
109
110 /// <summary>
111 /// Default time out period
112 /// </summary>
113 //private const int DefaultTimeout = 10*1000; // 10 seconds timeout
114
115 /// <summary>
116 /// Default Buffer size of a block requested from the web-server
117 /// </summary>
118 private const int BufferSize = 4096; // Read blocks of 4 KB.
119
120
121 /// <summary>
122 /// if an exception occours during async processing, we need to save it, so it can be
123 /// rethrown on the primary thread;
124 /// </summary>
125 private Exception _asyncException;
126
127 #endregion member variables
128
129 #region constructors
130
131 /// <summary>
132 /// Instantiate a new RestClient
133 /// </summary>
134 /// <param name="url">Web-service to query, e.g. http://osgrid.org:8003</param>
135 public RestClient(string url)
136 {
137 _url = url;
138 _readbuf = new byte[BufferSize];
139 _resource = new MemoryStream();
140 _request = null;
141 _response = null;
142 _lock = new object();
143 }
144
145 private object _lock;
146
147 #endregion constructors
148
149 /// <summary>
150 /// Add a path element to the query, e.g. assets
151 /// </summary>
152 /// <param name="element">path entry</param>
153 public void AddResourcePath(string element)
154 {
155 if (isSlashed(element))
156 _pathElements.Add(element.Substring(0, element.Length - 1));
157 else
158 _pathElements.Add(element);
159 }
160
161 /// <summary>
162 /// Add a query parameter to the Url
163 /// </summary>
164 /// <param name="name">Name of the parameter, e.g. min</param>
165 /// <param name="value">Value of the parameter, e.g. 42</param>
166 public void AddQueryParameter(string name, string value)
167 {
168 try
169 {
170 _parameterElements.Add(HttpUtility.UrlEncode(name), HttpUtility.UrlEncode(value));
171 }
172 catch (ArgumentException)
173 {
174 m_log.Error("[REST]: Query parameter " + name + " is already added.");
175 }
176 catch (Exception e)
177 {
178 m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e);
179 }
180 }
181
182 /// <summary>
183 /// Add a query parameter to the Url
184 /// </summary>
185 /// <param name="name">Name of the parameter, e.g. min</param>
186 public void AddQueryParameter(string name)
187 {
188 try
189 {
190 _parameterElements.Add(HttpUtility.UrlEncode(name), null);
191 }
192 catch (ArgumentException)
193 {
194 m_log.Error("[REST]: Query parameter " + name + " is already added.");
195 }
196 catch (Exception e)
197 {
198 m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e);
199 }
200 }
201
202 /// <summary>
203 /// Web-Request method, e.g. GET, PUT, POST, DELETE
204 /// </summary>
205 public string RequestMethod
206 {
207 get { return _method; }
208 set { _method = value; }
209 }
210
211 /// <summary>
212 /// True if string contains a trailing slash '/'
213 /// </summary>
214 /// <param name="s">string to be examined</param>
215 /// <returns>true if slash is present</returns>
216 private static bool isSlashed(string s)
217 {
218 return s.Substring(s.Length - 1, 1) == "/";
219 }
220
221 /// <summary>
222 /// Build a Uri based on the initial Url, path elements and parameters
223 /// </summary>
224 /// <returns>fully constructed Uri</returns>
225 private Uri buildUri()
226 {
227 StringBuilder sb = new StringBuilder();
228 sb.Append(_url);
229
230 foreach (string e in _pathElements)
231 {
232 sb.Append("/");
233 sb.Append(e);
234 }
235
236 bool firstElement = true;
237 foreach (KeyValuePair<string, string> kv in _parameterElements)
238 {
239 if (firstElement)
240 {
241 sb.Append("?");
242 firstElement = false;
243 }
244 else
245 sb.Append("&");
246
247 sb.Append(kv.Key);
248 if (!string.IsNullOrEmpty(kv.Value))
249 {
250 sb.Append("=");
251 sb.Append(kv.Value);
252 }
253 }
254 // realuri = sb.ToString();
255 //m_log.InfoFormat("[REST CLIENT]: RestURL: {0}", realuri);
256 return new Uri(sb.ToString());
257 }
258
259 #region Async communications with server
260
261 /// <summary>
262 /// Async method, invoked when a block of data has been received from the service
263 /// </summary>
264 /// <param name="ar"></param>
265 private void StreamIsReadyDelegate(IAsyncResult ar)
266 {
267 try
268 {
269 Stream s = (Stream) ar.AsyncState;
270 int read = s.EndRead(ar);
271
272 if (read > 0)
273 {
274 _resource.Write(_readbuf, 0, read);
275 // IAsyncResult asynchronousResult =
276 // s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s);
277 s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s);
278
279 // TODO! Implement timeout, without killing the server
280 //ThreadPool.RegisterWaitForSingleObject(asynchronousResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
281 }
282 else
283 {
284 s.Close();
285 //_allDone.Set();
286 }
287 }
288 catch (Exception e)
289 {
290 //_allDone.Set();
291 _asyncException = e;
292 }
293 }
294
295 #endregion Async communications with server
296
297 /// <summary>
298 /// Perform a synchronous request
299 /// </summary>
300 public Stream Request()
301 {
302 lock (_lock)
303 {
304 _request = (HttpWebRequest) WebRequest.Create(buildUri());
305 _request.KeepAlive = false;
306 _request.ContentType = "application/xml";
307 _request.Timeout = 200000;
308 _request.Method = RequestMethod;
309 _asyncException = null;
310
311// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
312 try
313 {
314 _response = (HttpWebResponse) _request.GetResponse();
315 }
316 catch (WebException e)
317 {
318 HttpWebResponse errorResponse = e.Response as HttpWebResponse;
319 if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode)
320 {
321 m_log.Warn("[REST CLIENT] Resource not found (404)");
322 }
323 else
324 {
325 m_log.Error("[REST CLIENT] Error fetching resource from server " + _request.Address.ToString());
326 m_log.Debug(e.ToString());
327 }
328
329 return null;
330 }
331
332 Stream src = _response.GetResponseStream();
333 int length = src.Read(_readbuf, 0, BufferSize);
334 while (length > 0)
335 {
336 _resource.Write(_readbuf, 0, length);
337 length = src.Read(_readbuf, 0, BufferSize);
338 }
339
340
341 // TODO! Implement timeout, without killing the server
342 // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
343 //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
344
345// _allDone.WaitOne();
346 if (_response != null)
347 _response.Close();
348 if (_asyncException != null)
349 throw _asyncException;
350
351 if (_resource != null)
352 {
353 _resource.Flush();
354 _resource.Seek(0, SeekOrigin.Begin);
355 }
356
357 return _resource;
358 }
359 }
360
361 public Stream Request(Stream src)
362 {
363 _request = (HttpWebRequest) WebRequest.Create(buildUri());
364 _request.KeepAlive = false;
365 _request.ContentType = "application/xml";
366 _request.Timeout = 900000;
367 _request.Method = RequestMethod;
368 _asyncException = null;
369 _request.ContentLength = src.Length;
370
371 m_log.InfoFormat("[REST]: Request Length {0}", _request.ContentLength);
372 m_log.InfoFormat("[REST]: Sending Web Request {0}", buildUri());
373 src.Seek(0, SeekOrigin.Begin);
374 m_log.Info("[REST]: Seek is ok");
375 Stream dst = _request.GetRequestStream();
376 m_log.Info("[REST]: GetRequestStream is ok");
377
378 byte[] buf = new byte[1024];
379 int length = src.Read(buf, 0, 1024);
380 m_log.Info("[REST]: First Read is ok");
381 while (length > 0)
382 {
383 dst.Write(buf, 0, length);
384 length = src.Read(buf, 0, 1024);
385 }
386
387 _response = (HttpWebResponse) _request.GetResponse();
388
389// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
390
391 // TODO! Implement timeout, without killing the server
392 // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
393 //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
394
395 return null;
396 }
397
398 #region Async Invocation
399
400 public IAsyncResult BeginRequest(AsyncCallback callback, object state)
401 {
402 /// <summary>
403 /// In case, we are invoked asynchroneously this object will keep track of the state
404 /// </summary>
405 AsyncResult<Stream> ar = new AsyncResult<Stream>(callback, state);
406 Util.FireAndForget(RequestHelper, ar);
407 return ar;
408 }
409
410 public Stream EndRequest(IAsyncResult asyncResult)
411 {
412 AsyncResult<Stream> ar = (AsyncResult<Stream>) asyncResult;
413
414 // Wait for operation to complete, then return result or
415 // throw exception
416 return ar.EndInvoke();
417 }
418
419 private void RequestHelper(Object asyncResult)
420 {
421 // We know that it's really an AsyncResult<DateTime> object
422 AsyncResult<Stream> ar = (AsyncResult<Stream>) asyncResult;
423 try
424 {
425 // Perform the operation; if sucessful set the result
426 Stream s = Request();
427 ar.SetAsCompleted(s, false);
428 }
429 catch (Exception e)
430 {
431 // If operation fails, set the exception
432 ar.HandleException(e, false);
433 }
434 }
435
436 #endregion Async Invocation
437 }
438}