aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Scripting/HttpRequest
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Scripting/HttpRequest')
-rw-r--r--OpenSim/Region/Environment/Modules/Scripting/HttpRequest/ScriptsHttpRequests.cs356
1 files changed, 356 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/Environment/Modules/Scripting/HttpRequest/ScriptsHttpRequests.cs
new file mode 100644
index 0000000..4977a86
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -0,0 +1,356 @@
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 OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Text;
33using System.Threading;
34using libsecondlife;
35using Nini.Config;
36using OpenSim.Framework;
37using OpenSim.Region.Environment.Interfaces;
38using OpenSim.Region.Environment.Scenes;
39
40/*****************************************************
41 *
42 * ScriptsHttpRequests
43 *
44 * Implements the llHttpRequest and http_response
45 * callback.
46 *
47 * Some stuff was already in LSLLongCmdHandler, and then
48 * there was this file with a stub class in it. So,
49 * I am moving some of the objects and functions out of
50 * LSLLongCmdHandler, such as the HttpRequestClass, the
51 * start and stop methods, and setting up pending and
52 * completed queues. These are processed in the
53 * LSLLongCmdHandler polling loop. Similiar to the
54 * XMLRPCModule, since that seems to work.
55 *
56 * //TODO
57 *
58 * This probably needs some throttling mechanism but
59 * its wide open right now. This applies to both
60 * number of requests and data volume.
61 *
62 * Linden puts all kinds of header fields in the requests.
63 * Not doing any of that:
64 * User-Agent
65 * X-SecondLife-Shard
66 * X-SecondLife-Object-Name
67 * X-SecondLife-Object-Key
68 * X-SecondLife-Region
69 * X-SecondLife-Local-Position
70 * X-SecondLife-Local-Velocity
71 * X-SecondLife-Local-Rotation
72 * X-SecondLife-Owner-Name
73 * X-SecondLife-Owner-Key
74 *
75 * HTTPS support
76 *
77 * Configurable timeout?
78 * Configurable max repsonse size?
79 * Configurable
80 *
81 * **************************************************/
82
83namespace OpenSim.Region.Environment.Modules.Scripting.HttpRequest
84{
85 public class HttpRequestModule : IRegionModule, IHttpRequests
86 {
87 private Scene m_scene;
88 private Queue<HttpRequestClass> rpcQueue = new Queue<HttpRequestClass>();
89 private object HttpListLock = new object();
90 private string m_name = "HttpScriptRequests";
91 private int httpTimeout = 30000;
92
93 // <request id, HttpRequestClass>
94 private Dictionary<LLUUID, HttpRequestClass> m_pendingRequests;
95
96 public HttpRequestModule()
97 {
98 }
99
100 public void Initialise(Scene scene, IConfigSource config)
101 {
102 m_scene = scene;
103
104 m_scene.RegisterModuleInterface<IHttpRequests>(this);
105
106 m_pendingRequests = new Dictionary<LLUUID, HttpRequestClass>();
107 }
108
109 public void PostInitialise()
110 {
111 }
112
113 public void Close()
114 {
115 }
116
117 public string Name
118 {
119 get { return m_name; }
120 }
121
122 public bool IsSharedModule
123 {
124 get { return true; }
125 }
126
127 public LLUUID MakeHttpRequest(string url, string parameters, string body)
128 {
129 return LLUUID.Zero;
130 }
131
132 public LLUUID StartHttpRequest(uint localID, LLUUID itemID, string url, List<string> parameters, string body)
133 {
134 LLUUID reqID = LLUUID.Random();
135 HttpRequestClass htc = new HttpRequestClass();
136
137 // Partial implementation: support for parameter flags needed
138 // see http://wiki.secondlife.com/wiki/LlHTTPRequest
139 //
140 // Parameters are expected in {key, value, ... , key, value}
141 if (parameters != null)
142 {
143 string[] parms = parameters.ToArray();
144 for (int i = 0; i < parms.Length/2; i += 2)
145 {
146 switch (Int32.Parse(parms[i]))
147 {
148 case HttpRequestClass.HTTP_METHOD:
149
150 htc.httpMethod = parms[i + 1];
151 break;
152
153 case HttpRequestClass.HTTP_MIMETYPE:
154
155 htc.httpMIMEType = parms[i + 1];
156 break;
157
158 case HttpRequestClass.HTTP_BODY_MAXLENGTH:
159
160 // TODO implement me
161 break;
162
163 case HttpRequestClass.HTTP_VERIFY_CERT:
164
165 // TODO implement me
166 break;
167 }
168 }
169 }
170
171 htc.localID = localID;
172 htc.itemID = itemID;
173 htc.url = url;
174 htc.reqID = reqID;
175 htc.httpTimeout = httpTimeout;
176 htc.outbound_body = body;
177
178 lock (HttpListLock)
179 {
180 m_pendingRequests.Add(reqID, htc);
181 }
182
183 htc.process();
184
185 return reqID;
186 }
187
188 public void StopHttpRequest(uint m_localID, LLUUID m_itemID)
189 {
190 if(m_pendingRequests != null) {
191 lock (HttpListLock)
192 {
193 HttpRequestClass tmpReq;
194 if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq))
195 {
196 tmpReq.Stop();
197 m_pendingRequests.Remove(m_itemID);
198 }
199 }
200 }
201 }
202
203 /*
204 * TODO
205 * Not sure how important ordering is is here - the next first
206 * one completed in the list is returned, based soley on its list
207 * position, not the order in which the request was started or
208 * finsihed. I thought about setting up a queue for this, but
209 * it will need some refactoring and this works 'enough' right now
210 */
211
212 public HttpRequestClass GetNextCompletedRequest()
213 {
214 lock (HttpListLock)
215 {
216 foreach (LLUUID luid in m_pendingRequests.Keys)
217 {
218 HttpRequestClass tmpReq;
219
220 if (m_pendingRequests.TryGetValue(luid, out tmpReq))
221 {
222 if (tmpReq.finished)
223 {
224 return tmpReq;
225 }
226 }
227 }
228 }
229 return null;
230 }
231
232 public void RemoveCompletedRequest(LLUUID id)
233 {
234 lock (HttpListLock)
235 {
236 HttpRequestClass tmpReq;
237 if (m_pendingRequests.TryGetValue(id, out tmpReq))
238 {
239 tmpReq.Stop();
240 tmpReq = null;
241 m_pendingRequests.Remove(id);
242 }
243 }
244 }
245
246 }
247
248 public class HttpRequestClass
249 {
250 // Constants for parameters
251 public const int HTTP_METHOD = 0;
252 public const int HTTP_MIMETYPE = 1;
253 public const int HTTP_BODY_MAXLENGTH = 2;
254 public const int HTTP_VERIFY_CERT = 3;
255
256 // Parameter members and default values
257 public string httpMethod = "GET";
258 public string httpMIMEType = "text/plain;charset=utf-8";
259 public int httpBodyMaxLen = 2048; // not implemented
260 public bool httpVerifyCert = true; // not implemented
261
262 // Request info
263 public uint localID;
264 public LLUUID itemID;
265 public LLUUID reqID;
266 public int httpTimeout;
267 public string url;
268 public string outbound_body;
269 public DateTime next;
270 public int status;
271 public bool finished;
272 public List<string> response_metadata;
273 public string response_body;
274 public HttpWebRequest request;
275 private Thread httpThread;
276
277 public void process()
278 {
279 httpThread = new Thread(SendRequest);
280 httpThread.Name = "HttpRequestThread";
281 httpThread.Priority = ThreadPriority.BelowNormal;
282 httpThread.IsBackground = true;
283 finished = false;
284 httpThread.Start();
285 ThreadTracker.Add(httpThread);
286 }
287
288 /*
289 * TODO: More work on the response codes. Right now
290 * returning 200 for success or 499 for exception
291 */
292
293 public void SendRequest()
294 {
295 HttpWebResponse response = null;
296 StringBuilder sb = new StringBuilder();
297 byte[] buf = new byte[8192];
298 string tempString = null;
299 int count = 0;
300
301 try
302 {
303 request = (HttpWebRequest)
304 WebRequest.Create(url);
305 request.Method = httpMethod;
306 request.ContentType = httpMIMEType;
307
308 request.Timeout = httpTimeout;
309 // execute the request
310 response = (HttpWebResponse)
311 request.GetResponse();
312
313 Stream resStream = response.GetResponseStream();
314
315 do
316 {
317 // fill the buffer with data
318 count = resStream.Read(buf, 0, buf.Length);
319
320 // make sure we read some data
321 if (count != 0)
322 {
323 // translate from bytes to ASCII text
324 tempString = Encoding.UTF8.GetString(buf, 0, count);
325
326 // continue building the string
327 sb.Append(tempString);
328 }
329 } while (count > 0); // any more data to read?
330
331 response_body = sb.ToString();
332 }
333 catch (Exception e)
334 {
335 status = 499;
336 response_body = e.Message;
337 finished = true;
338 return;
339 }
340
341 status = 200;
342 finished = true;
343 }
344
345 public void Stop()
346 {
347 try
348 {
349 httpThread.Abort();
350 }
351 catch (Exception)
352 {
353 }
354 }
355 }
356} \ No newline at end of file