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.cs928
1 files changed, 588 insertions, 340 deletions
diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs
index 5c34cf4..b180c8a 100644
--- a/OpenSim/Framework/WebUtil.cs
+++ b/OpenSim/Framework/WebUtil.cs
@@ -39,8 +39,13 @@ using System.Text;
39using System.Web; 39using System.Web;
40using System.Xml; 40using System.Xml;
41using System.Xml.Serialization; 41using System.Xml.Serialization;
42using System.Xml.Linq;
42using log4net; 43using log4net;
44using Nwc.XmlRpc;
43using OpenMetaverse.StructuredData; 45using OpenMetaverse.StructuredData;
46using XMLResponseHelper = OpenSim.Framework.SynchronousRestObjectRequester.XMLResponseHelper;
47
48using OpenSim.Framework.ServiceAuth;
44 49
45namespace OpenSim.Framework 50namespace OpenSim.Framework
46{ 51{
@@ -64,7 +69,12 @@ namespace OpenSim.Framework
64 /// <summary> 69 /// <summary>
65 /// Request number for diagnostic purposes. 70 /// Request number for diagnostic purposes.
66 /// </summary> 71 /// </summary>
67 public static int RequestNumber { get; internal set; } 72 public static int RequestNumber { get; set; }
73
74 /// <summary>
75 /// Control where OSD requests should be serialized per endpoint.
76 /// </summary>
77 public static bool SerializeOSDRequestsPerEndpoint { get; set; }
68 78
69 /// <summary> 79 /// <summary>
70 /// this is the header field used to communicate the local request id 80 /// this is the header field used to communicate the local request id
@@ -84,8 +94,9 @@ namespace OpenSim.Framework
84 /// <remarks> 94 /// <remarks>
85 /// This is to truncate any really large post data, such as an asset. In theory, the first section should 95 /// This is to truncate any really large post data, such as an asset. In theory, the first section should
86 /// give us useful information about the call (which agent it relates to if applicable, etc.). 96 /// give us useful information about the call (which agent it relates to if applicable, etc.).
97 /// This is also used to truncate messages when using DebugLevel 5.
87 /// </remarks> 98 /// </remarks>
88 public const int MaxRequestDiagLength = 100; 99 public const int MaxRequestDiagLength = 200;
89 100
90 /// <summary> 101 /// <summary>
91 /// Dictionary of end points 102 /// Dictionary of end points
@@ -120,45 +131,104 @@ namespace OpenSim.Framework
120 /// </summary> 131 /// </summary>
121 public static OSDMap PutToServiceCompressed(string url, OSDMap data, int timeout) 132 public static OSDMap PutToServiceCompressed(string url, OSDMap data, int timeout)
122 { 133 {
123 return ServiceOSDRequest(url,data, "PUT", timeout, true); 134 return ServiceOSDRequest(url,data, "PUT", timeout, true, false);
124 } 135 }
125 136
126 public static OSDMap PutToService(string url, OSDMap data, int timeout) 137 public static OSDMap PutToService(string url, OSDMap data, int timeout)
127 { 138 {
128 return ServiceOSDRequest(url,data, "PUT", timeout, false); 139 return ServiceOSDRequest(url,data, "PUT", timeout, false, false);
129 } 140 }
130 141
131 public static OSDMap PostToService(string url, OSDMap data, int timeout) 142 public static OSDMap PostToService(string url, OSDMap data, int timeout, bool rpc)
132 { 143 {
133 return ServiceOSDRequest(url, data, "POST", timeout, false); 144 return ServiceOSDRequest(url, data, "POST", timeout, false, rpc);
134 } 145 }
135 146
136 public static OSDMap PostToServiceCompressed(string url, OSDMap data, int timeout) 147 public static OSDMap PostToServiceCompressed(string url, OSDMap data, int timeout)
137 { 148 {
138 return ServiceOSDRequest(url, data, "POST", timeout, true); 149 return ServiceOSDRequest(url, data, "POST", timeout, true, false);
139 } 150 }
140 151
141 public static OSDMap GetFromService(string url, int timeout) 152 public static OSDMap GetFromService(string url, int timeout)
142 { 153 {
143 return ServiceOSDRequest(url, null, "GET", timeout, false); 154 return ServiceOSDRequest(url, null, "GET", timeout, false, false);
144 } 155 }
145 156
146 public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed) 157 public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed, bool rpc)
147 { 158 {
148 lock (EndPointLock(url)) 159 if (SerializeOSDRequestsPerEndpoint)
160 {
161 lock (EndPointLock(url))
162 {
163 return ServiceOSDRequestWorker(url, data, method, timeout, compressed, rpc);
164 }
165 }
166 else
149 { 167 {
150 return ServiceOSDRequestWorker(url,data,method,timeout,compressed); 168 return ServiceOSDRequestWorker(url, data, method, timeout, compressed, rpc);
151 } 169 }
152 } 170 }
153 171
154 private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) 172 public static void LogOutgoingDetail(Stream outputStream)
173 {
174 LogOutgoingDetail("", outputStream);
175 }
176
177 public static void LogOutgoingDetail(string context, Stream outputStream)
178 {
179 using (Stream stream = Util.Copy(outputStream))
180 using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
181 {
182 string output;
183
184 if (DebugLevel == 5)
185 {
186 char[] chars = new char[WebUtil.MaxRequestDiagLength + 1]; // +1 so we know to add "..." only if needed
187 int len = reader.Read(chars, 0, WebUtil.MaxRequestDiagLength + 1);
188 output = new string(chars, 0, len);
189 }
190 else
191 {
192 output = reader.ReadToEnd();
193 }
194
195 LogOutgoingDetail(context, output);
196 }
197 }
198
199 public static void LogOutgoingDetail(string type, int reqnum, string output)
200 {
201 LogOutgoingDetail(string.Format("{0} {1}: ", type, reqnum), output);
202 }
203
204 public static void LogOutgoingDetail(string context, string output)
205 {
206 if (DebugLevel == 5)
207 {
208 if (output.Length > MaxRequestDiagLength)
209 output = output.Substring(0, MaxRequestDiagLength) + "...";
210 }
211
212 m_log.DebugFormat("[LOGHTTP]: {0}{1}", context, Util.BinaryToASCII(output));
213 }
214
215 public static void LogResponseDetail(int reqnum, Stream inputStream)
216 {
217 LogOutgoingDetail(string.Format("RESPONSE {0}: ", reqnum), inputStream);
218 }
219
220 public static void LogResponseDetail(int reqnum, string input)
221 {
222 LogOutgoingDetail(string.Format("RESPONSE {0}: ", reqnum), input);
223 }
224
225 private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed, bool rpc)
155 { 226 {
156 int reqnum = RequestNumber++; 227 int reqnum = RequestNumber++;
157 228
158 if (DebugLevel >= 3) 229 if (DebugLevel >= 3)
159 m_log.DebugFormat( 230 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} JSON-RPC {1} to {2}",
160 "[WEB UTIL]: HTTP OUT {0} ServiceOSD {1} {2} (timeout {3}, compressed {4})", 231 reqnum, method, url);
161 reqnum, method, url, timeout, compressed);
162 232
163 string errorMessage = "unknown error"; 233 string errorMessage = "unknown error";
164 int tickstart = Util.EnvironmentTickCount(); 234 int tickstart = Util.EnvironmentTickCount();
@@ -178,20 +248,27 @@ namespace OpenSim.Framework
178 // If there is some input, write it into the request 248 // If there is some input, write it into the request
179 if (data != null) 249 if (data != null)
180 { 250 {
181 strBuffer = OSDParser.SerializeJsonString(data); 251 strBuffer = OSDParser.SerializeJsonString(data);
252
253 if (DebugLevel >= 5)
254 LogOutgoingDetail("SEND", reqnum, strBuffer);
255
182 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer); 256 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer);
183 257
258 request.ContentType = rpc ? "application/json-rpc" : "application/json";
259
184 if (compressed) 260 if (compressed)
185 { 261 {
186 request.ContentType = "application/x-gzip"; 262 request.Headers["X-Content-Encoding"] = "gzip"; // can't set "Content-Encoding" because old OpenSims fail if they get an unrecognized Content-Encoding
263
187 using (MemoryStream ms = new MemoryStream()) 264 using (MemoryStream ms = new MemoryStream())
188 { 265 {
189 using (GZipStream comp = new GZipStream(ms, CompressionMode.Compress)) 266 using (GZipStream comp = new GZipStream(ms, CompressionMode.Compress, true))
190 { 267 {
191 comp.Write(buffer, 0, buffer.Length); 268 comp.Write(buffer, 0, buffer.Length);
192 // We need to close the gzip stream before we write it anywhere 269 // We need to close the gzip stream before we write it anywhere
193 // because apparently something important related to gzip compression 270 // because apparently something important related to gzip compression
194 // gets written on the strteam upon Dispose() 271 // gets written on the stream upon Dispose()
195 } 272 }
196 byte[] buf = ms.ToArray(); 273 byte[] buf = ms.ToArray();
197 request.ContentLength = buf.Length; //Count bytes to send 274 request.ContentLength = buf.Length; //Count bytes to send
@@ -201,10 +278,9 @@ namespace OpenSim.Framework
201 } 278 }
202 else 279 else
203 { 280 {
204 request.ContentType = "application/json";
205 request.ContentLength = buffer.Length; //Count bytes to send 281 request.ContentLength = buffer.Length; //Count bytes to send
206 using (Stream requestStream = request.GetRequestStream()) 282 using (Stream requestStream = request.GetRequestStream())
207 requestStream.Write(buffer, 0, buffer.Length); //Send it 283 requestStream.Write(buffer, 0, buffer.Length); //Send it
208 } 284 }
209 } 285 }
210 286
@@ -216,10 +292,13 @@ namespace OpenSim.Framework
216 { 292 {
217 using (Stream responseStream = response.GetResponseStream()) 293 using (Stream responseStream = response.GetResponseStream())
218 { 294 {
219 string responseStr = null; 295 using (StreamReader reader = new StreamReader(responseStream))
220 responseStr = responseStream.GetStreamString(); 296 {
221 // m_log.DebugFormat("[WEB UTIL]: <{0}> response is <{1}>",reqnum,responseStr); 297 string responseStr = reader.ReadToEnd();
222 return CanonicalizeResults(responseStr); 298 if (WebUtil.DebugLevel >= 5)
299 WebUtil.LogResponseDetail(reqnum, responseStr);
300 return CanonicalizeResults(responseStr);
301 }
223 } 302 }
224 } 303 }
225 } 304 }
@@ -228,8 +307,8 @@ namespace OpenSim.Framework
228 errorMessage = we.Message; 307 errorMessage = we.Message;
229 if (we.Status == WebExceptionStatus.ProtocolError) 308 if (we.Status == WebExceptionStatus.ProtocolError)
230 { 309 {
231 HttpWebResponse webResponse = (HttpWebResponse)we.Response; 310 using (HttpWebResponse webResponse = (HttpWebResponse)we.Response)
232 errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription); 311 errorMessage = String.Format("[{0}] {1}", webResponse.StatusCode, webResponse.StatusDescription);
233 } 312 }
234 } 313 }
235 catch (Exception ex) 314 catch (Exception ex)
@@ -240,24 +319,23 @@ namespace OpenSim.Framework
240 { 319 {
241 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 320 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
242 if (tickdiff > LongCallTime) 321 if (tickdiff > LongCallTime)
322 {
243 m_log.InfoFormat( 323 m_log.InfoFormat(
244 "[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing, {5}", 324 "[LOGHTTP]: Slow JSON-RPC request {0} {1} to {2} took {3}ms, {4}ms writing, {5}",
245 reqnum, 325 reqnum, method, url, tickdiff, tickdata,
246 method,
247 url,
248 tickdiff,
249 tickdata,
250 strBuffer != null 326 strBuffer != null
251 ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer) 327 ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer)
252 : ""); 328 : "");
329 }
253 else if (DebugLevel >= 4) 330 else if (DebugLevel >= 4)
254 m_log.DebugFormat( 331 {
255 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", 332 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing",
256 reqnum, tickdiff, tickdata); 333 reqnum, tickdiff, tickdata);
334 }
257 } 335 }
258 336
259 m_log.DebugFormat( 337 m_log.DebugFormat(
260 "[WEB UTIL]: ServiceOSD request {0} {1} {2} FAILED: {3}", reqnum, url, method, errorMessage); 338 "[LOGHTTP]: JSON-RPC request {0} {1} to {2} FAILED: {3}", reqnum, method, url, errorMessage);
261 339
262 return ErrorResponseMap(errorMessage); 340 return ErrorResponseMap(errorMessage);
263 } 341 }
@@ -335,9 +413,8 @@ namespace OpenSim.Framework
335 string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown"; 413 string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown";
336 414
337 if (DebugLevel >= 3) 415 if (DebugLevel >= 3)
338 m_log.DebugFormat( 416 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} ServiceForm '{1}' to {2}",
339 "[WEB UTIL]: HTTP OUT {0} ServiceForm {1} {2} (timeout {3})", 417 reqnum, method, url);
340 reqnum, method, url, timeout);
341 418
342 string errorMessage = "unknown error"; 419 string errorMessage = "unknown error";
343 int tickstart = Util.EnvironmentTickCount(); 420 int tickstart = Util.EnvironmentTickCount();
@@ -357,6 +434,10 @@ namespace OpenSim.Framework
357 if (data != null) 434 if (data != null)
358 { 435 {
359 queryString = BuildQueryString(data); 436 queryString = BuildQueryString(data);
437
438 if (DebugLevel >= 5)
439 LogOutgoingDetail("SEND", reqnum, queryString);
440
360 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString); 441 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString);
361 442
362 request.ContentLength = buffer.Length; 443 request.ContentLength = buffer.Length;
@@ -373,12 +454,16 @@ namespace OpenSim.Framework
373 { 454 {
374 using (Stream responseStream = response.GetResponseStream()) 455 using (Stream responseStream = response.GetResponseStream())
375 { 456 {
376 string responseStr = null; 457 using (StreamReader reader = new StreamReader(responseStream))
458 {
459 string responseStr = reader.ReadToEnd();
460 if (WebUtil.DebugLevel >= 5)
461 WebUtil.LogResponseDetail(reqnum, responseStr);
462 OSD responseOSD = OSDParser.Deserialize(responseStr);
377 463
378 responseStr = responseStream.GetStreamString(); 464 if (responseOSD.Type == OSDType.Map)
379 OSD responseOSD = OSDParser.Deserialize(responseStr); 465 return (OSDMap)responseOSD;
380 if (responseOSD.Type == OSDType.Map) 466 }
381 return (OSDMap)responseOSD;
382 } 467 }
383 } 468 }
384 } 469 }
@@ -387,8 +472,8 @@ namespace OpenSim.Framework
387 errorMessage = we.Message; 472 errorMessage = we.Message;
388 if (we.Status == WebExceptionStatus.ProtocolError) 473 if (we.Status == WebExceptionStatus.ProtocolError)
389 { 474 {
390 HttpWebResponse webResponse = (HttpWebResponse)we.Response; 475 using (HttpWebResponse webResponse = (HttpWebResponse)we.Response)
391 errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription); 476 errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription);
392 } 477 }
393 } 478 }
394 catch (Exception ex) 479 catch (Exception ex)
@@ -399,23 +484,22 @@ namespace OpenSim.Framework
399 { 484 {
400 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 485 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
401 if (tickdiff > LongCallTime) 486 if (tickdiff > LongCallTime)
487 {
402 m_log.InfoFormat( 488 m_log.InfoFormat(
403 "[WEB UTIL]: Slow ServiceForm request {0} {1} {2} took {3}ms, {4}ms writing, {5}", 489 "[LOGHTTP]: Slow ServiceForm request {0} '{1}' to {2} took {3}ms, {4}ms writing, {5}",
404 reqnum, 490 reqnum, method, url, tickdiff, tickdata,
405 method,
406 url,
407 tickdiff,
408 tickdata,
409 queryString != null 491 queryString != null
410 ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString 492 ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString
411 : ""); 493 : "");
494 }
412 else if (DebugLevel >= 4) 495 else if (DebugLevel >= 4)
413 m_log.DebugFormat( 496 {
414 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", 497 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing",
415 reqnum, tickdiff, tickdata); 498 reqnum, tickdiff, tickdata);
499 }
416 } 500 }
417 501
418 m_log.WarnFormat("[WEB UTIL]: ServiceForm request {0} {1} {2} failed: {2}", reqnum, method, url, errorMessage); 502 m_log.WarnFormat("[LOGHTTP]: ServiceForm request {0} '{1}' to {2} failed: {3}", reqnum, method, url, errorMessage);
419 503
420 return ErrorResponseMap(errorMessage); 504 return ErrorResponseMap(errorMessage);
421 } 505 }
@@ -592,38 +676,6 @@ namespace OpenSim.Framework
592 return totalCopiedBytes; 676 return totalCopiedBytes;
593 } 677 }
594 678
595 /// <summary>
596 /// Converts an entire stream to a string, regardless of current stream
597 /// position
598 /// </summary>
599 /// <param name="stream">The stream to convert to a string</param>
600 /// <returns></returns>
601 /// <remarks>When this method is done, the stream position will be
602 /// reset to its previous position before this method was called</remarks>
603 public static string GetStreamString(this Stream stream)
604 {
605 string value = null;
606
607 if (stream != null && stream.CanRead)
608 {
609 long rewindPos = -1;
610
611 if (stream.CanSeek)
612 {
613 rewindPos = stream.Position;
614 stream.Seek(0, SeekOrigin.Begin);
615 }
616
617 StreamReader reader = new StreamReader(stream);
618 value = reader.ReadToEnd();
619
620 if (rewindPos >= 0)
621 stream.Seek(rewindPos, SeekOrigin.Begin);
622 }
623
624 return value;
625 }
626
627 #endregion Stream 679 #endregion Stream
628 680
629 public class QBasedComparer : IComparer 681 public class QBasedComparer : IComparer
@@ -667,7 +719,7 @@ namespace OpenSim.Framework
667 /// <returns></returns> 719 /// <returns></returns>
668 public static string[] GetPreferredImageTypes(string accept) 720 public static string[] GetPreferredImageTypes(string accept)
669 { 721 {
670 if (accept == null || accept == string.Empty) 722 if (string.IsNullOrEmpty(accept))
671 return new string[0]; 723 return new string[0];
672 724
673 string[] types = accept.Split(new char[] { ',' }); 725 string[] types = accept.Split(new char[] { ',' });
@@ -724,11 +776,17 @@ namespace OpenSim.Framework
724 string requestUrl, TRequest obj, Action<TResponse> action, 776 string requestUrl, TRequest obj, Action<TResponse> action,
725 int maxConnections) 777 int maxConnections)
726 { 778 {
779 MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, action, maxConnections, null);
780 }
781
782 public static void MakeRequest<TRequest, TResponse>(string verb,
783 string requestUrl, TRequest obj, Action<TResponse> action,
784 int maxConnections, IServiceAuth auth)
785 {
727 int reqnum = WebUtil.RequestNumber++; 786 int reqnum = WebUtil.RequestNumber++;
728 787
729 if (WebUtil.DebugLevel >= 3) 788 if (WebUtil.DebugLevel >= 3)
730 m_log.DebugFormat( 789 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} AsynchronousRequestObject {1} to {2}",
731 "[WEB UTIL]: HTTP OUT {0} AsynchronousRequestObject {1} {2}",
732 reqnum, verb, requestUrl); 790 reqnum, verb, requestUrl);
733 791
734 int tickstart = Util.EnvironmentTickCount(); 792 int tickstart = Util.EnvironmentTickCount();
@@ -738,171 +796,174 @@ namespace OpenSim.Framework
738 796
739 WebRequest request = WebRequest.Create(requestUrl); 797 WebRequest request = WebRequest.Create(requestUrl);
740 HttpWebRequest ht = (HttpWebRequest)request; 798 HttpWebRequest ht = (HttpWebRequest)request;
799
800 if (auth != null)
801 auth.AddAuthorization(ht.Headers);
802
741 if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections) 803 if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
742 ht.ServicePoint.ConnectionLimit = maxConnections; 804 ht.ServicePoint.ConnectionLimit = maxConnections;
743 805
744 WebResponse response = null;
745 TResponse deserial = default(TResponse); 806 TResponse deserial = default(TResponse);
746 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
747 807
748 request.Method = verb; 808 request.Method = verb;
809
749 MemoryStream buffer = null; 810 MemoryStream buffer = null;
750 811
751 if (verb == "POST") 812 try
752 { 813 {
753 request.ContentType = "text/xml"; 814 if (verb == "POST")
815 {
816 request.ContentType = "text/xml";
754 817
755 buffer = new MemoryStream(); 818 buffer = new MemoryStream();
756 819
757 XmlWriterSettings settings = new XmlWriterSettings(); 820 XmlWriterSettings settings = new XmlWriterSettings();
758 settings.Encoding = Encoding.UTF8; 821 settings.Encoding = Encoding.UTF8;
759 822
760 using (XmlWriter writer = XmlWriter.Create(buffer, settings)) 823 using (XmlWriter writer = XmlWriter.Create(buffer, settings))
761 { 824 {
762 XmlSerializer serializer = new XmlSerializer(type); 825 XmlSerializer serializer = new XmlSerializer(type);
763 serializer.Serialize(writer, obj); 826 serializer.Serialize(writer, obj);
764 writer.Flush(); 827 writer.Flush();
765 } 828 }
766 829
767 int length = (int)buffer.Length; 830 int length = (int)buffer.Length;
768 request.ContentLength = length; 831 request.ContentLength = length;
832 byte[] data = buffer.ToArray();
769 833
770 request.BeginGetRequestStream(delegate(IAsyncResult res) 834 if (WebUtil.DebugLevel >= 5)
771 { 835 WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data));
772 Stream requestStream = request.EndGetRequestStream(res);
773 836
774 requestStream.Write(buffer.ToArray(), 0, length); 837 request.BeginGetRequestStream(delegate(IAsyncResult res)
775 requestStream.Close(); 838 {
839 using (Stream requestStream = request.EndGetRequestStream(res))
840 requestStream.Write(data, 0, length);
776 841
777 // capture how much time was spent writing 842 // capture how much time was spent writing
778 tickdata = Util.EnvironmentTickCountSubtract(tickstart); 843 tickdata = Util.EnvironmentTickCountSubtract(tickstart);
779 844
780 request.BeginGetResponse(delegate(IAsyncResult ar) 845 request.BeginGetResponse(delegate(IAsyncResult ar)
781 {
782 response = request.EndGetResponse(ar);
783 Stream respStream = null;
784 try
785 { 846 {
786 respStream = response.GetResponseStream(); 847 using (WebResponse response = request.EndGetResponse(ar))
787 deserial = (TResponse)deserializer.Deserialize( 848 {
788 respStream); 849 try
789 } 850 {
790 catch (System.InvalidOperationException) 851 using (Stream respStream = response.GetResponseStream())
791 { 852 {
792 } 853 deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>(
793 finally 854 reqnum, respStream, response.ContentLength);
794 { 855 }
795 // Let's not close this 856 }
796 //buffer.Close(); 857 catch (System.InvalidOperationException)
797 respStream.Close(); 858 {
798 response.Close(); 859 }
799 } 860 }
800 861
801 action(deserial); 862 action(deserial);
802 863
864 }, null);
803 }, null); 865 }, null);
804 }, null); 866 }
805 } 867 else
806 else
807 {
808 request.BeginGetResponse(delegate(IAsyncResult res2)
809 { 868 {
810 try 869 request.BeginGetResponse(delegate(IAsyncResult res2)
811 { 870 {
812 // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't
813 // documented in MSDN
814 response = request.EndGetResponse(res2);
815
816 Stream respStream = null;
817 try 871 try
818 { 872 {
819 respStream = response.GetResponseStream(); 873 // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't
820 deserial = (TResponse)deserializer.Deserialize(respStream); 874 // documented in MSDN
821 } 875 using (WebResponse response = request.EndGetResponse(res2))
822 catch (System.InvalidOperationException) 876 {
823 { 877 try
824 } 878 {
825 finally 879 using (Stream respStream = response.GetResponseStream())
826 { 880 {
827 respStream.Close(); 881 deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>(
828 response.Close(); 882 reqnum, respStream, response.ContentLength);
883 }
884 }
885 catch (System.InvalidOperationException)
886 {
887 }
888 }
829 } 889 }
830 } 890 catch (WebException e)
831 catch (WebException e)
832 {
833 if (e.Status == WebExceptionStatus.ProtocolError)
834 { 891 {
835 if (e.Response is HttpWebResponse) 892 if (e.Status == WebExceptionStatus.ProtocolError)
836 { 893 {
837 HttpWebResponse httpResponse = (HttpWebResponse)e.Response; 894 if (e.Response is HttpWebResponse)
838
839 if (httpResponse.StatusCode != HttpStatusCode.NotFound)
840 { 895 {
841 // We don't appear to be handling any other status codes, so log these feailures to that 896 using (HttpWebResponse httpResponse = (HttpWebResponse)e.Response)
842 // people don't spend unnecessary hours hunting phantom bugs. 897 {
843 m_log.DebugFormat( 898 if (httpResponse.StatusCode != HttpStatusCode.NotFound)
844 "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}", 899 {
845 verb, requestUrl, httpResponse.StatusCode); 900 // We don't appear to be handling any other status codes, so log these feailures to that
901 // people don't spend unnecessary hours hunting phantom bugs.
902 m_log.DebugFormat(
903 "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}",
904 verb, requestUrl, httpResponse.StatusCode);
905 }
906 }
846 } 907 }
847 } 908 }
909 else
910 {
911 m_log.ErrorFormat(
912 "[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}",
913 verb, requestUrl, e.Status, e.Message);
914 }
848 } 915 }
849 else 916 catch (Exception e)
850 { 917 {
851 m_log.ErrorFormat( 918 m_log.ErrorFormat(
852 "[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", 919 "[ASYNC REQUEST]: Request {0} {1} failed with exception {2}{3}",
853 verb, requestUrl, e.Status, e.Message); 920 verb, requestUrl, e.Message, e.StackTrace);
854 } 921 }
855 } 922
856 catch (Exception e) 923 // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString());
857 {
858 m_log.ErrorFormat(
859 "[ASYNC REQUEST]: Request {0} {1} failed with exception {2}{3}",
860 verb, requestUrl, e.Message, e.StackTrace);
861 }
862
863 // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString());
864 924
865 try 925 try
866 { 926 {
867 action(deserial); 927 action(deserial);
868 } 928 }
869 catch (Exception e) 929 catch (Exception e)
930 {
931 m_log.ErrorFormat(
932 "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}{3}",
933 verb, requestUrl, e.Message, e.StackTrace);
934 }
935
936 }, null);
937 }
938
939 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
940 if (tickdiff > WebUtil.LongCallTime)
941 {
942 string originalRequest = null;
943
944 if (buffer != null)
870 { 945 {
871 m_log.ErrorFormat( 946 originalRequest = Encoding.UTF8.GetString(buffer.ToArray());
872 "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}{3}",
873 verb, requestUrl, e.Message, e.StackTrace);
874 }
875
876 }, null);
877 }
878 947
879 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 948 if (originalRequest.Length > WebUtil.MaxRequestDiagLength)
880 if (tickdiff > WebUtil.LongCallTime) 949 originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength);
881 { 950 }
882 string originalRequest = null;
883 951
884 if (buffer != null) 952 m_log.InfoFormat(
953 "[LOGHTTP]: Slow AsynchronousRequestObject request {0} {1} to {2} took {3}ms, {4}ms writing, {5}",
954 reqnum, verb, requestUrl, tickdiff, tickdata,
955 originalRequest);
956 }
957 else if (WebUtil.DebugLevel >= 4)
885 { 958 {
886 originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); 959 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing",
887 960 reqnum, tickdiff, tickdata);
888 if (originalRequest.Length > WebUtil.MaxRequestDiagLength)
889 originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength);
890 } 961 }
891
892 m_log.InfoFormat(
893 "[ASYNC REQUEST]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
894 reqnum,
895 verb,
896 requestUrl,
897 tickdiff,
898 tickdata,
899 originalRequest);
900 } 962 }
901 else if (WebUtil.DebugLevel >= 4) 963 finally
902 { 964 {
903 m_log.DebugFormat( 965 if (buffer != null)
904 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", 966 buffer.Dispose();
905 reqnum, tickdiff, tickdata);
906 } 967 }
907 } 968 }
908 } 969 }
@@ -917,17 +978,17 @@ namespace OpenSim.Framework
917 /// <param name="verb"></param> 978 /// <param name="verb"></param>
918 /// <param name="requestUrl"></param> 979 /// <param name="requestUrl"></param>
919 /// <param name="obj"> </param> 980 /// <param name="obj"> </param>
981 /// <param name="timeoutsecs"> </param>
920 /// <returns></returns> 982 /// <returns></returns>
921 /// 983 ///
922 /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting 984 /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting
923 /// the request. You'll want to make sure you deal with this as they're not uncommon</exception> 985 /// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
924 public static string MakeRequest(string verb, string requestUrl, string obj) 986 public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs, IServiceAuth auth)
925 { 987 {
926 int reqnum = WebUtil.RequestNumber++; 988 int reqnum = WebUtil.RequestNumber++;
927 989
928 if (WebUtil.DebugLevel >= 3) 990 if (WebUtil.DebugLevel >= 3)
929 m_log.DebugFormat( 991 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} SynchronousRestForms {1} to {2}",
930 "[WEB UTIL]: HTTP OUT {0} SynchronousRestForms {1} {2}",
931 reqnum, verb, requestUrl); 992 reqnum, verb, requestUrl);
932 993
933 int tickstart = Util.EnvironmentTickCount(); 994 int tickstart = Util.EnvironmentTickCount();
@@ -935,6 +996,12 @@ namespace OpenSim.Framework
935 996
936 WebRequest request = WebRequest.Create(requestUrl); 997 WebRequest request = WebRequest.Create(requestUrl);
937 request.Method = verb; 998 request.Method = verb;
999 if (timeoutsecs > 0)
1000 request.Timeout = timeoutsecs * 1000;
1001
1002 if (auth != null)
1003 auth.AddAuthorization(request.Headers);
1004
938 string respstring = String.Empty; 1005 string respstring = String.Empty;
939 1006
940 using (MemoryStream buffer = new MemoryStream()) 1007 using (MemoryStream buffer = new MemoryStream())
@@ -952,22 +1019,27 @@ namespace OpenSim.Framework
952 1019
953 length = (int)obj.Length; 1020 length = (int)obj.Length;
954 request.ContentLength = length; 1021 request.ContentLength = length;
1022 byte[] data = buffer.ToArray();
1023
1024 if (WebUtil.DebugLevel >= 5)
1025 WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data));
955 1026
956 Stream requestStream = null; 1027 Stream requestStream = null;
957 try 1028 try
958 { 1029 {
959 requestStream = request.GetRequestStream(); 1030 requestStream = request.GetRequestStream();
960 requestStream.Write(buffer.ToArray(), 0, length); 1031 requestStream.Write(data, 0, length);
961 } 1032 }
962 catch (Exception e) 1033 catch (Exception e)
963 { 1034 {
964 m_log.DebugFormat( 1035 m_log.InfoFormat("[FORMS]: Error sending request to {0}: {1}. Request: {2}", requestUrl, e.Message,
965 "[FORMS]: exception occured {0} {1}: {2}{3}", verb, requestUrl, e.Message, e.StackTrace); 1036 obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
1037 throw e;
966 } 1038 }
967 finally 1039 finally
968 { 1040 {
969 if (requestStream != null) 1041 if (requestStream != null)
970 requestStream.Close(); 1042 requestStream.Dispose();
971 1043
972 // capture how much time was spent writing 1044 // capture how much time was spent writing
973 tickdata = Util.EnvironmentTickCountSubtract(tickstart); 1045 tickdata = Util.EnvironmentTickCountSubtract(tickstart);
@@ -980,53 +1052,54 @@ namespace OpenSim.Framework
980 { 1052 {
981 if (resp.ContentLength != 0) 1053 if (resp.ContentLength != 0)
982 { 1054 {
983 Stream respStream = null; 1055 using (Stream respStream = resp.GetResponseStream())
984 try
985 {
986 respStream = resp.GetResponseStream();
987 using (StreamReader reader = new StreamReader(respStream)) 1056 using (StreamReader reader = new StreamReader(respStream))
988 {
989 respstring = reader.ReadToEnd(); 1057 respstring = reader.ReadToEnd();
990 }
991 }
992 catch (Exception e)
993 {
994 m_log.DebugFormat(
995 "[FORMS]: Exception occured on receiving {0} {1}: {2}{3}",
996 verb, requestUrl, e.Message, e.StackTrace);
997 }
998 finally
999 {
1000 if (respStream != null)
1001 respStream.Close();
1002 }
1003 } 1058 }
1004 } 1059 }
1005 } 1060 }
1006 catch (System.InvalidOperationException) 1061 catch (Exception e)
1007 { 1062 {
1008 // This is what happens when there is invalid XML 1063 m_log.InfoFormat("[FORMS]: Error receiving response from {0}: {1}. Request: {2}", requestUrl, e.Message,
1009 m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving {0} {1}", verb, requestUrl); 1064 obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
1065 throw e;
1010 } 1066 }
1011 } 1067 }
1012 1068
1013 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 1069 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
1014 if (tickdiff > WebUtil.LongCallTime) 1070 if (tickdiff > WebUtil.LongCallTime)
1071 {
1015 m_log.InfoFormat( 1072 m_log.InfoFormat(
1016 "[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", 1073 "[LOGHTTP]: Slow SynchronousRestForms request {0} {1} to {2} took {3}ms, {4}ms writing, {5}",
1017 reqnum, 1074 reqnum, verb, requestUrl, tickdiff, tickdata,
1018 verb,
1019 requestUrl,
1020 tickdiff,
1021 tickdata,
1022 obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); 1075 obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
1076 }
1023 else if (WebUtil.DebugLevel >= 4) 1077 else if (WebUtil.DebugLevel >= 4)
1024 m_log.DebugFormat( 1078 {
1025 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", 1079 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing",
1026 reqnum, tickdiff, tickdata); 1080 reqnum, tickdiff, tickdata);
1081 }
1082
1083 if (WebUtil.DebugLevel >= 5)
1084 WebUtil.LogResponseDetail(reqnum, respstring);
1027 1085
1028 return respstring; 1086 return respstring;
1029 } 1087 }
1088
1089 public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs)
1090 {
1091 return MakeRequest(verb, requestUrl, obj, timeoutsecs, null);
1092 }
1093
1094 public static string MakeRequest(string verb, string requestUrl, string obj)
1095 {
1096 return MakeRequest(verb, requestUrl, obj, -1);
1097 }
1098
1099 public static string MakeRequest(string verb, string requestUrl, string obj, IServiceAuth auth)
1100 {
1101 return MakeRequest(verb, requestUrl, obj, -1, auth);
1102 }
1030 } 1103 }
1031 1104
1032 public class SynchronousRestObjectRequester 1105 public class SynchronousRestObjectRequester
@@ -1040,28 +1113,80 @@ namespace OpenSim.Framework
1040 /// </summary> 1113 /// </summary>
1041 /// <param name="verb"></param> 1114 /// <param name="verb"></param>
1042 /// <param name="requestUrl"></param> 1115 /// <param name="requestUrl"></param>
1043 /// <param name="obj"> </param> 1116 /// <param name="obj"></param>
1044 /// <returns></returns> 1117 /// <returns>
1045 /// 1118 /// The response. If there was an internal exception, then the default(TResponse) is returned.
1046 /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting 1119 /// </returns>
1047 /// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
1048 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj) 1120 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj)
1049 { 1121 {
1050 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0); 1122 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0);
1051 } 1123 }
1052 1124
1125 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, IServiceAuth auth)
1126 {
1127 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0, auth);
1128 }
1129 /// <summary>
1130 /// Perform a synchronous REST request.
1131 /// </summary>
1132 /// <param name="verb"></param>
1133 /// <param name="requestUrl"></param>
1134 /// <param name="obj"></param>
1135 /// <param name="pTimeout">
1136 /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
1137 /// </param>
1138 /// <returns>
1139 /// The response. If there was an internal exception or the request timed out,
1140 /// then the default(TResponse) is returned.
1141 /// </returns>
1053 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout) 1142 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout)
1054 { 1143 {
1055 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0); 1144 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0);
1056 } 1145 }
1057 1146
1147 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, IServiceAuth auth)
1148 {
1149 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0, auth);
1150 }
1151
1152 /// Perform a synchronous REST request.
1153 /// </summary>
1154 /// <param name="verb"></param>
1155 /// <param name="requestUrl"></param>
1156 /// <param name="obj"></param>
1157 /// <param name="pTimeout">
1158 /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
1159 /// </param>
1160 /// <param name="maxConnections"></param>
1161 /// <returns>
1162 /// The response. If there was an internal exception or the request timed out,
1163 /// then the default(TResponse) is returned.
1164 /// </returns>
1058 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections) 1165 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections)
1059 { 1166 {
1167 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, maxConnections, null);
1168 }
1169
1170 /// <summary>
1171 /// Perform a synchronous REST request.
1172 /// </summary>
1173 /// <param name="verb"></param>
1174 /// <param name="requestUrl"></param>
1175 /// <param name="obj"></param>
1176 /// <param name="pTimeout">
1177 /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
1178 /// </param>
1179 /// <param name="maxConnections"></param>
1180 /// <returns>
1181 /// The response. If there was an internal exception or the request timed out,
1182 /// then the default(TResponse) is returned.
1183 /// </returns>
1184 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections, IServiceAuth auth)
1185 {
1060 int reqnum = WebUtil.RequestNumber++; 1186 int reqnum = WebUtil.RequestNumber++;
1061 1187
1062 if (WebUtil.DebugLevel >= 3) 1188 if (WebUtil.DebugLevel >= 3)
1063 m_log.DebugFormat( 1189 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} SynchronousRestObject {1} to {2}",
1064 "[WEB UTIL]: HTTP OUT {0} SynchronousRestObject {1} {2}",
1065 reqnum, verb, requestUrl); 1190 reqnum, verb, requestUrl);
1066 1191
1067 int tickstart = Util.EnvironmentTickCount(); 1192 int tickstart = Util.EnvironmentTickCount();
@@ -1072,129 +1197,252 @@ namespace OpenSim.Framework
1072 1197
1073 WebRequest request = WebRequest.Create(requestUrl); 1198 WebRequest request = WebRequest.Create(requestUrl);
1074 HttpWebRequest ht = (HttpWebRequest)request; 1199 HttpWebRequest ht = (HttpWebRequest)request;
1200
1201 if (auth != null)
1202 auth.AddAuthorization(ht.Headers);
1203
1204 if (pTimeout != 0)
1205 ht.Timeout = pTimeout;
1206
1075 if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections) 1207 if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
1076 ht.ServicePoint.ConnectionLimit = maxConnections; 1208 ht.ServicePoint.ConnectionLimit = maxConnections;
1077 1209
1078 request.Method = verb; 1210 request.Method = verb;
1079 MemoryStream buffer = null; 1211 MemoryStream buffer = null;
1080 1212
1081 if ((verb == "POST") || (verb == "PUT")) 1213 try
1082 { 1214 {
1083 request.ContentType = "text/xml"; 1215 if ((verb == "POST") || (verb == "PUT"))
1216 {
1217 request.ContentType = "text/xml";
1084 1218
1085 buffer = new MemoryStream(); 1219 buffer = new MemoryStream();
1086 1220
1087 XmlWriterSettings settings = new XmlWriterSettings(); 1221 XmlWriterSettings settings = new XmlWriterSettings();
1088 settings.Encoding = Encoding.UTF8; 1222 settings.Encoding = Encoding.UTF8;
1089 1223
1090 using (XmlWriter writer = XmlWriter.Create(buffer, settings)) 1224 using (XmlWriter writer = XmlWriter.Create(buffer, settings))
1091 { 1225 {
1092 XmlSerializer serializer = new XmlSerializer(type); 1226 XmlSerializer serializer = new XmlSerializer(type);
1093 serializer.Serialize(writer, obj); 1227 serializer.Serialize(writer, obj);
1094 writer.Flush(); 1228 writer.Flush();
1095 } 1229 }
1230
1231 int length = (int)buffer.Length;
1232 request.ContentLength = length;
1233 byte[] data = buffer.ToArray();
1234
1235 if (WebUtil.DebugLevel >= 5)
1236 WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data));
1237
1238 try
1239 {
1240 using (Stream requestStream = request.GetRequestStream())
1241 requestStream.Write(data, 0, length);
1242 }
1243 catch (Exception e)
1244 {
1245 m_log.DebugFormat(
1246 "[SynchronousRestObjectRequester]: Exception in making request {0} {1}: {2}{3}",
1247 verb, requestUrl, e.Message, e.StackTrace);
1096 1248
1097 int length = (int)buffer.Length; 1249 return deserial;
1098 request.ContentLength = length; 1250 }
1251 finally
1252 {
1253 // capture how much time was spent writing
1254 tickdata = Util.EnvironmentTickCountSubtract(tickstart);
1255 }
1256 }
1099 1257
1100 Stream requestStream = null;
1101 try 1258 try
1102 { 1259 {
1103 requestStream = request.GetRequestStream(); 1260 using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
1104 requestStream.Write(buffer.ToArray(), 0, length); 1261 {
1262 if (resp.ContentLength != 0)
1263 {
1264 using (Stream respStream = resp.GetResponseStream())
1265 {
1266 deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>(
1267 reqnum, respStream, resp.ContentLength);
1268 }
1269 }
1270 else
1271 {
1272 m_log.DebugFormat(
1273 "[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}",
1274 verb, requestUrl);
1275 }
1276 }
1105 } 1277 }
1106 catch (Exception e) 1278 catch (WebException e)
1107 { 1279 {
1280 using (HttpWebResponse hwr = (HttpWebResponse)e.Response)
1281 {
1282 if (hwr != null)
1283 {
1284 if (hwr.StatusCode == HttpStatusCode.NotFound)
1285 return deserial;
1286 if (hwr.StatusCode == HttpStatusCode.Unauthorized)
1287 {
1288 m_log.Error(string.Format(
1289 "[SynchronousRestObjectRequester]: Web request {0} requires authentication ",
1290 requestUrl));
1291 return deserial;
1292 }
1293 }
1294 else
1295 m_log.Error(string.Format(
1296 "[SynchronousRestObjectRequester]: WebException for {0} {1} {2} ",
1297 verb, requestUrl, typeof(TResponse).ToString()), e);
1298 }
1299 }
1300 catch (System.InvalidOperationException)
1301 {
1302 // This is what happens when there is invalid XML
1108 m_log.DebugFormat( 1303 m_log.DebugFormat(
1109 "[SynchronousRestObjectRequester]: Exception in making request {0} {1}: {2}{3}", 1304 "[SynchronousRestObjectRequester]: Invalid XML from {0} {1} {2}",
1110 verb, requestUrl, e.Message, e.StackTrace); 1305 verb, requestUrl, typeof(TResponse).ToString());
1111
1112 return deserial;
1113 } 1306 }
1114 finally 1307 catch (Exception e)
1115 { 1308 {
1116 if (requestStream != null) 1309 m_log.Debug(string.Format(
1117 requestStream.Close(); 1310 "[SynchronousRestObjectRequester]: Exception on response from {0} {1} ",
1118 1311 verb, requestUrl), e);
1119 // capture how much time was spent writing
1120 tickdata = Util.EnvironmentTickCountSubtract(tickstart);
1121 } 1312 }
1122 }
1123 1313
1124 try 1314 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
1125 { 1315 if (tickdiff > WebUtil.LongCallTime)
1126 using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
1127 { 1316 {
1128 if (resp.ContentLength != 0) 1317 string originalRequest = null;
1129 { 1318
1130 Stream respStream = resp.GetResponseStream(); 1319 if (buffer != null)
1131 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
1132 deserial = (TResponse)deserializer.Deserialize(respStream);
1133 respStream.Close();
1134 }
1135 else
1136 { 1320 {
1137 m_log.DebugFormat( 1321 originalRequest = Encoding.UTF8.GetString(buffer.ToArray());
1138 "[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}", 1322
1139 verb, requestUrl); 1323 if (originalRequest.Length > WebUtil.MaxRequestDiagLength)
1324 originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength);
1140 } 1325 }
1141 }
1142 }
1143 catch (WebException e)
1144 {
1145 HttpWebResponse hwr = (HttpWebResponse)e.Response;
1146 1326
1147 if (hwr != null && hwr.StatusCode == HttpStatusCode.NotFound) 1327 m_log.InfoFormat(
1148 return deserial; 1328 "[LOGHTTP]: Slow SynchronousRestObject request {0} {1} to {2} took {3}ms, {4}ms writing, {5}",
1149 else 1329 reqnum, verb, requestUrl, tickdiff, tickdata,
1150 m_log.ErrorFormat( 1330 originalRequest);
1151 "[SynchronousRestObjectRequester]: WebException for {0} {1} {2}: {3} {4}", 1331 }
1152 verb, requestUrl, typeof(TResponse).ToString(), e.Message, e.StackTrace); 1332 else if (WebUtil.DebugLevel >= 4)
1333 {
1334 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing",
1335 reqnum, tickdiff, tickdata);
1336 }
1153 } 1337 }
1154 catch (System.InvalidOperationException) 1338 finally
1155 { 1339 {
1156 // This is what happens when there is invalid XML 1340 if (buffer != null)
1157 m_log.DebugFormat( 1341 buffer.Dispose();
1158 "[SynchronousRestObjectRequester]: Invalid XML from {0} {1} {2}",
1159 verb, requestUrl, typeof(TResponse).ToString());
1160 } 1342 }
1161 catch (Exception e) 1343
1344 return deserial;
1345 }
1346
1347
1348 public static class XMLResponseHelper
1349 {
1350 public static TResponse LogAndDeserialize<TRequest, TResponse>(int reqnum, Stream respStream, long contentLength)
1162 { 1351 {
1163 m_log.DebugFormat( 1352 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
1164 "[SynchronousRestObjectRequester]: Exception on response from {0} {1}: {2}{3}", 1353
1165 verb, requestUrl, e.Message, e.StackTrace); 1354 if (WebUtil.DebugLevel >= 5)
1355 {
1356 byte[] data = new byte[contentLength];
1357 Util.ReadStream(respStream, data);
1358
1359 WebUtil.LogResponseDetail(reqnum, System.Text.Encoding.UTF8.GetString(data));
1360
1361 using (MemoryStream temp = new MemoryStream(data))
1362 return (TResponse)deserializer.Deserialize(temp);
1363 }
1364 else
1365 {
1366 return (TResponse)deserializer.Deserialize(respStream);
1367 }
1166 } 1368 }
1369 }
1370 }
1167 1371
1168 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 1372
1169 if (tickdiff > WebUtil.LongCallTime) 1373 public static class XMLRPCRequester
1374 {
1375 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1376
1377 public static Hashtable SendRequest(Hashtable ReqParams, string method, string url)
1378 {
1379 int reqnum = WebUtil.RequestNumber++;
1380
1381 if (WebUtil.DebugLevel >= 3)
1382 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} XML-RPC '{1}' to {2}",
1383 reqnum, method, url);
1384
1385 int tickstart = Util.EnvironmentTickCount();
1386 string responseStr = null;
1387
1388 try
1170 { 1389 {
1171 string originalRequest = null; 1390 ArrayList SendParams = new ArrayList();
1391 SendParams.Add(ReqParams);
1172 1392
1173 if (buffer != null) 1393 XmlRpcRequest Req = new XmlRpcRequest(method, SendParams);
1394
1395 if (WebUtil.DebugLevel >= 5)
1396 {
1397 string str = Req.ToString();
1398 str = XElement.Parse(str).ToString(SaveOptions.DisableFormatting);
1399 WebUtil.LogOutgoingDetail("SEND", reqnum, str);
1400 }
1401
1402 XmlRpcResponse Resp = Req.Send(url, 30000);
1403
1404 try
1174 { 1405 {
1175 originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); 1406 responseStr = Resp.ToString();
1407 responseStr = XElement.Parse(responseStr).ToString(SaveOptions.DisableFormatting);
1176 1408
1177 if (originalRequest.Length > WebUtil.MaxRequestDiagLength) 1409 if (WebUtil.DebugLevel >= 5)
1178 originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); 1410 WebUtil.LogResponseDetail(reqnum, responseStr);
1411 }
1412 catch (Exception e)
1413 {
1414 m_log.Error("Error parsing XML-RPC response", e);
1415 }
1416
1417 if (Resp.IsFault)
1418 {
1419 m_log.DebugFormat(
1420 "[LOGHTTP]: XML-RPC request {0} '{1}' to {2} FAILED: FaultCode={3}, FaultMessage={4}",
1421 reqnum, method, url, Resp.FaultCode, Resp.FaultString);
1422 return null;
1179 } 1423 }
1180 1424
1181 m_log.InfoFormat( 1425 Hashtable RespData = (Hashtable)Resp.Value;
1182 "[SynchronousRestObjectRequester]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", 1426 return RespData;
1183 reqnum,
1184 verb,
1185 requestUrl,
1186 tickdiff,
1187 tickdata,
1188 originalRequest);
1189 } 1427 }
1190 else if (WebUtil.DebugLevel >= 4) 1428 finally
1191 { 1429 {
1192 m_log.DebugFormat( 1430 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
1193 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", 1431 if (tickdiff > WebUtil.LongCallTime)
1194 reqnum, tickdiff, tickdata); 1432 {
1433 m_log.InfoFormat(
1434 "[LOGHTTP]: Slow XML-RPC request {0} '{1}' to {2} took {3}ms, {4}",
1435 reqnum, method, url, tickdiff,
1436 responseStr != null
1437 ? (responseStr.Length > WebUtil.MaxRequestDiagLength ? responseStr.Remove(WebUtil.MaxRequestDiagLength) : responseStr)
1438 : "");
1439 }
1440 else if (WebUtil.DebugLevel >= 4)
1441 {
1442 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms", reqnum, tickdiff);
1443 }
1195 } 1444 }
1196
1197 return deserial;
1198 } 1445 }
1446
1199 } 1447 }
1200} 1448}