diff options
author | Melanie | 2011-01-06 19:08:15 +0000 |
---|---|---|
committer | Melanie | 2011-01-06 19:08:15 +0000 |
commit | de4eaab5847b6c4c5eb4c8c07191b8c463d0b3ad (patch) | |
tree | 7b9865d97acfd441edb97d12ce8286eb48901cee /OpenSim/Framework | |
parent | Fix god mode perms adjustment (diff) | |
parent | Merge branch 'master' into cmickeyb (diff) | |
download | opensim-SC_OLD-de4eaab5847b6c4c5eb4c8c07191b8c463d0b3ad.zip opensim-SC_OLD-de4eaab5847b6c4c5eb4c8c07191b8c463d0b3ad.tar.gz opensim-SC_OLD-de4eaab5847b6c4c5eb4c8c07191b8c463d0b3ad.tar.bz2 opensim-SC_OLD-de4eaab5847b6c4c5eb4c8c07191b8c463d0b3ad.tar.xz |
Merge branch 'master' into careminster-presence-refactor
Diffstat (limited to 'OpenSim/Framework')
-rw-r--r-- | OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 16 | ||||
-rw-r--r-- | OpenSim/Framework/WebUtil.cs | 240 |
2 files changed, 228 insertions, 28 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 3343f60..86ad7aa 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | |||
@@ -346,9 +346,15 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
346 | /// <param name="response"></param> | 346 | /// <param name="response"></param> |
347 | public virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response) | 347 | public virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response) |
348 | { | 348 | { |
349 | string reqnum = "unknown"; | ||
350 | int tickstart = Environment.TickCount; | ||
351 | |||
349 | try | 352 | try |
350 | { | 353 | { |
351 | //m_log.Debug("[BASE HTTP SERVER]: Handling request to " + request.RawUrl); | 354 | // OpenSim.Framework.WebUtil.OSHeaderRequestID |
355 | if (request.Headers["opensim-request-id"] != null) | ||
356 | reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); | ||
357 | // m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); | ||
352 | 358 | ||
353 | Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); | 359 | Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); |
354 | 360 | ||
@@ -576,6 +582,14 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
576 | m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); | 582 | m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); |
577 | SendHTML500(response); | 583 | SendHTML500(response); |
578 | } | 584 | } |
585 | finally | ||
586 | { | ||
587 | // Every month or so this will wrap and give bad numbers, not really a problem | ||
588 | // since its just for reporting, 200ms limit can be adjusted | ||
589 | int tickdiff = Environment.TickCount - tickstart; | ||
590 | if (tickdiff > 200) | ||
591 | m_log.InfoFormat("[BASE HTTP SERVER]: slow request <{0}> for {1} took {2} ms",reqnum,request.RawUrl,tickdiff); | ||
592 | } | ||
579 | } | 593 | } |
580 | 594 | ||
581 | private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler) | 595 | private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler) |
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> |