aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/WebUtil.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/WebUtil.cs')
-rw-r--r--OpenSim/Framework/WebUtil.cs240
1 files changed, 213 insertions, 27 deletions
diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs
index 1c856af..d88d095 100644
--- a/OpenSim/Framework/WebUtil.cs
+++ b/OpenSim/Framework/WebUtil.cs
@@ -50,6 +50,16 @@ namespace OpenSim.Framework
50 LogManager.GetLogger( 50 LogManager.GetLogger(
51 MethodBase.GetCurrentMethod().DeclaringType); 51 MethodBase.GetCurrentMethod().DeclaringType);
52 52
53 private static int m_requestNumber = 0;
54
55 // this is the header field used to communicate the local request id
56 // used for performance and debugging
57 public const string OSHeaderRequestID = "opensim-request-id";
58
59 // number of milliseconds a call can take before it is considered
60 // a "long" call for warning & debugging purposes
61 public const int LongCallTime = 200;
62
53 /// <summary> 63 /// <summary>
54 /// Send LLSD to an HTTP client in application/llsd+json form 64 /// Send LLSD to an HTTP client in application/llsd+json form
55 /// </summary> 65 /// </summary>
@@ -123,26 +133,186 @@ namespace OpenSim.Framework
123 } 133 }
124 134
125 /// <summary> 135 /// <summary>
136 /// PUT JSON-encoded data to a web service that returns LLSD or
137 /// JSON data
138 /// </summary>
139 public static OSDMap PutToService(string url, OSDMap data)
140 {
141 return ServiceOSDRequest(url,data,"PUT",10000);
142 }
143
144 public static OSDMap PostToService(string url, OSDMap data)
145 {
146 return ServiceOSDRequest(url,data,"POST",10000);
147 }
148
149 public static OSDMap GetFromService(string url)
150 {
151 return ServiceOSDRequest(url,null,"GET",10000);
152 }
153
154 public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout)
155 {
156 int reqnum = m_requestNumber++;
157 // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
158
159 string errorMessage = "unknown error";
160 int tickstart = Util.EnvironmentTickCount();
161 int tickdata = 0;
162
163 try
164 {
165 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
166 request.Method = method;
167 request.Timeout = timeout;
168 request.KeepAlive = false;
169 request.MaximumAutomaticRedirections = 10;
170 request.ReadWriteTimeout = timeout / 4;
171 request.Headers[OSHeaderRequestID] = reqnum.ToString();
172
173 // If there is some input, write it into the request
174 if (data != null)
175 {
176 string strBuffer = OSDParser.SerializeJsonString(data);
177 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer);
178
179 request.ContentType = "application/json";
180 request.ContentLength = buffer.Length; //Count bytes to send
181 using (Stream requestStream = request.GetRequestStream())
182 requestStream.Write(buffer, 0, buffer.Length); //Send it
183 }
184
185 // capture how much time was spent writing, this may seem silly
186 // but with the number concurrent requests, this often blocks
187 tickdata = Util.EnvironmentTickCountSubtract(tickstart);
188
189 using (WebResponse response = request.GetResponse())
190 {
191 using (Stream responseStream = response.GetResponseStream())
192 {
193 string responseStr = null;
194 responseStr = responseStream.GetStreamString();
195 // m_log.DebugFormat("[WEB UTIL]: <{0}> response is <{1}>",reqnum,responseStr);
196 return CanonicalizeResults(responseStr);
197 }
198 }
199 }
200 catch (WebException we)
201 {
202 errorMessage = we.Message;
203 if (we.Status == WebExceptionStatus.ProtocolError)
204 {
205 HttpWebResponse webResponse = (HttpWebResponse)we.Response;
206 errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription);
207 }
208 }
209 catch (Exception ex)
210 {
211 errorMessage = ex.Message;
212 }
213 finally
214 {
215 // This just dumps a warning for any operation that takes more than 100 ms
216 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
217 if (tickdiff > LongCallTime)
218 m_log.InfoFormat("[WEB UTIL]: osd request <{0}> (URI:{1}, METHOD:{2}) took {3}ms overall, {4}ms writing",
219 reqnum,url,method,tickdiff,tickdata);
220 }
221
222 m_log.WarnFormat("[WEB UTIL] <{0}> osd request failed: {1}",reqnum,errorMessage);
223 return ErrorResponseMap(errorMessage);
224 }
225
226 /// <summary>
227 /// Since there are no consistencies in the way web requests are
228 /// formed, we need to do a little guessing about the result format.
229 /// Keys:
230 /// Success|success == the success fail of the request
231 /// _RawResult == the raw string that came back
232 /// _Result == the OSD unpacked string
233 /// </summary>
234 private static OSDMap CanonicalizeResults(string response)
235 {
236 OSDMap result = new OSDMap();
237
238 // Default values
239 result["Success"] = OSD.FromBoolean(true);
240 result["success"] = OSD.FromBoolean(true);
241 result["_RawResult"] = OSD.FromString(response);
242 result["_Result"] = new OSDMap();
243
244 if (response.Equals("true",System.StringComparison.OrdinalIgnoreCase))
245 return result;
246
247 if (response.Equals("false",System.StringComparison.OrdinalIgnoreCase))
248 {
249 result["Success"] = OSD.FromBoolean(false);
250 result["success"] = OSD.FromBoolean(false);
251 return result;
252 }
253
254 try
255 {
256 OSD responseOSD = OSDParser.Deserialize(response);
257 if (responseOSD.Type == OSDType.Map)
258 {
259 result["_Result"] = (OSDMap)responseOSD;
260 return result;
261 }
262 }
263 catch (Exception e)
264 {
265 // don't need to treat this as an error... we're just guessing anyway
266 m_log.DebugFormat("[WEB UTIL] couldn't decode <{0}>: {1}",response,e.Message);
267 }
268
269 return result;
270 }
271
272 /// <summary>
126 /// POST URL-encoded form data to a web service that returns LLSD or 273 /// POST URL-encoded form data to a web service that returns LLSD or
127 /// JSON data 274 /// JSON data
128 /// </summary> 275 /// </summary>
129 public static OSDMap PostToService(string url, NameValueCollection data) 276 public static OSDMap PostToService(string url, NameValueCollection data)
130 { 277 {
131 string errorMessage; 278 return ServiceFormRequest(url,data,10000);
279 }
280
281 public static OSDMap ServiceFormRequest(string url, NameValueCollection data, int timeout)
282 {
283 int reqnum = m_requestNumber++;
284 string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown";
285 // m_log.DebugFormat("[WEB UTIL]: <{0}> start form request for {1}, method {2}",reqnum,url,method);
286
287 string errorMessage = "unknown error";
288 int tickstart = Util.EnvironmentTickCount();
289 int tickdata = 0;
132 290
133 try 291 try
134 { 292 {
135 string queryString = BuildQueryString(data); 293
136 byte[] requestData = System.Text.Encoding.UTF8.GetBytes(queryString);
137
138 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); 294 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
139 request.Method = "POST"; 295 request.Method = "POST";
140 request.ContentLength = requestData.Length; 296 request.Timeout = timeout;
141 request.ContentType = "application/x-www-form-urlencoded"; 297 request.KeepAlive = false;
298 request.MaximumAutomaticRedirections = 10;
299 request.ReadWriteTimeout = timeout / 4;
300 request.Headers[OSHeaderRequestID] = reqnum.ToString();
301
302 if (data != null)
303 {
304 string queryString = BuildQueryString(data);
305 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString);
306
307 request.ContentLength = buffer.Length;
308 request.ContentType = "application/x-www-form-urlencoded";
309 using (Stream requestStream = request.GetRequestStream())
310 requestStream.Write(buffer, 0, buffer.Length);
311 }
142 312
143 Stream requestStream = request.GetRequestStream(); 313 // capture how much time was spent writing, this may seem silly
144 requestStream.Write(requestData, 0, requestData.Length); 314 // but with the number concurrent requests, this often blocks
145 requestStream.Close(); 315 tickdata = Util.EnvironmentTickCountSubtract(tickstart);
146 316
147 using (WebResponse response = request.GetResponse()) 317 using (WebResponse response = request.GetResponse())
148 { 318 {
@@ -150,34 +320,50 @@ namespace OpenSim.Framework
150 { 320 {
151 string responseStr = null; 321 string responseStr = null;
152 322
153 try 323 responseStr = responseStream.GetStreamString();
154 { 324 OSD responseOSD = OSDParser.Deserialize(responseStr);
155 responseStr = responseStream.GetStreamString(); 325 if (responseOSD.Type == OSDType.Map)
156 OSD responseOSD = OSDParser.Deserialize(responseStr); 326 return (OSDMap)responseOSD;
157 if (responseOSD.Type == OSDType.Map)
158 return (OSDMap)responseOSD;
159 else
160 errorMessage = "Response format was invalid.";
161 }
162 catch (Exception ex)
163 {
164 if (!String.IsNullOrEmpty(responseStr))
165 errorMessage = "Failed to parse the response:\n" + responseStr;
166 else
167 errorMessage = "Failed to retrieve the response: " + ex.Message;
168 }
169 } 327 }
170 } 328 }
171 } 329 }
330 catch (WebException we)
331 {
332 errorMessage = we.Message;
333 if (we.Status == WebExceptionStatus.ProtocolError)
334 {
335 HttpWebResponse webResponse = (HttpWebResponse)we.Response;
336 errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription);
337 }
338 }
172 catch (Exception ex) 339 catch (Exception ex)
173 { 340 {
174 m_log.Warn("POST to URL " + url + " failed: " + ex);
175 errorMessage = ex.Message; 341 errorMessage = ex.Message;
176 } 342 }
343 finally
344 {
345 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
346 if (tickdiff > LongCallTime)
347 m_log.InfoFormat("[WEB UTIL]: form request <{0}> (URI:{1}, METHOD:{2}) took {3}ms overall, {4}ms writing",
348 reqnum,url,method,tickdiff,tickdata);
349 }
177 350
178 return new OSDMap { { "Message", OSD.FromString("Service request failed. " + errorMessage) } }; 351 m_log.WarnFormat("[WEB UTIL]: <{0}> form request failed: {1}",reqnum,errorMessage);
352 return ErrorResponseMap(errorMessage);
179 } 353 }
180 354
355 /// <summary>
356 /// Create a response map for an error, trying to keep
357 /// the result formats consistent
358 /// </summary>
359 private static OSDMap ErrorResponseMap(string msg)
360 {
361 OSDMap result = new OSDMap();
362 result["Success"] = "False";
363 result["Message"] = OSD.FromString("Service request failed: " + msg);
364 return result;
365 }
366
181 #region Uri 367 #region Uri
182 368
183 /// <summary> 369 /// <summary>