diff options
author | Justin Clark-Casey (justincc) | 2013-07-11 23:02:30 +0100 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2013-07-11 23:02:30 +0100 |
commit | 44e9849ed1190dbc29ffa97fa5df286dc9794edb (patch) | |
tree | 427e9033c87ffa2bbedb176acb342c1677d153e0 | |
parent | Merge branch 'master' of ssh://opensimulator.org/var/git/opensim (diff) | |
download | opensim-SC_OLD-44e9849ed1190dbc29ffa97fa5df286dc9794edb.zip opensim-SC_OLD-44e9849ed1190dbc29ffa97fa5df286dc9794edb.tar.gz opensim-SC_OLD-44e9849ed1190dbc29ffa97fa5df286dc9794edb.tar.bz2 opensim-SC_OLD-44e9849ed1190dbc29ffa97fa5df286dc9794edb.tar.xz |
Fix regression where llHTTPRequests which did not get an OK response returned 499 and the exception message in the http_response event rather than the actual response code and body.
This was a regression since commit 831e4c3 (Thu Apr 4 00:36:15 2013)
This commit also adds a regression test for this case, though this currently only works with Mono
This aims to address http://opensimulator.org/mantis/view.php?id=6704
-rw-r--r-- | OpenSim/Framework/Util.cs | 7 | ||||
-rw-r--r-- | OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | 77 | ||||
-rw-r--r-- | OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs | 201 | ||||
-rw-r--r-- | prebuild.xml | 1 |
4 files changed, 245 insertions, 41 deletions
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ba6cc75..cafe103 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs | |||
@@ -141,6 +141,11 @@ namespace OpenSim.Framework | |||
141 | public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; | 141 | public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; |
142 | public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; | 142 | public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; |
143 | 143 | ||
144 | public static bool IsPlatformMono | ||
145 | { | ||
146 | get { return Type.GetType("Mono.Runtime") != null; } | ||
147 | } | ||
148 | |||
144 | /// <summary> | 149 | /// <summary> |
145 | /// Gets the name of the directory where the current running executable | 150 | /// Gets the name of the directory where the current running executable |
146 | /// is located | 151 | /// is located |
@@ -1326,7 +1331,7 @@ namespace OpenSim.Framework | |||
1326 | ru = "OSX/Mono"; | 1331 | ru = "OSX/Mono"; |
1327 | else | 1332 | else |
1328 | { | 1333 | { |
1329 | if (Type.GetType("Mono.Runtime") != null) | 1334 | if (IsPlatformMono) |
1330 | ru = "Win/Mono"; | 1335 | ru = "Win/Mono"; |
1331 | else | 1336 | else |
1332 | ru = "Win/.NET"; | 1337 | ru = "Win/.NET"; |
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index 6793fc8..1a62405 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | |||
@@ -419,7 +419,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
419 | get { return _reqID; } | 419 | get { return _reqID; } |
420 | set { _reqID = value; } | 420 | set { _reqID = value; } |
421 | } | 421 | } |
422 | public HttpWebRequest Request; | 422 | public WebRequest Request; |
423 | public string ResponseBody; | 423 | public string ResponseBody; |
424 | public List<string> ResponseMetadata; | 424 | public List<string> ResponseMetadata; |
425 | public Dictionary<string, string> ResponseHeaders; | 425 | public Dictionary<string, string> ResponseHeaders; |
@@ -431,18 +431,11 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
431 | SendRequest(); | 431 | SendRequest(); |
432 | } | 432 | } |
433 | 433 | ||
434 | /* | ||
435 | * TODO: More work on the response codes. Right now | ||
436 | * returning 200 for success or 499 for exception | ||
437 | */ | ||
438 | |||
439 | public void SendRequest() | 434 | public void SendRequest() |
440 | { | 435 | { |
441 | HttpWebResponse response = null; | ||
442 | |||
443 | try | 436 | try |
444 | { | 437 | { |
445 | Request = (HttpWebRequest) WebRequest.Create(Url); | 438 | Request = WebRequest.Create(Url); |
446 | Request.Method = HttpMethod; | 439 | Request.Method = HttpMethod; |
447 | Request.ContentType = HttpMIMEType; | 440 | Request.ContentType = HttpMIMEType; |
448 | 441 | ||
@@ -480,14 +473,17 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
480 | } | 473 | } |
481 | } | 474 | } |
482 | 475 | ||
483 | foreach (KeyValuePair<string, string> entry in ResponseHeaders) | 476 | if (ResponseHeaders != null) |
484 | if (entry.Key.ToLower().Equals("user-agent")) | 477 | { |
485 | Request.UserAgent = entry.Value; | 478 | foreach (KeyValuePair<string, string> entry in ResponseHeaders) |
486 | else | 479 | if (entry.Key.ToLower().Equals("user-agent") && Request is HttpWebRequest) |
487 | Request.Headers[entry.Key] = entry.Value; | 480 | ((HttpWebRequest)Request).UserAgent = entry.Value; |
481 | else | ||
482 | Request.Headers[entry.Key] = entry.Value; | ||
483 | } | ||
488 | 484 | ||
489 | // Encode outbound data | 485 | // Encode outbound data |
490 | if (OutboundBody.Length > 0) | 486 | if (OutboundBody != null && OutboundBody.Length > 0) |
491 | { | 487 | { |
492 | byte[] data = Util.UTF8.GetBytes(OutboundBody); | 488 | byte[] data = Util.UTF8.GetBytes(OutboundBody); |
493 | 489 | ||
@@ -510,12 +506,19 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
510 | { | 506 | { |
511 | throw; | 507 | throw; |
512 | } | 508 | } |
513 | response = (HttpWebResponse)e.Response; | 509 | |
510 | HttpWebResponse response = (HttpWebResponse)e.Response; | ||
511 | |||
512 | Status = (int)response.StatusCode; | ||
513 | ResponseBody = response.StatusDescription; | ||
514 | _finished = true; | 514 | _finished = true; |
515 | } | 515 | } |
516 | } | 516 | } |
517 | catch (Exception e) | 517 | catch (Exception e) |
518 | { | 518 | { |
519 | // m_log.Debug( | ||
520 | // string.Format("[SCRIPTS HTTP REQUESTS]: Exception on request to {0} for {1} ", Url, ItemID), e); | ||
521 | |||
519 | Status = (int)OSHttpStatusCode.ClientErrorJoker; | 522 | Status = (int)OSHttpStatusCode.ClientErrorJoker; |
520 | ResponseBody = e.Message; | 523 | ResponseBody = e.Message; |
521 | _finished = true; | 524 | _finished = true; |
@@ -528,33 +531,27 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
528 | 531 | ||
529 | try | 532 | try |
530 | { | 533 | { |
531 | response = (HttpWebResponse)Request.EndGetResponse(ar); | 534 | try |
532 | Status = (int)response.StatusCode; | ||
533 | |||
534 | Stream resStream = response.GetResponseStream(); | ||
535 | StringBuilder sb = new StringBuilder(); | ||
536 | byte[] buf = new byte[8192]; | ||
537 | string tempString = null; | ||
538 | int count = 0; | ||
539 | |||
540 | do | ||
541 | { | 535 | { |
542 | // fill the buffer with data | 536 | response = (HttpWebResponse)Request.EndGetResponse(ar); |
543 | count = resStream.Read(buf, 0, buf.Length); | 537 | } |
544 | 538 | catch (WebException e) | |
545 | // make sure we read some data | 539 | { |
546 | if (count != 0) | 540 | if (e.Status != WebExceptionStatus.ProtocolError) |
547 | { | 541 | { |
548 | // translate from bytes to ASCII text | 542 | throw; |
549 | tempString = Util.UTF8.GetString(buf, 0, count); | ||
550 | |||
551 | // continue building the string | ||
552 | sb.Append(tempString); | ||
553 | } | 543 | } |
554 | } | ||
555 | while (count > 0); // any more data to read? | ||
556 | 544 | ||
557 | ResponseBody = sb.ToString(); | 545 | response = (HttpWebResponse)e.Response; |
546 | } | ||
547 | |||
548 | Status = (int)response.StatusCode; | ||
549 | |||
550 | using (Stream stream = response.GetResponseStream()) | ||
551 | { | ||
552 | StreamReader reader = new StreamReader(stream, Encoding.UTF8); | ||
553 | ResponseBody = reader.ReadToEnd(); | ||
554 | } | ||
558 | } | 555 | } |
559 | catch (Exception e) | 556 | catch (Exception e) |
560 | { | 557 | { |
@@ -587,4 +584,4 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
587 | Request.Abort(); | 584 | Request.Abort(); |
588 | } | 585 | } |
589 | } | 586 | } |
590 | } | 587 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs new file mode 100644 index 0000000..f638f91 --- /dev/null +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs | |||
@@ -0,0 +1,201 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Runtime.Serialization; | ||
34 | using System.Text; | ||
35 | using System.Threading; | ||
36 | using log4net.Config; | ||
37 | using NUnit.Framework; | ||
38 | using OpenMetaverse; | ||
39 | using OpenMetaverse.Assets; | ||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Region.CoreModules.Scripting.HttpRequest; | ||
42 | using OpenSim.Region.Framework.Scenes; | ||
43 | using OpenSim.Tests.Common; | ||
44 | using OpenSim.Tests.Common.Mock; | ||
45 | |||
46 | namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests | ||
47 | { | ||
48 | class TestWebRequestCreate : IWebRequestCreate | ||
49 | { | ||
50 | public TestWebRequest NextRequest { get; set; } | ||
51 | |||
52 | public WebRequest Create(Uri uri) | ||
53 | { | ||
54 | // NextRequest.RequestUri = uri; | ||
55 | |||
56 | return NextRequest; | ||
57 | |||
58 | // return new TestWebRequest(new SerializationInfo(typeof(TestWebRequest), new FormatterConverter()), new StreamingContext()); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | class TestWebRequest : WebRequest | ||
63 | { | ||
64 | public override string ContentType { get; set; } | ||
65 | public override string Method { get; set; } | ||
66 | |||
67 | public Func<IAsyncResult, WebResponse> OnEndGetResponse { get; set; } | ||
68 | |||
69 | public TestWebRequest() : base() | ||
70 | { | ||
71 | // Console.WriteLine("created"); | ||
72 | } | ||
73 | |||
74 | // public TestWebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext) | ||
75 | // : base(serializationInfo, streamingContext) | ||
76 | // { | ||
77 | // Console.WriteLine("created"); | ||
78 | // } | ||
79 | |||
80 | public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state) | ||
81 | { | ||
82 | // Console.WriteLine("bish"); | ||
83 | TestAsyncResult tasr = new TestAsyncResult(); | ||
84 | callback(tasr); | ||
85 | |||
86 | return tasr; | ||
87 | } | ||
88 | |||
89 | public override WebResponse EndGetResponse(IAsyncResult asyncResult) | ||
90 | { | ||
91 | // Console.WriteLine("bosh"); | ||
92 | return OnEndGetResponse(asyncResult); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | class TestHttpWebResponse : HttpWebResponse | ||
97 | { | ||
98 | public string Response { get; set; } | ||
99 | |||
100 | public TestHttpWebResponse(SerializationInfo serializationInfo, StreamingContext streamingContext) | ||
101 | : base(serializationInfo, streamingContext) {} | ||
102 | |||
103 | public override Stream GetResponseStream() | ||
104 | { | ||
105 | return new MemoryStream(Encoding.UTF8.GetBytes(Response)); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | class TestAsyncResult : IAsyncResult | ||
110 | { | ||
111 | WaitHandle m_wh = new ManualResetEvent(true); | ||
112 | |||
113 | object IAsyncResult.AsyncState | ||
114 | { | ||
115 | get { | ||
116 | throw new System.NotImplementedException (); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | WaitHandle IAsyncResult.AsyncWaitHandle | ||
121 | { | ||
122 | get { return m_wh; } | ||
123 | } | ||
124 | |||
125 | bool IAsyncResult.CompletedSynchronously | ||
126 | { | ||
127 | get { return false; } | ||
128 | } | ||
129 | |||
130 | bool IAsyncResult.IsCompleted | ||
131 | { | ||
132 | get { return true; } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | /// <summary> | ||
137 | /// Test script http request code. | ||
138 | /// </summary> | ||
139 | /// <remarks> | ||
140 | /// This class uses some very hacky workarounds in order to mock HttpWebResponse which are Mono dependent (though | ||
141 | /// alternative code can be written to make this work for Windows). However, the value of being able to | ||
142 | /// regression test this kind of code is very high. | ||
143 | /// </remarks> | ||
144 | [TestFixture] | ||
145 | public class ScriptsHttpRequestsTests : OpenSimTestCase | ||
146 | { | ||
147 | /// <summary> | ||
148 | /// Test what happens when we get a 404 response from a call. | ||
149 | /// </summary> | ||
150 | [Test] | ||
151 | public void Test404Response() | ||
152 | { | ||
153 | TestHelpers.InMethod(); | ||
154 | TestHelpers.EnableLogging(); | ||
155 | |||
156 | if (!Util.IsPlatformMono) | ||
157 | Assert.Ignore("Ignoring test since can only currently run on Mono"); | ||
158 | |||
159 | string rawResponse = "boom"; | ||
160 | |||
161 | TestWebRequestCreate twrc = new TestWebRequestCreate(); | ||
162 | |||
163 | TestWebRequest twr = new TestWebRequest(); | ||
164 | //twr.OnEndGetResponse += ar => new TestHttpWebResponse(null, new StreamingContext()); | ||
165 | twr.OnEndGetResponse += ar => | ||
166 | { | ||
167 | SerializationInfo si = new SerializationInfo(typeof(HttpWebResponse), new FormatterConverter()); | ||
168 | StreamingContext sc = new StreamingContext(); | ||
169 | // WebHeaderCollection headers = new WebHeaderCollection(); | ||
170 | // si.AddValue("m_HttpResponseHeaders", headers); | ||
171 | si.AddValue("uri", new Uri("test://arrg")); | ||
172 | // si.AddValue("m_Certificate", null); | ||
173 | si.AddValue("version", HttpVersion.Version11); | ||
174 | si.AddValue("statusCode", HttpStatusCode.NotFound); | ||
175 | si.AddValue("contentLength", 0); | ||
176 | si.AddValue("method", "GET"); | ||
177 | si.AddValue("statusDescription", "Not Found"); | ||
178 | si.AddValue("contentType", null); | ||
179 | si.AddValue("cookieCollection", new CookieCollection()); | ||
180 | |||
181 | TestHttpWebResponse thwr = new TestHttpWebResponse(si, sc); | ||
182 | thwr.Response = rawResponse; | ||
183 | |||
184 | throw new WebException("no message", null, WebExceptionStatus.ProtocolError, thwr); | ||
185 | }; | ||
186 | |||
187 | twrc.NextRequest = twr; | ||
188 | |||
189 | WebRequest.RegisterPrefix("test", twrc); | ||
190 | HttpRequestClass hr = new HttpRequestClass(); | ||
191 | hr.Url = "test://something"; | ||
192 | hr.SendRequest(); | ||
193 | |||
194 | while (!hr.Finished) | ||
195 | Thread.Sleep(100); | ||
196 | |||
197 | Assert.That(hr.Status, Is.EqualTo((int)HttpStatusCode.NotFound)); | ||
198 | Assert.That(hr.ResponseBody, Is.EqualTo(rawResponse)); | ||
199 | } | ||
200 | } | ||
201 | } \ No newline at end of file | ||
diff --git a/prebuild.xml b/prebuild.xml index d9e32ea..d32287a 100644 --- a/prebuild.xml +++ b/prebuild.xml | |||
@@ -3102,6 +3102,7 @@ | |||
3102 | <Match path="Avatar/Inventory/Transfer/Tests" pattern="*.cs" recurse="true"/> | 3102 | <Match path="Avatar/Inventory/Transfer/Tests" pattern="*.cs" recurse="true"/> |
3103 | <Match path="Framework/InventoryAccess/Tests" pattern="*.cs" recurse="true"/> | 3103 | <Match path="Framework/InventoryAccess/Tests" pattern="*.cs" recurse="true"/> |
3104 | <Match path="Framework/UserManagement/Tests" pattern="*.cs" recurse="true"/> | 3104 | <Match path="Framework/UserManagement/Tests" pattern="*.cs" recurse="true"/> |
3105 | <Match path="Scripting/HttpRequest/Tests" pattern="*.cs" recurse="true"/> | ||
3105 | <Match path="Scripting/VectorRender/Tests" pattern="*.cs" recurse="true"/> | 3106 | <Match path="Scripting/VectorRender/Tests" pattern="*.cs" recurse="true"/> |
3106 | <Match path="World/Archiver/Tests" pattern="*.cs" recurse="true"/> | 3107 | <Match path="World/Archiver/Tests" pattern="*.cs" recurse="true"/> |
3107 | <Match buildAction="EmbeddedResource" path="World/Archiver/Tests/Resources" pattern="*"/> | 3108 | <Match buildAction="EmbeddedResource" path="World/Archiver/Tests/Resources" pattern="*"/> |