diff options
47 files changed, 6849 insertions, 0 deletions
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs new file mode 100644 index 0000000..7ab5c33 --- /dev/null +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs | |||
@@ -0,0 +1,510 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using System.Threading; | ||
34 | using System.Timers; | ||
35 | using log4net; | ||
36 | using log4net.Appender; | ||
37 | using log4net.Core; | ||
38 | using log4net.Repository; | ||
39 | using OpenSim.Framework.Console; | ||
40 | using OpenSim.Framework.Servers; | ||
41 | using OpenSim.Framework.Servers.HttpServer; | ||
42 | using OpenSim.Framework.Statistics; | ||
43 | using Timer=System.Timers.Timer; | ||
44 | |||
45 | using OpenMetaverse; | ||
46 | using OpenMetaverse.StructuredData; | ||
47 | |||
48 | |||
49 | namespace OpenSim.Framework.Servers | ||
50 | { | ||
51 | /// <summary> | ||
52 | /// Common base for the main OpenSimServers (user, grid, inventory, region, etc) | ||
53 | /// </summary> | ||
54 | public abstract class BaseOpenSimServer | ||
55 | { | ||
56 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
57 | |||
58 | /// <summary> | ||
59 | /// This will control a periodic log printout of the current 'show stats' (if they are active) for this | ||
60 | /// server. | ||
61 | /// </summary> | ||
62 | private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); | ||
63 | |||
64 | protected CommandConsole m_console; | ||
65 | protected OpenSimAppender m_consoleAppender; | ||
66 | protected IAppender m_logFileAppender = null; | ||
67 | |||
68 | /// <summary> | ||
69 | /// Time at which this server was started | ||
70 | /// </summary> | ||
71 | protected DateTime m_startuptime; | ||
72 | |||
73 | /// <summary> | ||
74 | /// Record the initial startup directory for info purposes | ||
75 | /// </summary> | ||
76 | protected string m_startupDirectory = Environment.CurrentDirectory; | ||
77 | |||
78 | /// <summary> | ||
79 | /// Server version information. Usually VersionInfo + information about svn revision, operating system, etc. | ||
80 | /// </summary> | ||
81 | protected string m_version; | ||
82 | |||
83 | protected string m_pidFile = String.Empty; | ||
84 | |||
85 | /// <summary> | ||
86 | /// Random uuid for private data | ||
87 | /// </summary> | ||
88 | protected string m_osSecret = String.Empty; | ||
89 | |||
90 | protected BaseHttpServer m_httpServer; | ||
91 | public BaseHttpServer HttpServer | ||
92 | { | ||
93 | get { return m_httpServer; } | ||
94 | } | ||
95 | |||
96 | /// <summary> | ||
97 | /// Holds the non-viewer statistics collection object for this service/server | ||
98 | /// </summary> | ||
99 | protected IStatsCollector m_stats; | ||
100 | |||
101 | public BaseOpenSimServer() | ||
102 | { | ||
103 | m_startuptime = DateTime.Now; | ||
104 | m_version = VersionInfo.Version; | ||
105 | |||
106 | // Random uuid for private data | ||
107 | m_osSecret = UUID.Random().ToString(); | ||
108 | |||
109 | m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics); | ||
110 | m_periodicDiagnosticsTimer.Enabled = true; | ||
111 | |||
112 | // Add ourselves to thread monitoring. This thread will go on to become the console listening thread | ||
113 | Thread.CurrentThread.Name = "ConsoleThread"; | ||
114 | ThreadTracker.Add(Thread.CurrentThread); | ||
115 | |||
116 | ILoggerRepository repository = LogManager.GetRepository(); | ||
117 | IAppender[] appenders = repository.GetAppenders(); | ||
118 | |||
119 | foreach (IAppender appender in appenders) | ||
120 | { | ||
121 | if (appender.Name == "LogFileAppender") | ||
122 | { | ||
123 | m_logFileAppender = appender; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | } | ||
128 | |||
129 | /// <summary> | ||
130 | /// Must be overriden by child classes for their own server specific startup behaviour. | ||
131 | /// </summary> | ||
132 | protected virtual void StartupSpecific() | ||
133 | { | ||
134 | if (m_console != null) | ||
135 | { | ||
136 | ILoggerRepository repository = LogManager.GetRepository(); | ||
137 | IAppender[] appenders = repository.GetAppenders(); | ||
138 | |||
139 | foreach (IAppender appender in appenders) | ||
140 | { | ||
141 | if (appender.Name == "Console") | ||
142 | { | ||
143 | m_consoleAppender = (OpenSimAppender)appender; | ||
144 | break; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | if (null == m_consoleAppender) | ||
149 | { | ||
150 | Notice("No appender named Console found (see the log4net config file for this executable)!"); | ||
151 | } | ||
152 | else | ||
153 | { | ||
154 | m_consoleAppender.Console = m_console; | ||
155 | |||
156 | // If there is no threshold set then the threshold is effectively everything. | ||
157 | if (null == m_consoleAppender.Threshold) | ||
158 | m_consoleAppender.Threshold = Level.All; | ||
159 | |||
160 | Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold)); | ||
161 | } | ||
162 | |||
163 | m_console.Commands.AddCommand("base", false, "quit", | ||
164 | "quit", | ||
165 | "Quit the application", HandleQuit); | ||
166 | |||
167 | m_console.Commands.AddCommand("base", false, "shutdown", | ||
168 | "shutdown", | ||
169 | "Quit the application", HandleQuit); | ||
170 | |||
171 | m_console.Commands.AddCommand("base", false, "set log level", | ||
172 | "set log level <level>", | ||
173 | "Set the console logging level", HandleLogLevel); | ||
174 | |||
175 | m_console.Commands.AddCommand("base", false, "show info", | ||
176 | "show info", | ||
177 | "Show general information", HandleShow); | ||
178 | |||
179 | m_console.Commands.AddCommand("base", false, "show stats", | ||
180 | "show stats", | ||
181 | "Show statistics", HandleShow); | ||
182 | |||
183 | m_console.Commands.AddCommand("base", false, "show threads", | ||
184 | "show threads", | ||
185 | "Show thread status", HandleShow); | ||
186 | |||
187 | m_console.Commands.AddCommand("base", false, "show uptime", | ||
188 | "show uptime", | ||
189 | "Show server uptime", HandleShow); | ||
190 | |||
191 | m_console.Commands.AddCommand("base", false, "show version", | ||
192 | "show version", | ||
193 | "Show server version", HandleShow); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /// <summary> | ||
198 | /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing | ||
199 | /// </summary> | ||
200 | public virtual void ShutdownSpecific() {} | ||
201 | |||
202 | /// <summary> | ||
203 | /// Provides a list of help topics that are available. Overriding classes should append their topics to the | ||
204 | /// information returned when the base method is called. | ||
205 | /// </summary> | ||
206 | /// | ||
207 | /// <returns> | ||
208 | /// A list of strings that represent different help topics on which more information is available | ||
209 | /// </returns> | ||
210 | protected virtual List<string> GetHelpTopics() { return new List<string>(); } | ||
211 | |||
212 | /// <summary> | ||
213 | /// Print statistics to the logfile, if they are active | ||
214 | /// </summary> | ||
215 | protected void LogDiagnostics(object source, ElapsedEventArgs e) | ||
216 | { | ||
217 | StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n"); | ||
218 | sb.Append(GetUptimeReport()); | ||
219 | |||
220 | if (m_stats != null) | ||
221 | { | ||
222 | sb.Append(m_stats.Report()); | ||
223 | } | ||
224 | |||
225 | sb.Append(Environment.NewLine); | ||
226 | sb.Append(GetThreadsReport()); | ||
227 | |||
228 | m_log.Debug(sb); | ||
229 | } | ||
230 | |||
231 | /// <summary> | ||
232 | /// Get a report about the registered threads in this server. | ||
233 | /// </summary> | ||
234 | protected string GetThreadsReport() | ||
235 | { | ||
236 | StringBuilder sb = new StringBuilder(); | ||
237 | |||
238 | List<Thread> threads = ThreadTracker.GetThreads(); | ||
239 | if (threads == null) | ||
240 | { | ||
241 | sb.Append("Thread tracking is only enabled in DEBUG mode."); | ||
242 | } | ||
243 | else | ||
244 | { | ||
245 | sb.Append(threads.Count + " threads are being tracked:" + Environment.NewLine); | ||
246 | foreach (Thread t in threads) | ||
247 | { | ||
248 | if (t.IsAlive) | ||
249 | { | ||
250 | sb.Append( | ||
251 | "ID: " + t.ManagedThreadId + ", Name: " + t.Name + ", Alive: " + t.IsAlive | ||
252 | + ", Pri: " + t.Priority + ", State: " + t.ThreadState + Environment.NewLine); | ||
253 | } | ||
254 | else | ||
255 | { | ||
256 | try | ||
257 | { | ||
258 | sb.Append("ID: " + t.ManagedThreadId + ", Name: " + t.Name + ", DEAD" + Environment.NewLine); | ||
259 | } | ||
260 | catch | ||
261 | { | ||
262 | sb.Append("THREAD ERROR" + Environment.NewLine); | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | return sb.ToString(); | ||
269 | } | ||
270 | |||
271 | /// <summary> | ||
272 | /// Return a report about the uptime of this server | ||
273 | /// </summary> | ||
274 | /// <returns></returns> | ||
275 | protected string GetUptimeReport() | ||
276 | { | ||
277 | StringBuilder sb = new StringBuilder(String.Format("Time now is {0}\n", DateTime.Now)); | ||
278 | sb.Append(String.Format("Server has been running since {0}, {1}\n", m_startuptime.DayOfWeek, m_startuptime)); | ||
279 | sb.Append(String.Format("That is an elapsed time of {0}\n", DateTime.Now - m_startuptime)); | ||
280 | |||
281 | return sb.ToString(); | ||
282 | } | ||
283 | |||
284 | /// <summary> | ||
285 | /// Performs initialisation of the scene, such as loading configuration from disk. | ||
286 | /// </summary> | ||
287 | public virtual void Startup() | ||
288 | { | ||
289 | m_log.Info("[STARTUP]: Beginning startup processing"); | ||
290 | |||
291 | EnhanceVersionInformation(); | ||
292 | |||
293 | m_log.Info("[STARTUP]: Version: " + m_version + "\n"); | ||
294 | |||
295 | StartupSpecific(); | ||
296 | |||
297 | TimeSpan timeTaken = DateTime.Now - m_startuptime; | ||
298 | |||
299 | m_log.InfoFormat("[STARTUP]: Startup took {0}m {1}s", timeTaken.Minutes, timeTaken.Seconds); | ||
300 | } | ||
301 | |||
302 | /// <summary> | ||
303 | /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing | ||
304 | /// </summary> | ||
305 | public virtual void Shutdown() | ||
306 | { | ||
307 | ShutdownSpecific(); | ||
308 | |||
309 | m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); | ||
310 | RemovePIDFile(); | ||
311 | |||
312 | Environment.Exit(0); | ||
313 | } | ||
314 | |||
315 | private void HandleQuit(string module, string[] args) | ||
316 | { | ||
317 | Shutdown(); | ||
318 | } | ||
319 | |||
320 | private void HandleLogLevel(string module, string[] cmd) | ||
321 | { | ||
322 | if (null == m_consoleAppender) | ||
323 | { | ||
324 | Notice("No appender named Console found (see the log4net config file for this executable)!"); | ||
325 | return; | ||
326 | } | ||
327 | |||
328 | string rawLevel = cmd[3]; | ||
329 | |||
330 | ILoggerRepository repository = LogManager.GetRepository(); | ||
331 | Level consoleLevel = repository.LevelMap[rawLevel]; | ||
332 | |||
333 | if (consoleLevel != null) | ||
334 | m_consoleAppender.Threshold = consoleLevel; | ||
335 | else | ||
336 | Notice( | ||
337 | String.Format( | ||
338 | "{0} is not a valid logging level. Valid logging levels are ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF", | ||
339 | rawLevel)); | ||
340 | |||
341 | Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold)); | ||
342 | } | ||
343 | |||
344 | /// <summary> | ||
345 | /// Show help information | ||
346 | /// </summary> | ||
347 | /// <param name="helpArgs"></param> | ||
348 | protected virtual void ShowHelp(string[] helpArgs) | ||
349 | { | ||
350 | Notice(""); | ||
351 | |||
352 | if (helpArgs.Length == 0) | ||
353 | { | ||
354 | Notice("set log level [level] - change the console logging level only. For example, off or debug."); | ||
355 | Notice("show info - show server information (e.g. startup path)."); | ||
356 | |||
357 | if (m_stats != null) | ||
358 | Notice("show stats - show statistical information for this server"); | ||
359 | |||
360 | Notice("show threads - list tracked threads"); | ||
361 | Notice("show uptime - show server startup time and uptime."); | ||
362 | Notice("show version - show server version."); | ||
363 | Notice(""); | ||
364 | |||
365 | return; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | public virtual void HandleShow(string module, string[] cmd) | ||
370 | { | ||
371 | List<string> args = new List<string>(cmd); | ||
372 | |||
373 | args.RemoveAt(0); | ||
374 | |||
375 | string[] showParams = args.ToArray(); | ||
376 | |||
377 | switch (showParams[0]) | ||
378 | { | ||
379 | case "info": | ||
380 | Notice("Version: " + m_version); | ||
381 | Notice("Startup directory: " + m_startupDirectory); | ||
382 | break; | ||
383 | |||
384 | case "stats": | ||
385 | if (m_stats != null) | ||
386 | Notice(m_stats.Report()); | ||
387 | break; | ||
388 | |||
389 | case "threads": | ||
390 | Notice(GetThreadsReport()); | ||
391 | break; | ||
392 | |||
393 | case "uptime": | ||
394 | Notice(GetUptimeReport()); | ||
395 | break; | ||
396 | |||
397 | case "version": | ||
398 | Notice( | ||
399 | String.Format( | ||
400 | "Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion)); | ||
401 | break; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | /// <summary> | ||
406 | /// Console output is only possible if a console has been established. | ||
407 | /// That is something that cannot be determined within this class. So | ||
408 | /// all attempts to use the console MUST be verified. | ||
409 | /// </summary> | ||
410 | protected void Notice(string msg) | ||
411 | { | ||
412 | if (m_console != null) | ||
413 | { | ||
414 | m_console.Notice(msg); | ||
415 | } | ||
416 | } | ||
417 | |||
418 | /// <summary> | ||
419 | /// Enhance the version string with extra information if it's available. | ||
420 | /// </summary> | ||
421 | protected void EnhanceVersionInformation() | ||
422 | { | ||
423 | string buildVersion = string.Empty; | ||
424 | |||
425 | // Add subversion revision information if available | ||
426 | // Try file "svn_revision" in the current directory first, then the .svn info. | ||
427 | // This allows to make the revision available in simulators not running from the source tree. | ||
428 | // FIXME: Making an assumption about the directory we're currently in - we do this all over the place | ||
429 | // elsewhere as well | ||
430 | string svnRevisionFileName = "svn_revision"; | ||
431 | string svnFileName = ".svn/entries"; | ||
432 | string inputLine; | ||
433 | int strcmp; | ||
434 | |||
435 | if (File.Exists(svnRevisionFileName)) | ||
436 | { | ||
437 | StreamReader RevisionFile = File.OpenText(svnRevisionFileName); | ||
438 | buildVersion = RevisionFile.ReadLine(); | ||
439 | buildVersion.Trim(); | ||
440 | RevisionFile.Close(); | ||
441 | } | ||
442 | |||
443 | if (string.IsNullOrEmpty(buildVersion) && File.Exists(svnFileName)) | ||
444 | { | ||
445 | StreamReader EntriesFile = File.OpenText(svnFileName); | ||
446 | inputLine = EntriesFile.ReadLine(); | ||
447 | while (inputLine != null) | ||
448 | { | ||
449 | // using the dir svn revision at the top of entries file | ||
450 | strcmp = String.Compare(inputLine, "dir"); | ||
451 | if (strcmp == 0) | ||
452 | { | ||
453 | buildVersion = EntriesFile.ReadLine(); | ||
454 | break; | ||
455 | } | ||
456 | else | ||
457 | { | ||
458 | inputLine = EntriesFile.ReadLine(); | ||
459 | } | ||
460 | } | ||
461 | EntriesFile.Close(); | ||
462 | } | ||
463 | |||
464 | m_version += string.IsNullOrEmpty(buildVersion) ? " " : ("." + buildVersion + " ").Substring(0, 6); | ||
465 | } | ||
466 | |||
467 | protected void CreatePIDFile(string path) | ||
468 | { | ||
469 | try | ||
470 | { | ||
471 | string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); | ||
472 | FileStream fs = File.Create(path); | ||
473 | System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); | ||
474 | Byte[] buf = enc.GetBytes(pidstring); | ||
475 | fs.Write(buf, 0, buf.Length); | ||
476 | fs.Close(); | ||
477 | m_pidFile = path; | ||
478 | } | ||
479 | catch (Exception) | ||
480 | { | ||
481 | } | ||
482 | } | ||
483 | |||
484 | public string osSecret { | ||
485 | // Secret uuid for the simulator | ||
486 | get { return m_osSecret; } | ||
487 | |||
488 | } | ||
489 | |||
490 | public string StatReport(OSHttpRequest httpRequest) | ||
491 | { | ||
492 | return m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version ); | ||
493 | } | ||
494 | |||
495 | protected void RemovePIDFile() | ||
496 | { | ||
497 | if (m_pidFile != String.Empty) | ||
498 | { | ||
499 | try | ||
500 | { | ||
501 | File.Delete(m_pidFile); | ||
502 | m_pidFile = String.Empty; | ||
503 | } | ||
504 | catch (Exception) | ||
505 | { | ||
506 | } | ||
507 | } | ||
508 | } | ||
509 | } | ||
510 | } | ||
diff --git a/OpenSim/Framework/Servers/CachedGetAssetStreamHandler.cs b/OpenSim/Framework/Servers/CachedGetAssetStreamHandler.cs new file mode 100644 index 0000000..39041df --- /dev/null +++ b/OpenSim/Framework/Servers/CachedGetAssetStreamHandler.cs | |||
@@ -0,0 +1,218 @@ | |||
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.IO; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using System.Text.RegularExpressions; | ||
33 | using System.Xml; | ||
34 | using System.Xml.Serialization; | ||
35 | using log4net; | ||
36 | using OpenMetaverse; | ||
37 | using OpenSim.Data; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Servers; | ||
40 | using OpenSim.Framework.Servers.HttpServer; | ||
41 | using OpenSim.Framework.Statistics; | ||
42 | using System.Net; | ||
43 | |||
44 | namespace OpenSim.Framework.Servers | ||
45 | { | ||
46 | public class CachedGetAssetStreamHandler : BaseStreamHandler | ||
47 | { | ||
48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | // private OpenAsset_Main m_assetManager; | ||
51 | private IAssetCache m_assetProvider; | ||
52 | |||
53 | /// <summary> | ||
54 | /// Constructor. | ||
55 | /// </summary> | ||
56 | /// <param name="assetManager"></param> | ||
57 | /// <param name="assetProvider"></param> | ||
58 | public CachedGetAssetStreamHandler(IAssetCache assetProvider) | ||
59 | : base("GET", "/assets") | ||
60 | { | ||
61 | m_log.Info("[REST]: In Get Request"); | ||
62 | // m_assetManager = assetManager; | ||
63 | m_assetProvider = assetProvider; | ||
64 | } | ||
65 | |||
66 | public override byte[] Handle(string path, Stream request, | ||
67 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
68 | { | ||
69 | string param = GetParam(path); | ||
70 | byte[] result = new byte[] { }; | ||
71 | |||
72 | string[] p = param.Split(new char[] { '/', '?', '&' }, StringSplitOptions.RemoveEmptyEntries); | ||
73 | |||
74 | if (p.Length > 0) | ||
75 | { | ||
76 | UUID assetID = UUID.Zero; | ||
77 | |||
78 | if (!UUID.TryParse(p[0], out assetID)) | ||
79 | { | ||
80 | m_log.InfoFormat( | ||
81 | "[REST]: GET:/asset ignoring request with malformed UUID {0}", p[0]); | ||
82 | return result; | ||
83 | } | ||
84 | |||
85 | if (StatsManager.AssetStats != null) | ||
86 | StatsManager.AssetStats.AddRequest(); | ||
87 | |||
88 | AssetBase asset = m_assetProvider.GetAsset(assetID,true); // TODO IsTexture should be deduced from loaded asset. It is not used in this case. | ||
89 | |||
90 | if (asset != null) | ||
91 | { | ||
92 | // if (asset.ContainsReferences) | ||
93 | // { | ||
94 | // asset.Data = ProcessOutgoingAssetData(asset.Data); | ||
95 | // } | ||
96 | if (p.Length > 1 && p[1] == "data") | ||
97 | { | ||
98 | httpResponse.StatusCode = (int)HttpStatusCode.OK; | ||
99 | httpResponse.ContentType = SLAssetTypeToContentType(asset.Type); | ||
100 | result = asset.Data; | ||
101 | } | ||
102 | else | ||
103 | { | ||
104 | XmlSerializer xs = new XmlSerializer(typeof(AssetBase)); | ||
105 | MemoryStream ms = new MemoryStream(); | ||
106 | XmlTextWriter xw = new XmlTextWriter(ms, Encoding.UTF8); | ||
107 | xw.Formatting = Formatting.Indented; | ||
108 | xs.Serialize(xw, asset); | ||
109 | xw.Flush(); | ||
110 | |||
111 | ms.Seek(0, SeekOrigin.Begin); | ||
112 | //StreamReader sr = new StreamReader(ms); | ||
113 | |||
114 | result = ms.GetBuffer(); | ||
115 | |||
116 | Array.Resize<byte>(ref result, (int)ms.Length); | ||
117 | } | ||
118 | } | ||
119 | else | ||
120 | { | ||
121 | if (StatsManager.AssetStats != null) | ||
122 | StatsManager.AssetStats.AddNotFoundRequest(); | ||
123 | |||
124 | m_log.InfoFormat("[REST]: GET:/asset failed to find {0}", assetID); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | return result; | ||
129 | } | ||
130 | |||
131 | // private byte[] ProcessOutgoingAssetData(byte[] assetData) | ||
132 | // { | ||
133 | // string data = Encoding.ASCII.GetString(assetData); | ||
134 | |||
135 | // data = ProcessAssetDataString(data); | ||
136 | |||
137 | // return Encoding.ASCII.GetBytes(data); | ||
138 | // } | ||
139 | |||
140 | public string ProcessAssetDataString(string data) | ||
141 | { | ||
142 | Regex regex = new Regex("(creator_id|owner_id)\\s+(\\S+)"); | ||
143 | |||
144 | // IUserService userService = null; | ||
145 | |||
146 | data = regex.Replace(data, delegate(Match m) | ||
147 | { | ||
148 | string result = String.Empty; | ||
149 | |||
150 | // string key = m.Groups[1].Captures[0].Value; | ||
151 | // | ||
152 | // string value = m.Groups[2].Captures[0].Value; | ||
153 | // | ||
154 | // Guid userUri; | ||
155 | // | ||
156 | // switch (key) | ||
157 | // { | ||
158 | // case "creator_id": | ||
159 | // userUri = new Guid(value); | ||
160 | // // result = "creator_url " + userService(userService, userUri); | ||
161 | // break; | ||
162 | // | ||
163 | // case "owner_id": | ||
164 | // userUri = new Guid(value); | ||
165 | // // result = "owner_url " + ResolveUserUri(userService, userUri); | ||
166 | // break; | ||
167 | // } | ||
168 | |||
169 | return result; | ||
170 | }); | ||
171 | |||
172 | return data; | ||
173 | } | ||
174 | |||
175 | private string SLAssetTypeToContentType(int assetType) | ||
176 | { | ||
177 | switch (assetType) | ||
178 | { | ||
179 | case 0: | ||
180 | return "image/jp2"; | ||
181 | case 1: | ||
182 | return "application/ogg"; | ||
183 | case 2: | ||
184 | return "application/x-metaverse-callingcard"; | ||
185 | case 3: | ||
186 | return "application/x-metaverse-landmark"; | ||
187 | case 5: | ||
188 | return "application/x-metaverse-clothing"; | ||
189 | case 6: | ||
190 | return "application/x-metaverse-primitive"; | ||
191 | case 7: | ||
192 | return "application/x-metaverse-notecard"; | ||
193 | case 8: | ||
194 | return "application/x-metaverse-folder"; | ||
195 | case 10: | ||
196 | return "application/x-metaverse-lsl"; | ||
197 | case 11: | ||
198 | return "application/x-metaverse-lso"; | ||
199 | case 12: | ||
200 | return "image/tga"; | ||
201 | case 13: | ||
202 | return "application/x-metaverse-bodypart"; | ||
203 | case 17: | ||
204 | return "audio/x-wav"; | ||
205 | case 19: | ||
206 | return "image/jpeg"; | ||
207 | case 20: | ||
208 | return "application/x-metaverse-animation"; | ||
209 | case 21: | ||
210 | return "application/x-metaverse-gesture"; | ||
211 | case 22: | ||
212 | return "application/x-metaverse-simstate"; | ||
213 | default: | ||
214 | return "application/octet-stream"; | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | } | ||
diff --git a/OpenSim/Framework/Servers/CheckSumServer.cs b/OpenSim/Framework/Servers/CheckSumServer.cs new file mode 100644 index 0000000..63059f0 --- /dev/null +++ b/OpenSim/Framework/Servers/CheckSumServer.cs | |||
@@ -0,0 +1,26 @@ | |||
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 | */ | ||
diff --git a/OpenSim/Framework/Servers/GetAssetStreamHandler.cs b/OpenSim/Framework/Servers/GetAssetStreamHandler.cs new file mode 100644 index 0000000..c935d2a --- /dev/null +++ b/OpenSim/Framework/Servers/GetAssetStreamHandler.cs | |||
@@ -0,0 +1,217 @@ | |||
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.IO; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using System.Text.RegularExpressions; | ||
33 | using System.Xml; | ||
34 | using System.Xml.Serialization; | ||
35 | using log4net; | ||
36 | using OpenMetaverse; | ||
37 | using OpenSim.Data; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Servers; | ||
40 | using OpenSim.Framework.Servers.HttpServer; | ||
41 | using OpenSim.Framework.Statistics; | ||
42 | using System.Net; | ||
43 | |||
44 | namespace OpenSim.Framework.Servers | ||
45 | { | ||
46 | public class GetAssetStreamHandler : BaseStreamHandler | ||
47 | { | ||
48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | // private OpenAsset_Main m_assetManager; | ||
51 | private IAssetDataPlugin m_assetProvider; | ||
52 | |||
53 | /// <summary> | ||
54 | /// Constructor. | ||
55 | /// </summary> | ||
56 | /// <param name="assetManager"></param> | ||
57 | /// <param name="assetProvider"></param> | ||
58 | public GetAssetStreamHandler(IAssetDataPlugin assetProvider) | ||
59 | : base("GET", "/assets") | ||
60 | { | ||
61 | m_log.Info("[REST]: In Get Request"); | ||
62 | // m_assetManager = assetManager; | ||
63 | m_assetProvider = assetProvider; | ||
64 | } | ||
65 | |||
66 | public override byte[] Handle(string path, Stream request, | ||
67 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
68 | { | ||
69 | string param = GetParam(path); | ||
70 | byte[] result = new byte[] { }; | ||
71 | |||
72 | string[] p = param.Split(new char[] { '/', '?', '&' }, StringSplitOptions.RemoveEmptyEntries); | ||
73 | |||
74 | if (p.Length > 0) | ||
75 | { | ||
76 | UUID assetID = UUID.Zero; | ||
77 | |||
78 | if (!UUID.TryParse(p[0], out assetID)) | ||
79 | { | ||
80 | m_log.InfoFormat( | ||
81 | "[REST]: GET:/asset ignoring request with malformed UUID {0}", p[0]); | ||
82 | return result; | ||
83 | } | ||
84 | |||
85 | if (StatsManager.AssetStats != null) | ||
86 | StatsManager.AssetStats.AddRequest(); | ||
87 | |||
88 | AssetBase asset = m_assetProvider.FetchAsset(assetID); | ||
89 | if (asset != null) | ||
90 | { | ||
91 | // if (asset.ContainsReferences) | ||
92 | // { | ||
93 | // asset.Data = ProcessOutgoingAssetData(asset.Data); | ||
94 | // } | ||
95 | if (p.Length > 1 && p[1] == "data") | ||
96 | { | ||
97 | httpResponse.StatusCode = (int)HttpStatusCode.OK; | ||
98 | httpResponse.ContentType = SLAssetTypeToContentType(asset.Type); | ||
99 | result = asset.Data; | ||
100 | } | ||
101 | else | ||
102 | { | ||
103 | XmlSerializer xs = new XmlSerializer(typeof(AssetBase)); | ||
104 | MemoryStream ms = new MemoryStream(); | ||
105 | XmlTextWriter xw = new XmlTextWriter(ms, Encoding.UTF8); | ||
106 | xw.Formatting = Formatting.Indented; | ||
107 | xs.Serialize(xw, asset); | ||
108 | xw.Flush(); | ||
109 | |||
110 | ms.Seek(0, SeekOrigin.Begin); | ||
111 | //StreamReader sr = new StreamReader(ms); | ||
112 | |||
113 | result = ms.GetBuffer(); | ||
114 | |||
115 | Array.Resize<byte>(ref result, (int)ms.Length); | ||
116 | } | ||
117 | } | ||
118 | else | ||
119 | { | ||
120 | if (StatsManager.AssetStats != null) | ||
121 | StatsManager.AssetStats.AddNotFoundRequest(); | ||
122 | |||
123 | m_log.InfoFormat("[REST]: GET:/asset failed to find {0}", assetID); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | return result; | ||
128 | } | ||
129 | |||
130 | // private byte[] ProcessOutgoingAssetData(byte[] assetData) | ||
131 | // { | ||
132 | // string data = Encoding.ASCII.GetString(assetData); | ||
133 | |||
134 | // data = ProcessAssetDataString(data); | ||
135 | |||
136 | // return Encoding.ASCII.GetBytes(data); | ||
137 | // } | ||
138 | |||
139 | public string ProcessAssetDataString(string data) | ||
140 | { | ||
141 | Regex regex = new Regex("(creator_id|owner_id)\\s+(\\S+)"); | ||
142 | |||
143 | // IUserService userService = null; | ||
144 | |||
145 | data = regex.Replace(data, delegate(Match m) | ||
146 | { | ||
147 | string result = String.Empty; | ||
148 | |||
149 | // string key = m.Groups[1].Captures[0].Value; | ||
150 | // | ||
151 | // string value = m.Groups[2].Captures[0].Value; | ||
152 | // | ||
153 | // Guid userUri; | ||
154 | // | ||
155 | // switch (key) | ||
156 | // { | ||
157 | // case "creator_id": | ||
158 | // userUri = new Guid(value); | ||
159 | // // result = "creator_url " + userService(userService, userUri); | ||
160 | // break; | ||
161 | // | ||
162 | // case "owner_id": | ||
163 | // userUri = new Guid(value); | ||
164 | // // result = "owner_url " + ResolveUserUri(userService, userUri); | ||
165 | // break; | ||
166 | // } | ||
167 | |||
168 | return result; | ||
169 | }); | ||
170 | |||
171 | return data; | ||
172 | } | ||
173 | |||
174 | private string SLAssetTypeToContentType(int assetType) | ||
175 | { | ||
176 | switch (assetType) | ||
177 | { | ||
178 | case 0: | ||
179 | return "image/jp2"; | ||
180 | case 1: | ||
181 | return "application/ogg"; | ||
182 | case 2: | ||
183 | return "application/x-metaverse-callingcard"; | ||
184 | case 3: | ||
185 | return "application/x-metaverse-landmark"; | ||
186 | case 5: | ||
187 | return "application/x-metaverse-clothing"; | ||
188 | case 6: | ||
189 | return "application/x-metaverse-primitive"; | ||
190 | case 7: | ||
191 | return "application/x-metaverse-notecard"; | ||
192 | case 8: | ||
193 | return "application/x-metaverse-folder"; | ||
194 | case 10: | ||
195 | return "application/x-metaverse-lsl"; | ||
196 | case 11: | ||
197 | return "application/x-metaverse-lso"; | ||
198 | case 12: | ||
199 | return "image/tga"; | ||
200 | case 13: | ||
201 | return "application/x-metaverse-bodypart"; | ||
202 | case 17: | ||
203 | return "audio/x-wav"; | ||
204 | case 19: | ||
205 | return "image/jpeg"; | ||
206 | case 20: | ||
207 | return "application/x-metaverse-animation"; | ||
208 | case 21: | ||
209 | return "application/x-metaverse-gesture"; | ||
210 | case 22: | ||
211 | return "application/x-metaverse-simstate"; | ||
212 | default: | ||
213 | return "application/octet-stream"; | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHTTPHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseHTTPHandler.cs new file mode 100644 index 0000000..fc89e30 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseHTTPHandler.cs | |||
@@ -0,0 +1,41 @@ | |||
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 | |||
28 | using System.Collections; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | public abstract class BaseHTTPHandler : BaseRequestHandler, IGenericHTTPHandler | ||
33 | { | ||
34 | public abstract Hashtable Handle(string path, Hashtable Request); | ||
35 | |||
36 | protected BaseHTTPHandler(string httpMethod, string path) | ||
37 | : base(httpMethod, path) | ||
38 | { | ||
39 | } | ||
40 | } | ||
41 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs new file mode 100644 index 0000000..779f577 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | |||
@@ -0,0 +1,1626 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Net; | ||
33 | using System.Net.Sockets; | ||
34 | using System.Reflection; | ||
35 | using System.Globalization; | ||
36 | using System.Text; | ||
37 | using System.Threading; | ||
38 | using System.Xml; | ||
39 | using HttpServer; | ||
40 | using log4net; | ||
41 | using Nwc.XmlRpc; | ||
42 | using OpenMetaverse.StructuredData; | ||
43 | using CoolHTTPListener = HttpServer.HttpListener; | ||
44 | using HttpListener=System.Net.HttpListener; | ||
45 | |||
46 | namespace OpenSim.Framework.Servers.HttpServer | ||
47 | { | ||
48 | public class BaseHttpServer : IHttpServer | ||
49 | { | ||
50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); | ||
52 | |||
53 | private volatile int NotSocketErrors = 0; | ||
54 | public volatile bool HTTPDRunning = false; | ||
55 | |||
56 | protected Thread m_workerThread; | ||
57 | // protected HttpListener m_httpListener; | ||
58 | protected CoolHTTPListener m_httpListener2; | ||
59 | protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); | ||
60 | protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>(); | ||
61 | protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ | ||
62 | protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); | ||
63 | protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>(); | ||
64 | protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>(); | ||
65 | protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>(); | ||
66 | |||
67 | protected uint m_port; | ||
68 | protected uint m_sslport; | ||
69 | protected bool m_ssl; | ||
70 | protected bool m_firstcaps = true; | ||
71 | protected string m_SSLCommonName = ""; | ||
72 | |||
73 | public uint SSLPort | ||
74 | { | ||
75 | get { return m_sslport; } | ||
76 | } | ||
77 | |||
78 | public string SSLCommonName | ||
79 | { | ||
80 | get { return m_SSLCommonName; } | ||
81 | } | ||
82 | |||
83 | public uint Port | ||
84 | { | ||
85 | get { return m_port; } | ||
86 | } | ||
87 | |||
88 | public bool UseSSL | ||
89 | { | ||
90 | get { return m_ssl; } | ||
91 | } | ||
92 | |||
93 | public BaseHttpServer(uint port) | ||
94 | { | ||
95 | m_port = port; | ||
96 | } | ||
97 | |||
98 | public BaseHttpServer(uint port, bool ssl) : this (port) | ||
99 | { | ||
100 | m_ssl = ssl; | ||
101 | } | ||
102 | |||
103 | public BaseHttpServer(uint port, bool ssl, uint sslport, string CN) : this (port, ssl) | ||
104 | { | ||
105 | if (m_ssl) | ||
106 | { | ||
107 | m_sslport = sslport; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /// <summary> | ||
112 | /// Add a stream handler to the http server. If the handler already exists, then nothing happens. | ||
113 | /// </summary> | ||
114 | /// <param name="handler"></param> | ||
115 | public void AddStreamHandler(IRequestHandler handler) | ||
116 | { | ||
117 | string httpMethod = handler.HttpMethod; | ||
118 | string path = handler.Path; | ||
119 | string handlerKey = GetHandlerKey(httpMethod, path); | ||
120 | |||
121 | lock (m_streamHandlers) | ||
122 | { | ||
123 | if (!m_streamHandlers.ContainsKey(handlerKey)) | ||
124 | { | ||
125 | // m_log.DebugFormat("[BASE HTTP SERVER]: Adding handler key {0}", handlerKey); | ||
126 | m_streamHandlers.Add(handlerKey, handler); | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | private static string GetHandlerKey(string httpMethod, string path) | ||
132 | { | ||
133 | return httpMethod + ":" + path; | ||
134 | } | ||
135 | |||
136 | public bool AddXmlRPCHandler(string method, XmlRpcMethod handler) | ||
137 | { | ||
138 | return AddXmlRPCHandler(method, handler, true); | ||
139 | } | ||
140 | |||
141 | public bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive) | ||
142 | { | ||
143 | lock (m_rpcHandlers) | ||
144 | { | ||
145 | m_rpcHandlers[method] = handler; | ||
146 | m_rpcHandlersKeepAlive[method] = keepAlive; // default | ||
147 | } | ||
148 | |||
149 | return true; | ||
150 | } | ||
151 | |||
152 | public XmlRpcMethod GetXmlRPCHandler(string method) | ||
153 | { | ||
154 | lock (m_rpcHandlers) | ||
155 | { | ||
156 | if (m_rpcHandlers.ContainsKey(method)) | ||
157 | { | ||
158 | return m_rpcHandlers[method]; | ||
159 | } | ||
160 | else | ||
161 | { | ||
162 | return null; | ||
163 | } | ||
164 | } | ||
165 | } | ||
166 | |||
167 | public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) | ||
168 | { | ||
169 | //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); | ||
170 | |||
171 | lock (m_HTTPHandlers) | ||
172 | { | ||
173 | if (!m_HTTPHandlers.ContainsKey(methodName)) | ||
174 | { | ||
175 | m_HTTPHandlers.Add(methodName, handler); | ||
176 | return true; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | //must already have a handler for that path so return false | ||
181 | return false; | ||
182 | } | ||
183 | |||
184 | // Note that the agent string is provided simply to differentiate | ||
185 | // the handlers - it is NOT required to be an actual agent header | ||
186 | // value. | ||
187 | public bool AddAgentHandler(string agent, IHttpAgentHandler handler) | ||
188 | { | ||
189 | lock (m_agentHandlers) | ||
190 | { | ||
191 | if (!m_agentHandlers.ContainsKey(agent)) | ||
192 | { | ||
193 | m_agentHandlers.Add(agent, handler); | ||
194 | return true; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | //must already have a handler for that path so return false | ||
199 | return false; | ||
200 | } | ||
201 | |||
202 | public bool AddLLSDHandler(string path, LLSDMethod handler) | ||
203 | { | ||
204 | lock (m_llsdHandlers) | ||
205 | { | ||
206 | if (!m_llsdHandlers.ContainsKey(path)) | ||
207 | { | ||
208 | m_llsdHandlers.Add(path, handler); | ||
209 | return true; | ||
210 | } | ||
211 | } | ||
212 | return false; | ||
213 | } | ||
214 | |||
215 | public bool SetDefaultLLSDHandler(DefaultLLSDMethod handler) | ||
216 | { | ||
217 | m_defaultLlsdHandler = handler; | ||
218 | return true; | ||
219 | } | ||
220 | |||
221 | public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) | ||
222 | { | ||
223 | OSHttpRequest req = new OSHttpRequest(context, request); | ||
224 | OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request)); | ||
225 | //resp.KeepAlive = req.KeepAlive; | ||
226 | //m_log.Info("[Debug BASE HTTP SERVER]: Got Request"); | ||
227 | //HttpServerContextObj objstate= new HttpServerContextObj(req,resp); | ||
228 | //ThreadPool.QueueUserWorkItem(new WaitCallback(ConvertIHttpClientContextToOSHttp), (object)objstate); | ||
229 | HandleRequest(req, resp); | ||
230 | } | ||
231 | |||
232 | public void ConvertIHttpClientContextToOSHttp(object stateinfo) | ||
233 | { | ||
234 | HttpServerContextObj objstate = (HttpServerContextObj)stateinfo; | ||
235 | //OSHttpRequest request = new OSHttpRequest(objstate.context,objstate.req); | ||
236 | //OSHttpResponse resp = new OSHttpResponse(new HttpServer.HttpResponse(objstate.context, objstate.req)); | ||
237 | |||
238 | OSHttpRequest request = objstate.oreq; | ||
239 | OSHttpResponse resp = objstate.oresp; | ||
240 | //OSHttpResponse resp = new OSHttpResponse(new HttpServer.HttpResponse(objstate.context, objstate.req)); | ||
241 | |||
242 | /* | ||
243 | request.AcceptTypes = objstate.req.AcceptTypes; | ||
244 | request.ContentLength = (long)objstate.req.ContentLength; | ||
245 | request.Headers = objstate.req.Headers; | ||
246 | request.HttpMethod = objstate.req.Method; | ||
247 | request.InputStream = objstate.req.Body; | ||
248 | foreach (string str in request.Headers) | ||
249 | { | ||
250 | if (str.ToLower().Contains("content-type: ")) | ||
251 | { | ||
252 | request.ContentType = str.Substring(13, str.Length - 13); | ||
253 | break; | ||
254 | } | ||
255 | } | ||
256 | //request.KeepAlive = objstate.req. | ||
257 | foreach (HttpServer.HttpInput httpinput in objstate.req.QueryString) | ||
258 | { | ||
259 | request.QueryString.Add(httpinput.Name, httpinput[httpinput.Name]); | ||
260 | } | ||
261 | |||
262 | //request.Query = objstate.req.//objstate.req.QueryString; | ||
263 | //foreach ( | ||
264 | //request.QueryString = objstate.req.QueryString; | ||
265 | |||
266 | */ | ||
267 | HandleRequest(request,resp); | ||
268 | } | ||
269 | |||
270 | public virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response) | ||
271 | { | ||
272 | try | ||
273 | { | ||
274 | Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); | ||
275 | // This is the REST agent interface. We require an agent to properly identify | ||
276 | // itself. If the REST handler recognizes the prefix it will attempt to | ||
277 | // satisfy the request. If it is not recognizable, and no damage has occurred | ||
278 | // the request can be passed through to the other handlers. This is a low | ||
279 | // probability event; if a request is matched it is normally expected to be | ||
280 | // handled | ||
281 | //m_log.Debug("[BASE HTTP SERVER]: Handling Request" + request.RawUrl); | ||
282 | IHttpAgentHandler agentHandler; | ||
283 | |||
284 | if (TryGetAgentHandler(request, response, out agentHandler)) | ||
285 | { | ||
286 | if (HandleAgentRequest(agentHandler, request, response)) | ||
287 | { | ||
288 | return; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | IRequestHandler requestHandler; | ||
293 | //response.KeepAlive = true; | ||
294 | response.SendChunked = false; | ||
295 | |||
296 | string path = request.RawUrl; | ||
297 | string handlerKey = GetHandlerKey(request.HttpMethod, path); | ||
298 | |||
299 | //m_log.DebugFormat("[BASE HTTP SERVER]: Handling {0} request for {1}", request.HttpMethod, path); | ||
300 | |||
301 | if (TryGetStreamHandler(handlerKey, out requestHandler)) | ||
302 | { | ||
303 | //m_log.Debug("[BASE HTTP SERVER]: Found Stream Handler"); | ||
304 | // Okay, so this is bad, but should be considered temporary until everything is IStreamHandler. | ||
305 | byte[] buffer; | ||
306 | |||
307 | response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. | ||
308 | |||
309 | if (requestHandler is IStreamedRequestHandler) | ||
310 | { | ||
311 | IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; | ||
312 | |||
313 | buffer = streamedRequestHandler.Handle(path, request.InputStream, request, response); | ||
314 | } | ||
315 | else if (requestHandler is IGenericHTTPHandler) | ||
316 | { | ||
317 | //m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler"); | ||
318 | IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler; | ||
319 | Stream requestStream = request.InputStream; | ||
320 | |||
321 | Encoding encoding = Encoding.UTF8; | ||
322 | StreamReader reader = new StreamReader(requestStream, encoding); | ||
323 | |||
324 | string requestBody = reader.ReadToEnd(); | ||
325 | |||
326 | reader.Close(); | ||
327 | requestStream.Close(); | ||
328 | |||
329 | Hashtable keysvals = new Hashtable(); | ||
330 | Hashtable headervals = new Hashtable(); | ||
331 | //string host = String.Empty; | ||
332 | |||
333 | string[] querystringkeys = request.QueryString.AllKeys; | ||
334 | string[] rHeaders = request.Headers.AllKeys; | ||
335 | |||
336 | |||
337 | foreach (string queryname in querystringkeys) | ||
338 | { | ||
339 | keysvals.Add(queryname, request.QueryString[queryname]); | ||
340 | } | ||
341 | |||
342 | foreach (string headername in rHeaders) | ||
343 | { | ||
344 | //m_log.Warn("[HEADER]: " + headername + "=" + request.Headers[headername]); | ||
345 | headervals[headername] = request.Headers[headername]; | ||
346 | } | ||
347 | |||
348 | // if (headervals.Contains("Host")) | ||
349 | // { | ||
350 | // host = (string)headervals["Host"]; | ||
351 | // } | ||
352 | |||
353 | keysvals.Add("requestbody", requestBody); | ||
354 | if (keysvals.Contains("method")) | ||
355 | { | ||
356 | //m_log.Warn("[HTTP]: Contains Method"); | ||
357 | //string method = (string)keysvals["method"]; | ||
358 | //m_log.Warn("[HTTP]: " + requestBody); | ||
359 | |||
360 | } | ||
361 | DoHTTPGruntWork(HTTPRequestHandler.Handle(path, keysvals), response); | ||
362 | return; | ||
363 | } | ||
364 | else | ||
365 | { | ||
366 | IStreamHandler streamHandler = (IStreamHandler)requestHandler; | ||
367 | |||
368 | using (MemoryStream memoryStream = new MemoryStream()) | ||
369 | { | ||
370 | streamHandler.Handle(path, request.InputStream, memoryStream, request, response); | ||
371 | memoryStream.Flush(); | ||
372 | buffer = memoryStream.ToArray(); | ||
373 | } | ||
374 | } | ||
375 | |||
376 | request.InputStream.Close(); | ||
377 | |||
378 | if (!response.SendChunked) | ||
379 | response.ContentLength64 = buffer.LongLength; | ||
380 | |||
381 | try | ||
382 | { | ||
383 | response.OutputStream.Write(buffer, 0, buffer.Length); | ||
384 | //response.OutputStream.Close(); | ||
385 | } | ||
386 | catch (HttpListenerException) | ||
387 | { | ||
388 | m_log.WarnFormat("[BASE HTTP SERVER]: HTTP request abnormally terminated."); | ||
389 | } | ||
390 | //response.OutputStream.Close(); | ||
391 | try | ||
392 | { | ||
393 | response.Send(); | ||
394 | } | ||
395 | catch (SocketException e) | ||
396 | { | ||
397 | // This has to be here to prevent a Linux/Mono crash | ||
398 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
399 | } | ||
400 | return; | ||
401 | } | ||
402 | |||
403 | if (request.AcceptTypes != null && request.AcceptTypes.Length > 0) | ||
404 | { | ||
405 | foreach (string strAccept in request.AcceptTypes) | ||
406 | { | ||
407 | if (strAccept.Contains("application/llsd+xml")) | ||
408 | { | ||
409 | //m_log.Info("[Debug BASE HTTP SERVER]: Found an application/llsd+xml accept header"); | ||
410 | HandleLLSDRequests(request, response); | ||
411 | return; | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | |||
416 | switch (request.ContentType) | ||
417 | { | ||
418 | case null: | ||
419 | case "text/html": | ||
420 | //m_log.Info("[Debug BASE HTTP SERVER]: found a text/html content type"); | ||
421 | HandleHTTPRequest(request, response); | ||
422 | return; | ||
423 | |||
424 | case "application/llsd+xml": | ||
425 | case "application/xml+llsd": | ||
426 | //m_log.Info("[Debug BASE HTTP SERVER]: found a application/llsd+xml content type"); | ||
427 | HandleLLSDRequests(request, response); | ||
428 | return; | ||
429 | |||
430 | case "text/xml": | ||
431 | case "application/xml": | ||
432 | default: | ||
433 | //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); | ||
434 | // Point of note.. the DoWeHaveA methods check for an EXACT path | ||
435 | // if (request.RawUrl.Contains("/CAPS/EQG")) | ||
436 | // { | ||
437 | // int i = 1; | ||
438 | // } | ||
439 | //m_log.Info("[Debug BASE HTTP SERVER]: Checking for LLSD Handler"); | ||
440 | if (DoWeHaveALLSDHandler(request.RawUrl)) | ||
441 | { | ||
442 | //m_log.Info("[Debug BASE HTTP SERVER]: Found LLSD Handler"); | ||
443 | HandleLLSDRequests(request, response); | ||
444 | return; | ||
445 | } | ||
446 | //m_log.Info("[Debug BASE HTTP SERVER]: Checking for HTTP Handler"); | ||
447 | if (DoWeHaveAHTTPHandler(request.RawUrl)) | ||
448 | { | ||
449 | //m_log.Info("[Debug BASE HTTP SERVER]: found HTTP Handler"); | ||
450 | HandleHTTPRequest(request, response); | ||
451 | return; | ||
452 | } | ||
453 | |||
454 | //m_log.Info("[Debug BASE HTTP SERVER]: Generic XMLRPC"); | ||
455 | // generic login request. | ||
456 | HandleXmlRpcRequests(request, response); | ||
457 | |||
458 | return; | ||
459 | } | ||
460 | } | ||
461 | catch (SocketException e) | ||
462 | { | ||
463 | // At least on linux, it appears that if the client makes a request without requiring the response, | ||
464 | // an unconnected socket exception is thrown when we close the response output stream. There's no | ||
465 | // obvious way to tell if the client didn't require the response, so instead we'll catch and ignore | ||
466 | // the exception instead. | ||
467 | // | ||
468 | // An alternative may be to turn off all response write exceptions on the HttpListener, but let's go | ||
469 | // with the minimum first | ||
470 | m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e); | ||
471 | } | ||
472 | catch (EndOfStreamException e) | ||
473 | { | ||
474 | m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); | ||
475 | } | ||
476 | catch (InvalidOperationException e) | ||
477 | { | ||
478 | m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); | ||
479 | SendHTML500(response); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler) | ||
484 | { | ||
485 | string bestMatch = null; | ||
486 | |||
487 | lock (m_streamHandlers) | ||
488 | { | ||
489 | foreach (string pattern in m_streamHandlers.Keys) | ||
490 | { | ||
491 | if (handlerKey.StartsWith(pattern)) | ||
492 | { | ||
493 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) | ||
494 | { | ||
495 | bestMatch = pattern; | ||
496 | } | ||
497 | } | ||
498 | } | ||
499 | |||
500 | if (String.IsNullOrEmpty(bestMatch)) | ||
501 | { | ||
502 | streamHandler = null; | ||
503 | return false; | ||
504 | } | ||
505 | else | ||
506 | { | ||
507 | streamHandler = m_streamHandlers[bestMatch]; | ||
508 | return true; | ||
509 | } | ||
510 | } | ||
511 | } | ||
512 | |||
513 | private bool TryGetHTTPHandler(string handlerKey, out GenericHTTPMethod HTTPHandler) | ||
514 | { | ||
515 | //m_log.DebugFormat("[BASE HTTP HANDLER]: Looking for HTTP handler for {0}", handlerKey); | ||
516 | |||
517 | string bestMatch = null; | ||
518 | |||
519 | lock (m_HTTPHandlers) | ||
520 | { | ||
521 | foreach (string pattern in m_HTTPHandlers.Keys) | ||
522 | { | ||
523 | if (handlerKey.StartsWith(pattern)) | ||
524 | { | ||
525 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) | ||
526 | { | ||
527 | bestMatch = pattern; | ||
528 | } | ||
529 | } | ||
530 | } | ||
531 | |||
532 | if (String.IsNullOrEmpty(bestMatch)) | ||
533 | { | ||
534 | HTTPHandler = null; | ||
535 | return false; | ||
536 | } | ||
537 | else | ||
538 | { | ||
539 | HTTPHandler = m_HTTPHandlers[bestMatch]; | ||
540 | return true; | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | |||
545 | private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler) | ||
546 | { | ||
547 | agentHandler = null; | ||
548 | try | ||
549 | { | ||
550 | foreach (IHttpAgentHandler handler in m_agentHandlers.Values) | ||
551 | { | ||
552 | if (handler.Match(request, response)) | ||
553 | { | ||
554 | agentHandler = handler; | ||
555 | return true; | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | catch(KeyNotFoundException) | ||
560 | { | ||
561 | } | ||
562 | |||
563 | return false; | ||
564 | } | ||
565 | |||
566 | /// <summary> | ||
567 | /// Try all the registered xmlrpc handlers when an xmlrpc request is received. | ||
568 | /// Sends back an XMLRPC unknown request response if no handler is registered for the requested method. | ||
569 | /// </summary> | ||
570 | /// <param name="request"></param> | ||
571 | /// <param name="response"></param> | ||
572 | private void HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response) | ||
573 | { | ||
574 | Stream requestStream = request.InputStream; | ||
575 | |||
576 | Encoding encoding = Encoding.UTF8; | ||
577 | StreamReader reader = new StreamReader(requestStream, encoding); | ||
578 | |||
579 | string requestBody = reader.ReadToEnd(); | ||
580 | reader.Close(); | ||
581 | requestStream.Close(); | ||
582 | |||
583 | string responseString = String.Empty; | ||
584 | XmlRpcRequest xmlRprcRequest = null; | ||
585 | |||
586 | try | ||
587 | { | ||
588 | xmlRprcRequest = (XmlRpcRequest) (new XmlRpcRequestDeserializer()).Deserialize(requestBody); | ||
589 | } | ||
590 | catch (XmlException) | ||
591 | { | ||
592 | } | ||
593 | |||
594 | if (xmlRprcRequest != null) | ||
595 | { | ||
596 | string methodName = xmlRprcRequest.MethodName; | ||
597 | if (methodName != null) | ||
598 | { | ||
599 | xmlRprcRequest.Params.Add(request.RemoteIPEndPoint); // Param[1] | ||
600 | XmlRpcResponse xmlRpcResponse; | ||
601 | |||
602 | XmlRpcMethod method; | ||
603 | bool methodWasFound; | ||
604 | lock (m_rpcHandlers) | ||
605 | { | ||
606 | methodWasFound = m_rpcHandlers.TryGetValue(methodName, out method); | ||
607 | } | ||
608 | |||
609 | if (methodWasFound) | ||
610 | { | ||
611 | xmlRprcRequest.Params.Add(request.Url); // Param[2] | ||
612 | |||
613 | try | ||
614 | { | ||
615 | xmlRpcResponse = method(xmlRprcRequest); | ||
616 | } | ||
617 | catch(Exception e) | ||
618 | { | ||
619 | // if the registered XmlRpc method threw an exception, we pass a fault-code along | ||
620 | xmlRpcResponse = new XmlRpcResponse(); | ||
621 | // Code probably set in accordance with http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php | ||
622 | xmlRpcResponse.SetFault(-32603, String.Format("Requested method [{0}] threw exception: {1}", | ||
623 | methodName, e.Message)); | ||
624 | } | ||
625 | // if the method wasn't found, we can't determine KeepAlive state anyway, so lets do it only here | ||
626 | response.KeepAlive = m_rpcHandlersKeepAlive[methodName]; | ||
627 | } | ||
628 | else | ||
629 | { | ||
630 | xmlRpcResponse = new XmlRpcResponse(); | ||
631 | // Code set in accordance with http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php | ||
632 | xmlRpcResponse.SetFault(-32601, String.Format("Requested method [{0}] not found", methodName)); | ||
633 | } | ||
634 | |||
635 | responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); | ||
636 | } | ||
637 | else | ||
638 | { | ||
639 | //HandleLLSDRequests(request, response); | ||
640 | response.ContentType = "text/plain"; | ||
641 | response.StatusCode = 404; | ||
642 | response.StatusDescription = "Not Found"; | ||
643 | response.ProtocolVersion = "HTTP/1.0"; | ||
644 | byte[] buf = Encoding.UTF8.GetBytes("Not found"); | ||
645 | response.KeepAlive = false; | ||
646 | |||
647 | m_log.ErrorFormat("[BASE HTTP SERVER] Handler not found for http request {0}", request.RawUrl); | ||
648 | |||
649 | response.SendChunked = false; | ||
650 | response.ContentLength64 = buf.Length; | ||
651 | response.ContentEncoding = Encoding.UTF8; | ||
652 | try | ||
653 | { | ||
654 | response.OutputStream.Write(buf, 0, buf.Length); | ||
655 | } | ||
656 | catch (Exception ex) | ||
657 | { | ||
658 | m_log.Warn("[HTTPD]: Error - " + ex.Message); | ||
659 | } | ||
660 | finally | ||
661 | { | ||
662 | try | ||
663 | { | ||
664 | response.Send(); | ||
665 | } | ||
666 | catch (SocketException e) | ||
667 | { | ||
668 | // This has to be here to prevent a Linux/Mono crash | ||
669 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
670 | } | ||
671 | } | ||
672 | return; | ||
673 | //responseString = "Error"; | ||
674 | } | ||
675 | } | ||
676 | |||
677 | response.ContentType = "text/xml"; | ||
678 | |||
679 | byte[] buffer = Encoding.UTF8.GetBytes(responseString); | ||
680 | |||
681 | response.SendChunked = false; | ||
682 | response.ContentLength64 = buffer.Length; | ||
683 | response.ContentEncoding = Encoding.UTF8; | ||
684 | try | ||
685 | { | ||
686 | response.OutputStream.Write(buffer, 0, buffer.Length); | ||
687 | } | ||
688 | catch (Exception ex) | ||
689 | { | ||
690 | m_log.Warn("[HTTPD]: Error - " + ex.Message); | ||
691 | } | ||
692 | finally | ||
693 | { | ||
694 | try | ||
695 | { | ||
696 | response.Send(); | ||
697 | } | ||
698 | catch (SocketException e) | ||
699 | { | ||
700 | // This has to be here to prevent a Linux/Mono crash | ||
701 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
702 | } | ||
703 | } | ||
704 | } | ||
705 | |||
706 | private void HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) | ||
707 | { | ||
708 | //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); | ||
709 | Stream requestStream = request.InputStream; | ||
710 | |||
711 | Encoding encoding = Encoding.UTF8; | ||
712 | StreamReader reader = new StreamReader(requestStream, encoding); | ||
713 | |||
714 | string requestBody = reader.ReadToEnd(); | ||
715 | reader.Close(); | ||
716 | requestStream.Close(); | ||
717 | |||
718 | //m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody); | ||
719 | response.KeepAlive = true; | ||
720 | |||
721 | OSD llsdRequest = null; | ||
722 | OSD llsdResponse = null; | ||
723 | |||
724 | bool LegacyLLSDLoginLibOMV = (requestBody.Contains("passwd") && requestBody.Contains("mac") && requestBody.Contains("viewer_digest")); | ||
725 | |||
726 | if (requestBody.Length == 0) | ||
727 | // Get Request | ||
728 | { | ||
729 | requestBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><llsd><map><key>request</key><string>get</string></map></llsd>"; | ||
730 | } | ||
731 | try | ||
732 | { | ||
733 | llsdRequest = OSDParser.DeserializeLLSDXml(requestBody); | ||
734 | } | ||
735 | catch (Exception ex) | ||
736 | { | ||
737 | m_log.Warn("[HTTPD]: Error - " + ex.Message); | ||
738 | } | ||
739 | |||
740 | if (llsdRequest != null)// && m_defaultLlsdHandler != null) | ||
741 | { | ||
742 | |||
743 | LLSDMethod llsdhandler = null; | ||
744 | |||
745 | if (TryGetLLSDHandler(request.RawUrl, out llsdhandler) && !LegacyLLSDLoginLibOMV) | ||
746 | { | ||
747 | // we found a registered llsd handler to service this request | ||
748 | llsdResponse = llsdhandler(request.RawUrl, llsdRequest, request.RemoteIPEndPoint.ToString()); | ||
749 | } | ||
750 | else | ||
751 | { | ||
752 | // we didn't find a registered llsd handler to service this request | ||
753 | // check if we have a default llsd handler | ||
754 | |||
755 | if (m_defaultLlsdHandler != null) | ||
756 | { | ||
757 | // LibOMV path | ||
758 | llsdResponse = m_defaultLlsdHandler(llsdRequest); | ||
759 | } | ||
760 | else | ||
761 | { | ||
762 | // Oops, no handler for this.. give em the failed message | ||
763 | llsdResponse = GenerateNoLLSDHandlerResponse(); | ||
764 | } | ||
765 | } | ||
766 | |||
767 | } | ||
768 | else | ||
769 | { | ||
770 | llsdResponse = GenerateNoLLSDHandlerResponse(); | ||
771 | } | ||
772 | byte[] buffer = new byte[0]; | ||
773 | if (llsdResponse.ToString() == "shutdown404!") | ||
774 | { | ||
775 | response.ContentType = "text/plain"; | ||
776 | response.StatusCode = 404; | ||
777 | response.StatusDescription = "Not Found"; | ||
778 | response.ProtocolVersion = "HTTP/1.0"; | ||
779 | buffer = Encoding.UTF8.GetBytes("Not found"); | ||
780 | } | ||
781 | else | ||
782 | { | ||
783 | response.ContentType = "application/llsd+xml"; | ||
784 | //m_log.Info("[Debug BASE HTTP SERVER]: Response: " + llsdResponse.ToString()); | ||
785 | buffer = OSDParser.SerializeLLSDXmlBytes(llsdResponse); | ||
786 | } | ||
787 | response.SendChunked = false; | ||
788 | response.ContentLength64 = buffer.Length; | ||
789 | response.ContentEncoding = Encoding.UTF8; | ||
790 | response.KeepAlive = true; | ||
791 | |||
792 | try | ||
793 | { | ||
794 | response.OutputStream.Write(buffer, 0, buffer.Length); | ||
795 | } | ||
796 | catch (Exception ex) | ||
797 | { | ||
798 | m_log.Warn("[HTTPD]: Error - " + ex.Message); | ||
799 | } | ||
800 | finally | ||
801 | { | ||
802 | //response.OutputStream.Close(); | ||
803 | try | ||
804 | { | ||
805 | response.Send(); | ||
806 | response.OutputStream.Flush(); | ||
807 | response.OutputStream.Close(); | ||
808 | } | ||
809 | catch (IOException e) | ||
810 | { | ||
811 | m_log.DebugFormat("[BASE HTTP SERVER] LLSD IOException {0}.", e); | ||
812 | } | ||
813 | catch (SocketException e) | ||
814 | { | ||
815 | // This has to be here to prevent a Linux/Mono crash | ||
816 | m_log.WarnFormat("[BASE HTTP SERVER] LLSD issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
817 | } | ||
818 | } | ||
819 | } | ||
820 | |||
821 | /// <summary> | ||
822 | /// Checks if we have an Exact path in the LLSD handlers for the path provided | ||
823 | /// </summary> | ||
824 | /// <param name="path">URI of the request</param> | ||
825 | /// <returns>true if we have one, false if not</returns> | ||
826 | private bool DoWeHaveALLSDHandler(string path) | ||
827 | { | ||
828 | |||
829 | string[] pathbase = path.Split('/'); | ||
830 | string searchquery = "/"; | ||
831 | |||
832 | if (pathbase.Length < 1) | ||
833 | return false; | ||
834 | |||
835 | for (int i = 1; i < pathbase.Length; i++) | ||
836 | { | ||
837 | searchquery += pathbase[i]; | ||
838 | if (pathbase.Length - 1 != i) | ||
839 | searchquery += "/"; | ||
840 | } | ||
841 | |||
842 | string bestMatch = null; | ||
843 | |||
844 | foreach (string pattern in m_llsdHandlers.Keys) | ||
845 | { | ||
846 | |||
847 | if (searchquery.StartsWith(pattern) && searchquery.Length >= pattern.Length) | ||
848 | { | ||
849 | |||
850 | bestMatch = pattern; | ||
851 | |||
852 | } | ||
853 | } | ||
854 | |||
855 | // extra kicker to remove the default XMLRPC login case.. just in case.. | ||
856 | if (path != "/" && bestMatch == "/" && searchquery != "/") | ||
857 | return false; | ||
858 | |||
859 | if (path == "/") | ||
860 | return false; | ||
861 | |||
862 | if (String.IsNullOrEmpty(bestMatch)) | ||
863 | { | ||
864 | |||
865 | return false; | ||
866 | } | ||
867 | else | ||
868 | { | ||
869 | |||
870 | return true; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | /// <summary> | ||
875 | /// Checks if we have an Exact path in the HTTP handlers for the path provided | ||
876 | /// </summary> | ||
877 | /// <param name="path">URI of the request</param> | ||
878 | /// <returns>true if we have one, false if not</returns> | ||
879 | private bool DoWeHaveAHTTPHandler(string path) | ||
880 | { | ||
881 | string[] pathbase = path.Split('/'); | ||
882 | string searchquery = "/"; | ||
883 | |||
884 | if (pathbase.Length < 1) | ||
885 | return false; | ||
886 | |||
887 | for (int i = 1; i < pathbase.Length; i++) | ||
888 | { | ||
889 | searchquery += pathbase[i]; | ||
890 | if (pathbase.Length - 1 != i) | ||
891 | searchquery += "/"; | ||
892 | } | ||
893 | |||
894 | string bestMatch = null; | ||
895 | |||
896 | //m_log.DebugFormat("[BASE HTTP HANDLER]: Checking if we have an HTTP handler for {0}", searchquery); | ||
897 | |||
898 | lock (m_HTTPHandlers) | ||
899 | { | ||
900 | foreach (string pattern in m_HTTPHandlers.Keys) | ||
901 | { | ||
902 | if (searchquery.StartsWith(pattern) && searchquery.Length >= pattern.Length) | ||
903 | { | ||
904 | bestMatch = pattern; | ||
905 | } | ||
906 | } | ||
907 | |||
908 | // extra kicker to remove the default XMLRPC login case.. just in case.. | ||
909 | if (path == "/") | ||
910 | return false; | ||
911 | |||
912 | if (String.IsNullOrEmpty(bestMatch)) | ||
913 | { | ||
914 | return false; | ||
915 | } | ||
916 | else | ||
917 | { | ||
918 | return true; | ||
919 | } | ||
920 | } | ||
921 | } | ||
922 | |||
923 | private bool TryGetLLSDHandler(string path, out LLSDMethod llsdHandler) | ||
924 | { | ||
925 | llsdHandler = null; | ||
926 | // Pull out the first part of the path | ||
927 | // splitting the path by '/' means we'll get the following return.. | ||
928 | // {0}/{1}/{2} | ||
929 | // where {0} isn't something we really control 100% | ||
930 | |||
931 | string[] pathbase = path.Split('/'); | ||
932 | string searchquery = "/"; | ||
933 | |||
934 | if (pathbase.Length < 1) | ||
935 | return false; | ||
936 | |||
937 | for (int i=1; i<pathbase.Length; i++) | ||
938 | { | ||
939 | searchquery += pathbase[i]; | ||
940 | if (pathbase.Length-1 != i) | ||
941 | searchquery += "/"; | ||
942 | } | ||
943 | |||
944 | // while the matching algorithm below doesn't require it, we're expecting a query in the form | ||
945 | // | ||
946 | // [] = optional | ||
947 | // /resource/UUID/action[/action] | ||
948 | // | ||
949 | // now try to get the closest match to the reigstered path | ||
950 | // at least for OGP, registered path would probably only consist of the /resource/ | ||
951 | |||
952 | string bestMatch = null; | ||
953 | |||
954 | foreach (string pattern in m_llsdHandlers.Keys) | ||
955 | { | ||
956 | if (searchquery.ToLower().StartsWith(pattern.ToLower())) | ||
957 | { | ||
958 | if (String.IsNullOrEmpty(bestMatch) || searchquery.Length > bestMatch.Length) | ||
959 | { | ||
960 | // You have to specifically register for '/' and to get it, you must specificaly request it | ||
961 | // | ||
962 | if (pattern == "/" && searchquery == "/" || pattern != "/") | ||
963 | bestMatch = pattern; | ||
964 | } | ||
965 | } | ||
966 | } | ||
967 | |||
968 | if (String.IsNullOrEmpty(bestMatch)) | ||
969 | { | ||
970 | llsdHandler = null; | ||
971 | return false; | ||
972 | } | ||
973 | else | ||
974 | { | ||
975 | llsdHandler = m_llsdHandlers[bestMatch]; | ||
976 | return true; | ||
977 | } | ||
978 | } | ||
979 | |||
980 | private OSDMap GenerateNoLLSDHandlerResponse() | ||
981 | { | ||
982 | OSDMap map = new OSDMap(); | ||
983 | map["reason"] = OSD.FromString("LLSDRequest"); | ||
984 | map["message"] = OSD.FromString("No handler registered for LLSD Requests"); | ||
985 | map["login"] = OSD.FromString("false"); | ||
986 | return map; | ||
987 | } | ||
988 | /// <summary> | ||
989 | /// A specific agent handler was provided. Such a handler is expecetd to have an | ||
990 | /// intimate, and highly specific relationship with the client. Consequently, | ||
991 | /// nothing is done here. | ||
992 | /// </summary> | ||
993 | /// <param name="handler"></param> | ||
994 | /// <param name="request"></param> | ||
995 | /// <param name="response"></param> | ||
996 | |||
997 | private bool HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response) | ||
998 | { | ||
999 | // In the case of REST, then handler is responsible for ALL aspects of | ||
1000 | // the request/response handling. Nothing is done here, not even encoding. | ||
1001 | |||
1002 | try | ||
1003 | { | ||
1004 | return handler.Handle(request, response); | ||
1005 | } | ||
1006 | catch (Exception e) | ||
1007 | { | ||
1008 | // If the handler did in fact close the stream, then this will blow | ||
1009 | // chunks. So that that doesn't disturb anybody we throw away any | ||
1010 | // and all exceptions raised. We've done our best to release the | ||
1011 | // client. | ||
1012 | try | ||
1013 | { | ||
1014 | m_log.Warn("[HTTP-AGENT]: Error - " + e.Message); | ||
1015 | response.SendChunked = false; | ||
1016 | response.KeepAlive = true; | ||
1017 | response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError; | ||
1018 | //response.OutputStream.Close(); | ||
1019 | try | ||
1020 | { | ||
1021 | response.Send(); | ||
1022 | } | ||
1023 | catch (SocketException f) | ||
1024 | { | ||
1025 | // This has to be here to prevent a Linux/Mono crash | ||
1026 | m_log.WarnFormat( | ||
1027 | "[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", f); | ||
1028 | } | ||
1029 | } | ||
1030 | catch(Exception) | ||
1031 | { | ||
1032 | } | ||
1033 | } | ||
1034 | |||
1035 | // Indicate that the request has been "handled" | ||
1036 | |||
1037 | return true; | ||
1038 | |||
1039 | } | ||
1040 | |||
1041 | public void HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) | ||
1042 | { | ||
1043 | switch (request.HttpMethod) | ||
1044 | { | ||
1045 | case "OPTIONS": | ||
1046 | response.StatusCode = (int)OSHttpStatusCode.SuccessOk; | ||
1047 | return; | ||
1048 | |||
1049 | default: | ||
1050 | HandleContentVerbs(request, response); | ||
1051 | return; | ||
1052 | } | ||
1053 | } | ||
1054 | |||
1055 | private void HandleContentVerbs(OSHttpRequest request, OSHttpResponse response) | ||
1056 | { | ||
1057 | // This is a test. There's a workable alternative.. as this way sucks. | ||
1058 | // We'd like to put this into a text file parhaps that's easily editable. | ||
1059 | // | ||
1060 | // For this test to work, I used the following secondlife.exe parameters | ||
1061 | // "C:\Program Files\SecondLifeWindLight\SecondLifeWindLight.exe" -settings settings_windlight.xml -channel "Second Life WindLight" -set SystemLanguage en-us -loginpage http://10.1.1.2:8002/?show_login_form=TRUE -loginuri http://10.1.1.2:8002 -user 10.1.1.2 | ||
1062 | // | ||
1063 | // Even after all that, there's still an error, but it's a start. | ||
1064 | // | ||
1065 | // I depend on show_login_form being in the secondlife.exe parameters to figure out | ||
1066 | // to display the form, or process it. | ||
1067 | // a better way would be nifty. | ||
1068 | |||
1069 | Stream requestStream = request.InputStream; | ||
1070 | |||
1071 | Encoding encoding = Encoding.UTF8; | ||
1072 | StreamReader reader = new StreamReader(requestStream, encoding); | ||
1073 | |||
1074 | string requestBody = reader.ReadToEnd(); | ||
1075 | // avoid warning for now | ||
1076 | reader.ReadToEnd(); | ||
1077 | reader.Close(); | ||
1078 | requestStream.Close(); | ||
1079 | |||
1080 | Hashtable keysvals = new Hashtable(); | ||
1081 | Hashtable headervals = new Hashtable(); | ||
1082 | |||
1083 | Hashtable requestVars = new Hashtable(); | ||
1084 | |||
1085 | string host = String.Empty; | ||
1086 | |||
1087 | string[] querystringkeys = request.QueryString.AllKeys; | ||
1088 | string[] rHeaders = request.Headers.AllKeys; | ||
1089 | |||
1090 | keysvals.Add("body", requestBody); | ||
1091 | keysvals.Add("uri", request.RawUrl); | ||
1092 | keysvals.Add("content-type", request.ContentType); | ||
1093 | keysvals.Add("http-method", request.HttpMethod); | ||
1094 | |||
1095 | foreach (string queryname in querystringkeys) | ||
1096 | { | ||
1097 | keysvals.Add(queryname, request.QueryString[queryname]); | ||
1098 | requestVars.Add(queryname, keysvals[queryname]); | ||
1099 | } | ||
1100 | |||
1101 | foreach (string headername in rHeaders) | ||
1102 | { | ||
1103 | //m_log.Warn("[HEADER]: " + headername + "=" + request.Headers[headername]); | ||
1104 | headervals[headername] = request.Headers[headername]; | ||
1105 | } | ||
1106 | |||
1107 | if (headervals.Contains("Host")) | ||
1108 | { | ||
1109 | host = (string)headervals["Host"]; | ||
1110 | } | ||
1111 | |||
1112 | keysvals.Add("headers",headervals); | ||
1113 | keysvals.Add("querystringkeys", querystringkeys); | ||
1114 | keysvals.Add("requestvars", requestVars); | ||
1115 | |||
1116 | if (keysvals.Contains("method")) | ||
1117 | { | ||
1118 | //m_log.Warn("[HTTP]: Contains Method"); | ||
1119 | string method = (string) keysvals["method"]; | ||
1120 | //m_log.Warn("[HTTP]: " + requestBody); | ||
1121 | GenericHTTPMethod requestprocessor; | ||
1122 | bool foundHandler = TryGetHTTPHandler(method, out requestprocessor); | ||
1123 | if (foundHandler) | ||
1124 | { | ||
1125 | Hashtable responsedata1 = requestprocessor(keysvals); | ||
1126 | DoHTTPGruntWork(responsedata1,response); | ||
1127 | |||
1128 | //SendHTML500(response); | ||
1129 | } | ||
1130 | else | ||
1131 | { | ||
1132 | //m_log.Warn("[HTTP]: Handler Not Found"); | ||
1133 | SendHTML404(response, host); | ||
1134 | } | ||
1135 | } | ||
1136 | else | ||
1137 | { | ||
1138 | |||
1139 | GenericHTTPMethod requestprocessor; | ||
1140 | bool foundHandler = TryGetHTTPHandlerPathBased(request.RawUrl, out requestprocessor); | ||
1141 | if (foundHandler) | ||
1142 | { | ||
1143 | Hashtable responsedata2 = requestprocessor(keysvals); | ||
1144 | DoHTTPGruntWork(responsedata2, response); | ||
1145 | |||
1146 | //SendHTML500(response); | ||
1147 | } | ||
1148 | else | ||
1149 | { | ||
1150 | //m_log.Warn("[HTTP]: Handler Not Found"); | ||
1151 | SendHTML404(response, host); | ||
1152 | } | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1156 | private bool TryGetHTTPHandlerPathBased(string path, out GenericHTTPMethod httpHandler) | ||
1157 | { | ||
1158 | httpHandler = null; | ||
1159 | // Pull out the first part of the path | ||
1160 | // splitting the path by '/' means we'll get the following return.. | ||
1161 | // {0}/{1}/{2} | ||
1162 | // where {0} isn't something we really control 100% | ||
1163 | |||
1164 | string[] pathbase = path.Split('/'); | ||
1165 | string searchquery = "/"; | ||
1166 | |||
1167 | if (pathbase.Length < 1) | ||
1168 | return false; | ||
1169 | |||
1170 | for (int i = 1; i < pathbase.Length; i++) | ||
1171 | { | ||
1172 | searchquery += pathbase[i]; | ||
1173 | if (pathbase.Length - 1 != i) | ||
1174 | searchquery += "/"; | ||
1175 | } | ||
1176 | |||
1177 | // while the matching algorithm below doesn't require it, we're expecting a query in the form | ||
1178 | // | ||
1179 | // [] = optional | ||
1180 | // /resource/UUID/action[/action] | ||
1181 | // | ||
1182 | // now try to get the closest match to the reigstered path | ||
1183 | // at least for OGP, registered path would probably only consist of the /resource/ | ||
1184 | |||
1185 | string bestMatch = null; | ||
1186 | |||
1187 | // m_log.DebugFormat( | ||
1188 | // "[BASE HTTP HANDLER]: TryGetHTTPHandlerPathBased() looking for HTTP handler to match {0}", searchquery); | ||
1189 | |||
1190 | lock (m_HTTPHandlers) | ||
1191 | { | ||
1192 | foreach (string pattern in m_HTTPHandlers.Keys) | ||
1193 | { | ||
1194 | if (searchquery.ToLower().StartsWith(pattern.ToLower())) | ||
1195 | { | ||
1196 | if (String.IsNullOrEmpty(bestMatch) || searchquery.Length > bestMatch.Length) | ||
1197 | { | ||
1198 | // You have to specifically register for '/' and to get it, you must specificaly request it | ||
1199 | // | ||
1200 | if (pattern == "/" && searchquery == "/" || pattern != "/") | ||
1201 | bestMatch = pattern; | ||
1202 | } | ||
1203 | } | ||
1204 | } | ||
1205 | |||
1206 | if (String.IsNullOrEmpty(bestMatch)) | ||
1207 | { | ||
1208 | httpHandler = null; | ||
1209 | return false; | ||
1210 | } | ||
1211 | else | ||
1212 | { | ||
1213 | if (bestMatch == "/" && searchquery != "/") | ||
1214 | return false; | ||
1215 | |||
1216 | httpHandler = m_HTTPHandlers[bestMatch]; | ||
1217 | return true; | ||
1218 | } | ||
1219 | } | ||
1220 | } | ||
1221 | |||
1222 | private static void DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) | ||
1223 | { | ||
1224 | //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); | ||
1225 | int responsecode = (int)responsedata["int_response_code"]; | ||
1226 | string responseString = (string)responsedata["str_response_string"]; | ||
1227 | string contentType = (string)responsedata["content_type"]; | ||
1228 | |||
1229 | if (responsedata.ContainsKey("error_status_text")) | ||
1230 | { | ||
1231 | response.StatusDescription = (string)responsedata["error_status_text"]; | ||
1232 | } | ||
1233 | if (responsedata.ContainsKey("http_protocol_version")) | ||
1234 | { | ||
1235 | response.ProtocolVersion = (string)responsedata["http_protocol_version"]; | ||
1236 | } | ||
1237 | |||
1238 | if (responsedata.ContainsKey("keepalive")) | ||
1239 | { | ||
1240 | bool keepalive = (bool)responsedata["keepalive"]; | ||
1241 | response.KeepAlive = keepalive; | ||
1242 | |||
1243 | } | ||
1244 | //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this | ||
1245 | //and should check for NullReferenceExceptions | ||
1246 | |||
1247 | if (string.IsNullOrEmpty(contentType)) | ||
1248 | { | ||
1249 | contentType = "text/html"; | ||
1250 | } | ||
1251 | |||
1252 | // The client ignores anything but 200 here for web login, so ensure that this is 200 for that | ||
1253 | |||
1254 | response.StatusCode = responsecode; | ||
1255 | |||
1256 | if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently) | ||
1257 | { | ||
1258 | response.RedirectLocation = (string)responsedata["str_redirect_location"]; | ||
1259 | response.StatusCode = responsecode; | ||
1260 | } | ||
1261 | |||
1262 | response.AddHeader("Content-Type", contentType); | ||
1263 | |||
1264 | byte[] buffer; | ||
1265 | |||
1266 | if (!(contentType.Contains("image") | ||
1267 | || contentType.Contains("x-shockwave-flash") | ||
1268 | || contentType.Contains("application/x-oar"))) | ||
1269 | { | ||
1270 | // Text | ||
1271 | buffer = Encoding.UTF8.GetBytes(responseString); | ||
1272 | } | ||
1273 | else | ||
1274 | { | ||
1275 | // Binary! | ||
1276 | buffer = Convert.FromBase64String(responseString); | ||
1277 | } | ||
1278 | |||
1279 | response.SendChunked = false; | ||
1280 | response.ContentLength64 = buffer.Length; | ||
1281 | response.ContentEncoding = Encoding.UTF8; | ||
1282 | |||
1283 | try | ||
1284 | { | ||
1285 | response.OutputStream.Write(buffer, 0, buffer.Length); | ||
1286 | } | ||
1287 | catch (Exception ex) | ||
1288 | { | ||
1289 | m_log.Warn("[HTTPD]: Error - " + ex.Message); | ||
1290 | } | ||
1291 | finally | ||
1292 | { | ||
1293 | //response.OutputStream.Close(); | ||
1294 | try | ||
1295 | { | ||
1296 | response.Send(); | ||
1297 | } | ||
1298 | catch (SocketException e) | ||
1299 | { | ||
1300 | // This has to be here to prevent a Linux/Mono crash | ||
1301 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
1302 | } | ||
1303 | } | ||
1304 | } | ||
1305 | |||
1306 | public void SendHTML404(OSHttpResponse response, string host) | ||
1307 | { | ||
1308 | // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s | ||
1309 | response.StatusCode = 404; | ||
1310 | response.AddHeader("Content-type", "text/html"); | ||
1311 | |||
1312 | string responseString = GetHTTP404(host); | ||
1313 | byte[] buffer = Encoding.UTF8.GetBytes(responseString); | ||
1314 | |||
1315 | response.SendChunked = false; | ||
1316 | response.ContentLength64 = buffer.Length; | ||
1317 | response.ContentEncoding = Encoding.UTF8; | ||
1318 | |||
1319 | try | ||
1320 | { | ||
1321 | response.OutputStream.Write(buffer, 0, buffer.Length); | ||
1322 | } | ||
1323 | catch (Exception ex) | ||
1324 | { | ||
1325 | m_log.Warn("[HTTPD]: Error - " + ex.Message); | ||
1326 | } | ||
1327 | finally | ||
1328 | { | ||
1329 | //response.OutputStream.Close(); | ||
1330 | try | ||
1331 | { | ||
1332 | response.Send(); | ||
1333 | } | ||
1334 | catch (SocketException e) | ||
1335 | { | ||
1336 | // This has to be here to prevent a Linux/Mono crash | ||
1337 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
1338 | } | ||
1339 | } | ||
1340 | } | ||
1341 | |||
1342 | public void SendHTML500(OSHttpResponse response) | ||
1343 | { | ||
1344 | // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s | ||
1345 | response.StatusCode = (int)OSHttpStatusCode.SuccessOk; | ||
1346 | response.AddHeader("Content-type", "text/html"); | ||
1347 | |||
1348 | string responseString = GetHTTP500(); | ||
1349 | byte[] buffer = Encoding.UTF8.GetBytes(responseString); | ||
1350 | |||
1351 | response.SendChunked = false; | ||
1352 | response.ContentLength64 = buffer.Length; | ||
1353 | response.ContentEncoding = Encoding.UTF8; | ||
1354 | try | ||
1355 | { | ||
1356 | response.OutputStream.Write(buffer, 0, buffer.Length); | ||
1357 | } | ||
1358 | catch (Exception ex) | ||
1359 | { | ||
1360 | m_log.Warn("[HTTPD]: Error - " + ex.Message); | ||
1361 | } | ||
1362 | finally | ||
1363 | { | ||
1364 | //response.OutputStream.Close(); | ||
1365 | try | ||
1366 | { | ||
1367 | response.Send(); | ||
1368 | } | ||
1369 | catch (SocketException e) | ||
1370 | { | ||
1371 | // This has to be here to prevent a Linux/Mono crash | ||
1372 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
1373 | } | ||
1374 | } | ||
1375 | } | ||
1376 | |||
1377 | public void Start() | ||
1378 | { | ||
1379 | m_log.Info("[HTTPD]: Starting up HTTP Server"); | ||
1380 | |||
1381 | //m_workerThread = new Thread(new ThreadStart(StartHTTP)); | ||
1382 | //m_workerThread.Name = "HttpThread"; | ||
1383 | //m_workerThread.IsBackground = true; | ||
1384 | //m_workerThread.Start(); | ||
1385 | //ThreadTracker.Add(m_workerThread); | ||
1386 | StartHTTP(); | ||
1387 | } | ||
1388 | |||
1389 | private void StartHTTP() | ||
1390 | { | ||
1391 | try | ||
1392 | { | ||
1393 | m_log.Info("[HTTPD]: Spawned main thread OK"); | ||
1394 | //m_httpListener = new HttpListener(); | ||
1395 | NotSocketErrors = 0; | ||
1396 | if (!m_ssl) | ||
1397 | { | ||
1398 | //m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); | ||
1399 | //m_httpListener.Prefixes.Add("http://10.1.1.5:" + m_port + "/"); | ||
1400 | m_httpListener2 = new CoolHTTPListener(IPAddress.Any, (int)m_port); | ||
1401 | m_httpListener2.ExceptionThrown += httpServerException; | ||
1402 | m_httpListener2.LogWriter = httpserverlog; | ||
1403 | |||
1404 | // Uncomment this line in addition to those in HttpServerLogWriter | ||
1405 | // if you want more detailed trace information from the HttpServer | ||
1406 | //m_httpListener2.UseTraceLogs = true; | ||
1407 | |||
1408 | m_httpListener2.DisconnectHandler = httpServerDisconnectMonitor; | ||
1409 | } | ||
1410 | else | ||
1411 | { | ||
1412 | //m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/"); | ||
1413 | //m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); | ||
1414 | } | ||
1415 | |||
1416 | m_httpListener2.RequestHandler += OnHandleRequestIOThread; | ||
1417 | //m_httpListener.Start(); | ||
1418 | m_httpListener2.Start(64); | ||
1419 | HTTPDRunning = true; | ||
1420 | |||
1421 | //HttpListenerContext context; | ||
1422 | //while (true) | ||
1423 | //{ | ||
1424 | // context = m_httpListener.GetContext(); | ||
1425 | // ThreadPool.QueueUserWorkItem(new WaitCallback(HandleRequest), context); | ||
1426 | // } | ||
1427 | } | ||
1428 | catch (Exception e) | ||
1429 | { | ||
1430 | m_log.Error("[HTTPD]: Error - " + e.Message); | ||
1431 | m_log.Error("[HTTPD]: Tip: Do you have permission to listen on port " + m_port + ", " + m_sslport + "?"); | ||
1432 | |||
1433 | // We want this exception to halt the entire server since in current configurations we aren't too | ||
1434 | // useful without inbound HTTP. | ||
1435 | throw e; | ||
1436 | } | ||
1437 | } | ||
1438 | |||
1439 | public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) | ||
1440 | { | ||
1441 | switch (err) | ||
1442 | { | ||
1443 | case SocketError.NotSocket: | ||
1444 | NotSocketErrors++; | ||
1445 | |||
1446 | break; | ||
1447 | } | ||
1448 | } | ||
1449 | |||
1450 | public void httpServerException(object source, Exception exception) | ||
1451 | { | ||
1452 | m_log.ErrorFormat("[HTTPSERVER]: {0} had an exception {1}", source.ToString(), exception.ToString()); | ||
1453 | /* | ||
1454 | if (HTTPDRunning)// && NotSocketErrors > 5) | ||
1455 | { | ||
1456 | Stop(); | ||
1457 | Thread.Sleep(200); | ||
1458 | StartHTTP(); | ||
1459 | m_log.Warn("[HTTPSERVER]: Died. Trying to kick....."); | ||
1460 | } | ||
1461 | */ | ||
1462 | } | ||
1463 | |||
1464 | public void Stop() | ||
1465 | { | ||
1466 | HTTPDRunning = false; | ||
1467 | m_httpListener2.ExceptionThrown -= httpServerException; | ||
1468 | m_httpListener2.DisconnectHandler = null; | ||
1469 | |||
1470 | m_httpListener2.LogWriter = null; | ||
1471 | m_httpListener2.RequestHandler -= OnHandleRequestIOThread; | ||
1472 | |||
1473 | m_httpListener2.Stop(); | ||
1474 | } | ||
1475 | |||
1476 | public void RemoveStreamHandler(string httpMethod, string path) | ||
1477 | { | ||
1478 | string handlerKey = GetHandlerKey(httpMethod, path); | ||
1479 | |||
1480 | //m_log.DebugFormat("[BASE HTTP SERVER]: Removing handler key {0}", handlerKey); | ||
1481 | |||
1482 | lock (m_streamHandlers) m_streamHandlers.Remove(handlerKey); | ||
1483 | } | ||
1484 | |||
1485 | public void RemoveHTTPHandler(string httpMethod, string path) | ||
1486 | { | ||
1487 | lock (m_HTTPHandlers) | ||
1488 | { | ||
1489 | if (httpMethod != null && httpMethod.Length == 0) | ||
1490 | { | ||
1491 | m_HTTPHandlers.Remove(path); | ||
1492 | return; | ||
1493 | } | ||
1494 | |||
1495 | m_HTTPHandlers.Remove(GetHandlerKey(httpMethod, path)); | ||
1496 | } | ||
1497 | } | ||
1498 | |||
1499 | public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler) | ||
1500 | { | ||
1501 | try | ||
1502 | { | ||
1503 | if (handler == m_agentHandlers[agent]) | ||
1504 | { | ||
1505 | m_agentHandlers.Remove(agent); | ||
1506 | return true; | ||
1507 | } | ||
1508 | } | ||
1509 | catch(KeyNotFoundException) | ||
1510 | { | ||
1511 | } | ||
1512 | |||
1513 | return false; | ||
1514 | } | ||
1515 | |||
1516 | public bool RemoveLLSDHandler(string path, LLSDMethod handler) | ||
1517 | { | ||
1518 | try | ||
1519 | { | ||
1520 | if (handler == m_llsdHandlers[path]) | ||
1521 | { | ||
1522 | m_llsdHandlers.Remove(path); | ||
1523 | return true; | ||
1524 | } | ||
1525 | } | ||
1526 | catch (KeyNotFoundException) | ||
1527 | { | ||
1528 | // This is an exception to prevent crashing because of invalid code | ||
1529 | } | ||
1530 | |||
1531 | return false; | ||
1532 | } | ||
1533 | |||
1534 | public string GetHTTP404(string host) | ||
1535 | { | ||
1536 | string file = Path.Combine(".", "http_404.html"); | ||
1537 | if (!File.Exists(file)) | ||
1538 | return getDefaultHTTP404(host); | ||
1539 | |||
1540 | StreamReader sr = File.OpenText(file); | ||
1541 | string result = sr.ReadToEnd(); | ||
1542 | sr.Close(); | ||
1543 | return result; | ||
1544 | } | ||
1545 | |||
1546 | public string GetHTTP500() | ||
1547 | { | ||
1548 | string file = Path.Combine(".", "http_500.html"); | ||
1549 | if (!File.Exists(file)) | ||
1550 | return getDefaultHTTP500(); | ||
1551 | |||
1552 | StreamReader sr = File.OpenText(file); | ||
1553 | string result = sr.ReadToEnd(); | ||
1554 | sr.Close(); | ||
1555 | return result; | ||
1556 | } | ||
1557 | |||
1558 | // Fallback HTTP responses in case the HTTP error response files don't exist | ||
1559 | private static string getDefaultHTTP404(string host) | ||
1560 | { | ||
1561 | return "<HTML><HEAD><TITLE>404 Page not found</TITLE><BODY><BR /><H1>Ooops!</H1><P>The page you requested has been obsconded with by knomes. Find hippos quick!</P><P>If you are trying to log-in, your link parameters should have: "-loginpage http://" + host + "/?method=login -loginuri http://" + host + "/" in your link </P></BODY></HTML>"; | ||
1562 | } | ||
1563 | |||
1564 | private static string getDefaultHTTP500() | ||
1565 | { | ||
1566 | return "<HTML><HEAD><TITLE>500 Internal Server Error</TITLE><BODY><BR /><H1>Ooops!</H1><P>The server you requested is overun by knomes! Find hippos quick!</P></BODY></HTML>"; | ||
1567 | } | ||
1568 | } | ||
1569 | |||
1570 | public class HttpServerContextObj | ||
1571 | { | ||
1572 | public IHttpClientContext context = null; | ||
1573 | public IHttpRequest req = null; | ||
1574 | public OSHttpRequest oreq = null; | ||
1575 | public OSHttpResponse oresp = null; | ||
1576 | |||
1577 | public HttpServerContextObj(IHttpClientContext contxt, IHttpRequest reqs) | ||
1578 | { | ||
1579 | context = contxt; | ||
1580 | req = reqs; | ||
1581 | } | ||
1582 | |||
1583 | public HttpServerContextObj(OSHttpRequest osreq, OSHttpResponse osresp) | ||
1584 | { | ||
1585 | oreq = osreq; | ||
1586 | oresp = osresp; | ||
1587 | } | ||
1588 | } | ||
1589 | |||
1590 | /// <summary> | ||
1591 | /// Relays HttpServer log messages to our own logging mechanism. | ||
1592 | /// </summary> | ||
1593 | /// There is also a UseTraceLogs line in this file that can be uncommented for more detailed log information | ||
1594 | public class HttpServerLogWriter : ILogWriter | ||
1595 | { | ||
1596 | //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
1597 | |||
1598 | public void Write(object source, LogPrio priority, string message) | ||
1599 | { | ||
1600 | /* | ||
1601 | switch (priority) | ||
1602 | { | ||
1603 | case HttpServer.LogPrio.Debug: | ||
1604 | m_log.DebugFormat("[{0}]: {1}", source.ToString(), message); | ||
1605 | break; | ||
1606 | case HttpServer.LogPrio.Error: | ||
1607 | m_log.ErrorFormat("[{0}]: {1}", source.ToString(), message); | ||
1608 | break; | ||
1609 | case HttpServer.LogPrio.Info: | ||
1610 | m_log.InfoFormat("[{0}]: {1}", source.ToString(), message); | ||
1611 | break; | ||
1612 | case HttpServer.LogPrio.Warning: | ||
1613 | m_log.WarnFormat("[{0}]: {1}", source.ToString(), message); | ||
1614 | break; | ||
1615 | case HttpServer.LogPrio.Fatal: | ||
1616 | m_log.ErrorFormat("[{0}]: FATAL! - {1}", source.ToString(), message); | ||
1617 | break; | ||
1618 | default: | ||
1619 | break; | ||
1620 | } | ||
1621 | */ | ||
1622 | |||
1623 | return; | ||
1624 | } | ||
1625 | } | ||
1626 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs new file mode 100644 index 0000000..9334972 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs | |||
@@ -0,0 +1,71 @@ | |||
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 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | public class BaseRequestHandler | ||
33 | { | ||
34 | public virtual string ContentType | ||
35 | { | ||
36 | get { return "application/xml"; } | ||
37 | } | ||
38 | |||
39 | private readonly string m_httpMethod; | ||
40 | |||
41 | public virtual string HttpMethod | ||
42 | { | ||
43 | get { return m_httpMethod; } | ||
44 | } | ||
45 | |||
46 | private readonly string m_path; | ||
47 | |||
48 | protected BaseRequestHandler(string httpMethod, string path) | ||
49 | { | ||
50 | m_httpMethod = httpMethod; | ||
51 | m_path = path; | ||
52 | } | ||
53 | |||
54 | public virtual string Path | ||
55 | { | ||
56 | get { return m_path; } | ||
57 | } | ||
58 | |||
59 | protected string GetParam(string path) | ||
60 | { | ||
61 | try | ||
62 | { | ||
63 | return path.Substring(m_path.Length); | ||
64 | } | ||
65 | catch (Exception) | ||
66 | { | ||
67 | return String.Empty; | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs new file mode 100644 index 0000000..734e3e4 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs | |||
@@ -0,0 +1,41 @@ | |||
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 | |||
28 | using System.IO; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler | ||
33 | { | ||
34 | public abstract byte[] Handle(string path, Stream request, | ||
35 | OSHttpRequest httpRequest, OSHttpResponse httpResponse); | ||
36 | |||
37 | protected BaseStreamHandler(string httpMethod, string path) : base(httpMethod, path) | ||
38 | { | ||
39 | } | ||
40 | } | ||
41 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs new file mode 100644 index 0000000..fe5bcbc --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs | |||
@@ -0,0 +1,73 @@ | |||
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 | |||
28 | using System.IO; | ||
29 | using System.Text; | ||
30 | |||
31 | namespace OpenSim.Framework.Servers.HttpServer | ||
32 | { | ||
33 | public delegate string BinaryMethod(byte[] data, string path, string param); | ||
34 | |||
35 | public class BinaryStreamHandler : BaseStreamHandler | ||
36 | { | ||
37 | private BinaryMethod m_method; | ||
38 | |||
39 | public override byte[] Handle(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
40 | { | ||
41 | byte[] data = ReadFully(request); | ||
42 | string param = GetParam(path); | ||
43 | string responseString = m_method(data, path, param); | ||
44 | |||
45 | return Encoding.UTF8.GetBytes(responseString); | ||
46 | } | ||
47 | |||
48 | public BinaryStreamHandler(string httpMethod, string path, BinaryMethod binaryMethod) | ||
49 | : base(httpMethod, path) | ||
50 | { | ||
51 | m_method = binaryMethod; | ||
52 | } | ||
53 | |||
54 | private static byte[] ReadFully(Stream stream) | ||
55 | { | ||
56 | byte[] buffer = new byte[32768]; | ||
57 | using (MemoryStream ms = new MemoryStream()) | ||
58 | { | ||
59 | while (true) | ||
60 | { | ||
61 | int read = stream.Read(buffer, 0, buffer.Length); | ||
62 | |||
63 | if (read <= 0) | ||
64 | { | ||
65 | return ms.ToArray(); | ||
66 | } | ||
67 | |||
68 | ms.Write(buffer, 0, read); | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/GenericHTTPMethod.cs b/OpenSim/Framework/Servers/HttpServer/GenericHTTPMethod.cs new file mode 100644 index 0000000..060761a --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/GenericHTTPMethod.cs | |||
@@ -0,0 +1,33 @@ | |||
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 | |||
28 | using System.Collections; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | public delegate Hashtable GenericHTTPMethod(Hashtable request); | ||
33 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpAgentHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpAgentHandler.cs new file mode 100644 index 0000000..60c8e6e --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpAgentHandler.cs | |||
@@ -0,0 +1,35 @@ | |||
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 | |||
28 | namespace OpenSim.Framework.Servers.HttpServer | ||
29 | { | ||
30 | public interface IHttpAgentHandler | ||
31 | { | ||
32 | bool Handle(OSHttpRequest req, OSHttpResponse resp); | ||
33 | bool Match(OSHttpRequest req, OSHttpResponse resp); | ||
34 | } | ||
35 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs new file mode 100644 index 0000000..6e3cc49 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs | |||
@@ -0,0 +1,126 @@ | |||
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 | |||
28 | using Nwc.XmlRpc; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | /// <summary> | ||
33 | /// Interface to OpenSimulator's built in HTTP server. Use this to register handlers (http, llsd, xmlrpc, etc.) | ||
34 | /// for given URLs. | ||
35 | /// </summary> | ||
36 | public interface IHttpServer | ||
37 | { | ||
38 | uint SSLPort { get; } | ||
39 | string SSLCommonName { get; } | ||
40 | |||
41 | uint Port { get; } | ||
42 | bool UseSSL { get; } | ||
43 | |||
44 | // Note that the agent string is provided simply to differentiate | ||
45 | // the handlers - it is NOT required to be an actual agent header | ||
46 | // value. | ||
47 | bool AddAgentHandler(string agent, IHttpAgentHandler handler); | ||
48 | |||
49 | /// <summary> | ||
50 | /// Add a handler for an HTTP request | ||
51 | /// </summary> | ||
52 | /// | ||
53 | /// This handler can actually be invoked either as | ||
54 | /// | ||
55 | /// http://<hostname>:<port>/?method=<methodName> | ||
56 | /// | ||
57 | /// or | ||
58 | /// | ||
59 | /// http://<hostname>:<port><method> | ||
60 | /// | ||
61 | /// if the method name starts with a slash. For example, AddHTTPHandler("/object/", ...) on a standalone region | ||
62 | /// server will register a handler that can be invoked with either | ||
63 | /// | ||
64 | /// http://localhost:9000/?method=/object/ | ||
65 | /// | ||
66 | /// or | ||
67 | /// | ||
68 | /// http://localhost:9000/object/ | ||
69 | /// | ||
70 | /// <param name="methodName"></param> | ||
71 | /// <param name="handler"></param> | ||
72 | /// <returns> | ||
73 | /// true if the handler was successfully registered, false if a handler with the same name already existed. | ||
74 | /// </returns> | ||
75 | bool AddHTTPHandler(string methodName, GenericHTTPMethod handler); | ||
76 | |||
77 | /// <summary> | ||
78 | /// Adds a LLSD handler, yay. | ||
79 | /// </summary> | ||
80 | /// <param name="path">/resource/ path</param> | ||
81 | /// <param name="handler">handle the LLSD response</param> | ||
82 | /// <returns></returns> | ||
83 | bool AddLLSDHandler(string path, LLSDMethod handler); | ||
84 | |||
85 | /// <summary> | ||
86 | /// Add a stream handler to the http server. If the handler already exists, then nothing happens. | ||
87 | /// </summary> | ||
88 | /// <param name="handler"></param> | ||
89 | void AddStreamHandler(IRequestHandler handler); | ||
90 | |||
91 | bool AddXmlRPCHandler(string method, XmlRpcMethod handler); | ||
92 | bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive); | ||
93 | |||
94 | /// <summary> | ||
95 | /// Gets the XML RPC handler for given method name | ||
96 | /// </summary> | ||
97 | /// <param name="method">Name of the method</param> | ||
98 | /// <returns>Returns null if not found</returns> | ||
99 | XmlRpcMethod GetXmlRPCHandler(string method); | ||
100 | |||
101 | bool SetDefaultLLSDHandler(DefaultLLSDMethod handler); | ||
102 | |||
103 | /// <summary> | ||
104 | /// Remove the agent if it is registered. | ||
105 | /// </summary> | ||
106 | /// <param name="agent"></param> | ||
107 | /// <param name="handler"></param> | ||
108 | /// <returns></returns> | ||
109 | bool RemoveAgentHandler(string agent, IHttpAgentHandler handler); | ||
110 | |||
111 | /// <summary> | ||
112 | /// Remove an HTTP handler | ||
113 | /// </summary> | ||
114 | /// <param name="httpMethod"></param> | ||
115 | /// <param name="path"></param> | ||
116 | void RemoveHTTPHandler(string httpMethod, string path); | ||
117 | |||
118 | bool RemoveLLSDHandler(string path, LLSDMethod handler); | ||
119 | |||
120 | void RemoveStreamHandler(string httpMethod, string path); | ||
121 | |||
122 | string GetHTTP404(string host); | ||
123 | |||
124 | string GetHTTP500(); | ||
125 | } | ||
126 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs new file mode 100644 index 0000000..6e27aba --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs | |||
@@ -0,0 +1,61 @@ | |||
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 | |||
28 | using System.Collections; | ||
29 | using System.IO; | ||
30 | |||
31 | namespace OpenSim.Framework.Servers.HttpServer | ||
32 | { | ||
33 | public interface IRequestHandler | ||
34 | { | ||
35 | // Return response content type | ||
36 | string ContentType { get; } | ||
37 | |||
38 | // Return required http method | ||
39 | string HttpMethod { get; } | ||
40 | |||
41 | // Return path | ||
42 | string Path { get; } | ||
43 | } | ||
44 | |||
45 | public interface IStreamedRequestHandler : IRequestHandler | ||
46 | { | ||
47 | // Handle request stream, return byte array | ||
48 | byte[] Handle(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse); | ||
49 | } | ||
50 | |||
51 | public interface IStreamHandler : IRequestHandler | ||
52 | { | ||
53 | // Handle request stream, return byte array | ||
54 | void Handle(string path, Stream request, Stream response, OSHttpRequest httpReqbuest, OSHttpResponse httpResponse); | ||
55 | } | ||
56 | |||
57 | public interface IGenericHTTPHandler : IRequestHandler | ||
58 | { | ||
59 | Hashtable Handle(string path, Hashtable request); | ||
60 | } | ||
61 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj new file mode 100644 index 0000000..e8700f1 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj | |||
@@ -0,0 +1,120 @@ | |||
1 | <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" > | ||
2 | <PropertyGroup> | ||
3 | <ProjectType>Local</ProjectType> | ||
4 | <ProductVersion>8.0.50727</ProductVersion> | ||
5 | <SchemaVersion>2.0</SchemaVersion> | ||
6 | <ProjectGuid>{8673D009-0000-0000-0000-000000000000}</ProjectGuid> | ||
7 | <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
8 | <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
9 | <ApplicationIcon></ApplicationIcon> | ||
10 | <AssemblyKeyContainerName> | ||
11 | </AssemblyKeyContainerName> | ||
12 | <AssemblyName>OpenSim.Framework.Servers.Interfaces</AssemblyName> | ||
13 | <DefaultClientScript>JScript</DefaultClientScript> | ||
14 | <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout> | ||
15 | <DefaultTargetSchema>IE50</DefaultTargetSchema> | ||
16 | <DelaySign>false</DelaySign> | ||
17 | <TargetFrameworkVersion>v2.0</TargetFrameworkVersion> | ||
18 | <OutputType>Library</OutputType> | ||
19 | <AppDesignerFolder></AppDesignerFolder> | ||
20 | <RootNamespace>OpenSim.Framework.Servers.Interfaces</RootNamespace> | ||
21 | <StartupObject></StartupObject> | ||
22 | <StartArguments></StartArguments> | ||
23 | <FileUpgradeFlags> | ||
24 | </FileUpgradeFlags> | ||
25 | </PropertyGroup> | ||
26 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
27 | <AllowUnsafeBlocks>False</AllowUnsafeBlocks> | ||
28 | <BaseAddress>285212672</BaseAddress> | ||
29 | <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> | ||
30 | <ConfigurationOverrideFile> | ||
31 | </ConfigurationOverrideFile> | ||
32 | <DefineConstants>TRACE;DEBUG</DefineConstants> | ||
33 | <DocumentationFile></DocumentationFile> | ||
34 | <DebugSymbols>True</DebugSymbols> | ||
35 | <FileAlignment>4096</FileAlignment> | ||
36 | <Optimize>False</Optimize> | ||
37 | <OutputPath>../../../../bin/</OutputPath> | ||
38 | <RegisterForComInterop>False</RegisterForComInterop> | ||
39 | <RemoveIntegerChecks>False</RemoveIntegerChecks> | ||
40 | <TreatWarningsAsErrors>False</TreatWarningsAsErrors> | ||
41 | <WarningLevel>4</WarningLevel> | ||
42 | <NoStdLib>False</NoStdLib> | ||
43 | <NoWarn></NoWarn> | ||
44 | </PropertyGroup> | ||
45 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
46 | <AllowUnsafeBlocks>False</AllowUnsafeBlocks> | ||
47 | <BaseAddress>285212672</BaseAddress> | ||
48 | <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> | ||
49 | <ConfigurationOverrideFile> | ||
50 | </ConfigurationOverrideFile> | ||
51 | <DefineConstants>TRACE</DefineConstants> | ||
52 | <DocumentationFile></DocumentationFile> | ||
53 | <DebugSymbols>False</DebugSymbols> | ||
54 | <FileAlignment>4096</FileAlignment> | ||
55 | <Optimize>True</Optimize> | ||
56 | <OutputPath>../../../../bin/</OutputPath> | ||
57 | <RegisterForComInterop>False</RegisterForComInterop> | ||
58 | <RemoveIntegerChecks>False</RemoveIntegerChecks> | ||
59 | <TreatWarningsAsErrors>False</TreatWarningsAsErrors> | ||
60 | <WarningLevel>4</WarningLevel> | ||
61 | <NoStdLib>False</NoStdLib> | ||
62 | <NoWarn></NoWarn> | ||
63 | </PropertyGroup> | ||
64 | <ItemGroup> | ||
65 | <Reference Include="HttpServer_OpenSim.dll" > | ||
66 | <Name>HttpServer_OpenSim.dll</Name> | ||
67 | <Private>False</Private> | ||
68 | </Reference> | ||
69 | <Reference Include="log4net.dll" > | ||
70 | <Name>log4net.dll</Name> | ||
71 | <Private>False</Private> | ||
72 | </Reference> | ||
73 | <Reference Include="OpenMetaverse.StructuredData.dll" > | ||
74 | <Name>OpenMetaverse.StructuredData.dll</Name> | ||
75 | <Private>False</Private> | ||
76 | </Reference> | ||
77 | <Reference Include="OpenMetaverseTypes.dll" > | ||
78 | <Name>OpenMetaverseTypes.dll</Name> | ||
79 | <Private>False</Private> | ||
80 | </Reference> | ||
81 | <Reference Include="System" > | ||
82 | <Name>System</Name> | ||
83 | <Private>False</Private> | ||
84 | </Reference> | ||
85 | <Reference Include="System.Xml" > | ||
86 | <Name>System.Xml</Name> | ||
87 | <Private>False</Private> | ||
88 | </Reference> | ||
89 | <Reference Include="XMLRPC.dll" > | ||
90 | <Name>XMLRPC.dll</Name> | ||
91 | <Private>False</Private> | ||
92 | </Reference> | ||
93 | </ItemGroup> | ||
94 | <ItemGroup> | ||
95 | <ProjectReference Include="../../../Data/OpenSim.Data.csproj"> | ||
96 | <Name>OpenSim.Data</Name> | ||
97 | <Project>{B75A430B-0000-0000-0000-000000000000}</Project> | ||
98 | <Package>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</Package> | ||
99 | <Private>False</Private> | ||
100 | </ProjectReference> | ||
101 | </ItemGroup> | ||
102 | <ItemGroup> | ||
103 | <Compile Include="IHttpAgentHandler.cs"> | ||
104 | <SubType>Code</SubType> | ||
105 | </Compile> | ||
106 | <Compile Include="IHttpServer.cs"> | ||
107 | <SubType>Code</SubType> | ||
108 | </Compile> | ||
109 | <Compile Include="IStreamHandler.cs"> | ||
110 | <SubType>Code</SubType> | ||
111 | </Compile> | ||
112 | </ItemGroup> | ||
113 | <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" /> | ||
114 | <PropertyGroup> | ||
115 | <PreBuildEvent> | ||
116 | </PreBuildEvent> | ||
117 | <PostBuildEvent> | ||
118 | </PostBuildEvent> | ||
119 | </PropertyGroup> | ||
120 | </Project> | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj.user b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj.user new file mode 100644 index 0000000..b73b33f --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj.user | |||
@@ -0,0 +1,12 @@ | |||
1 | <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
2 | <PropertyGroup> | ||
3 | <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
4 | <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
5 | <ReferencePath>/root/opensim-commit/bin/</ReferencePath> | ||
6 | <LastOpenVersion>8.0.50727</LastOpenVersion> | ||
7 | <ProjectView>ProjectFiles</ProjectView> | ||
8 | <ProjectTrust>0</ProjectTrust> | ||
9 | </PropertyGroup> | ||
10 | <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' " /> | ||
11 | <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> | ||
12 | </Project> | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.dll.build b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.dll.build new file mode 100644 index 0000000..102300f --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.dll.build | |||
@@ -0,0 +1,54 @@ | |||
1 | <?xml version="1.0" ?> | ||
2 | <project name="OpenSim.Framework.Servers.Interfaces" default="build"> | ||
3 | <target name="build"> | ||
4 | <echo message="Build Directory is ${project::get-base-directory()}/${build.dir}" /> | ||
5 | <mkdir dir="${project::get-base-directory()}/${build.dir}" /> | ||
6 | <copy todir="${project::get-base-directory()}/${build.dir}" flatten="true"> | ||
7 | <fileset basedir="${project::get-base-directory()}"> | ||
8 | </fileset> | ||
9 | </copy> | ||
10 | <copy todir="${project::get-base-directory()}/${build.dir}"> | ||
11 | <fileset basedir="."> | ||
12 | </fileset> | ||
13 | </copy> | ||
14 | <csc target="library" debug="${build.debug}" unsafe="False" warnaserror="False" define="TRACE;DEBUG" nostdlib="False" main="" output="${project::get-base-directory()}/${build.dir}/${project::get-name()}.dll"> | ||
15 | <resources prefix="OpenSim.Framework.Servers.Interfaces" dynamicprefix="true" > | ||
16 | </resources> | ||
17 | <sources failonempty="true"> | ||
18 | <include name="IHttpAgentHandler.cs" /> | ||
19 | <include name="IHttpServer.cs" /> | ||
20 | <include name="IStreamHandler.cs" /> | ||
21 | </sources> | ||
22 | <references basedir="${project::get-base-directory()}"> | ||
23 | <lib> | ||
24 | <include name="${project::get-base-directory()}" /> | ||
25 | <include name="${project::get-base-directory()}/../../../../bin" /> | ||
26 | </lib> | ||
27 | <include name="../../../../bin/HttpServer_OpenSim.dll" /> | ||
28 | <include name="../../../../bin/log4net.dll" /> | ||
29 | <include name="../../../../bin/OpenMetaverse.StructuredData.dll" /> | ||
30 | <include name="../../../../bin/OpenMetaverseTypes.dll" /> | ||
31 | <include name="OpenSim.Data.dll" /> | ||
32 | <include name="System.dll" /> | ||
33 | <include name="System.Xml.dll" /> | ||
34 | <include name="../../../../bin/XMLRPC.dll" /> | ||
35 | </references> | ||
36 | </csc> | ||
37 | <echo message="Copying from [${project::get-base-directory()}/${build.dir}/] to [${project::get-base-directory()}/../../../../bin/" /> | ||
38 | <mkdir dir="${project::get-base-directory()}/../../../../bin/"/> | ||
39 | <copy todir="${project::get-base-directory()}/../../../../bin/"> | ||
40 | <fileset basedir="${project::get-base-directory()}/${build.dir}/" > | ||
41 | <include name="*.dll"/> | ||
42 | <include name="*.exe"/> | ||
43 | <include name="*.mdb" if='${build.debug}'/> | ||
44 | <include name="*.pdb" if='${build.debug}'/> | ||
45 | </fileset> | ||
46 | </copy> | ||
47 | </target> | ||
48 | <target name="clean"> | ||
49 | <delete dir="${bin.dir}" failonerror="false" /> | ||
50 | <delete dir="${obj.dir}" failonerror="false" /> | ||
51 | </target> | ||
52 | <target name="doc" description="Creates documentation."> | ||
53 | </target> | ||
54 | </project> | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.mdp b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.mdp new file mode 100644 index 0000000..96f6b46 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.mdp | |||
@@ -0,0 +1,34 @@ | |||
1 | <Project name="OpenSim.Framework.Servers.Interfaces" description="" standardNamespace="OpenSim.Framework.Servers.Interfaces" newfilesearch="None" enableviewstate="True" fileversion="2.0" language="C#" clr-version="Net_2_0" ctype="DotNetProject"> | ||
2 | <Configurations active="Debug"> | ||
3 | <Configuration name="Debug" ctype="DotNetProjectConfiguration"> | ||
4 | <Output directory="./../../../../bin/" assembly="OpenSim.Framework.Servers.Interfaces" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" /> | ||
5 | <Build debugmode="True" target="Library" /> | ||
6 | <Execution runwithwarnings="True" consolepause="True" runtime="MsNet" clr-version="Net_2_0" /> | ||
7 | <CodeGeneration compiler="Csc" warninglevel="4" nowarn="" includedebuginformation="True" optimize="False" unsafecodeallowed="False" generateoverflowchecks="False" mainclass="" target="Library" definesymbols="TRACE;DEBUG" generatexmldocumentation="False" win32Icon="" ctype="CSharpCompilerParameters" /> | ||
8 | </Configuration> | ||
9 | <Configuration name="Release" ctype="DotNetProjectConfiguration"> | ||
10 | <Output directory="./../../../../bin/" assembly="OpenSim.Framework.Servers.Interfaces" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" /> | ||
11 | <Build debugmode="True" target="Library" /> | ||
12 | <Execution runwithwarnings="True" consolepause="True" runtime="MsNet" clr-version="Net_2_0" /> | ||
13 | <CodeGeneration compiler="Csc" warninglevel="4" nowarn="" includedebuginformation="False" optimize="True" unsafecodeallowed="False" generateoverflowchecks="False" mainclass="" target="Library" definesymbols="TRACE" generatexmldocumentation="False" win32Icon="" ctype="CSharpCompilerParameters" /> | ||
14 | </Configuration> | ||
15 | </Configurations> | ||
16 | <DeploymentInformation target="" script="" strategy="File"> | ||
17 | <excludeFiles /> | ||
18 | </DeploymentInformation> | ||
19 | <Contents> | ||
20 | <File name="./IHttpAgentHandler.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
21 | <File name="./IHttpServer.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
22 | <File name="./IStreamHandler.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
23 | </Contents> | ||
24 | <References> | ||
25 | <ProjectReference type="Assembly" refto="../../../../bin/HttpServer_OpenSim.dll" localcopy="False" /> | ||
26 | <ProjectReference type="Assembly" refto="../../../../bin/log4net.dll" localcopy="False" /> | ||
27 | <ProjectReference type="Assembly" refto="../../../../bin/OpenMetaverse.StructuredData.dll" localcopy="False" /> | ||
28 | <ProjectReference type="Assembly" refto="../../../../bin/OpenMetaverseTypes.dll" localcopy="False" /> | ||
29 | <ProjectReference type="Project" localcopy="False" refto="OpenSim.Data" /> | ||
30 | <ProjectReference type="Gac" localcopy="False" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> | ||
31 | <ProjectReference type="Gac" localcopy="False" refto="System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> | ||
32 | <ProjectReference type="Assembly" refto="../../../../bin/XMLRPC.dll" localcopy="False" /> | ||
33 | </References> | ||
34 | </Project> | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/LLSDMethod.cs b/OpenSim/Framework/Servers/HttpServer/LLSDMethod.cs new file mode 100644 index 0000000..d669182 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/LLSDMethod.cs | |||
@@ -0,0 +1,34 @@ | |||
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 | |||
28 | using OpenMetaverse.StructuredData; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | public delegate OSD LLSDMethod( string path, OSD request, string endpoint ); | ||
33 | public delegate OSD DefaultLLSDMethod(OSD request); | ||
34 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/LLSDMethodString.cs b/OpenSim/Framework/Servers/HttpServer/LLSDMethodString.cs new file mode 100644 index 0000000..61def78 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/LLSDMethodString.cs | |||
@@ -0,0 +1,33 @@ | |||
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 | |||
28 | using OpenMetaverse.StructuredData; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | public delegate OSD LLSDMethodString(OSD request, string thePath); | ||
33 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpHandler.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpHandler.cs new file mode 100644 index 0000000..f1788a0 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpHandler.cs | |||
@@ -0,0 +1,183 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Text.RegularExpressions; | ||
32 | |||
33 | namespace OpenSim.Framework.Servers.HttpServer | ||
34 | { | ||
35 | /// <sumary> | ||
36 | /// Any OSHttpHandler must return one of the following results: | ||
37 | /// <list type = "table"> | ||
38 | /// <listheader> | ||
39 | /// <term>result code</term> | ||
40 | /// <description>meaning</description> | ||
41 | /// </listheader> | ||
42 | /// <item> | ||
43 | /// <term>Pass</term> | ||
44 | /// <description>handler did not process the request</request> | ||
45 | /// </item> | ||
46 | /// <item> | ||
47 | /// <term>Done</term> | ||
48 | /// <description>handler did process the request, OSHttpServer | ||
49 | /// can clean up and close the request</request> | ||
50 | /// </item> | ||
51 | /// </list> | ||
52 | /// </summary> | ||
53 | public enum OSHttpHandlerResult | ||
54 | { | ||
55 | Unprocessed, | ||
56 | Pass, | ||
57 | Done, | ||
58 | } | ||
59 | |||
60 | /// <summary> | ||
61 | /// An OSHttpHandler that matches on the "content-type" header can | ||
62 | /// supply an OSHttpContentTypeChecker delegate which will be | ||
63 | /// invoked by the request matcher in OSHttpRequestPump. | ||
64 | /// </summary> | ||
65 | /// <returns>true if the handler is interested in the content; | ||
66 | /// false otherwise</returns> | ||
67 | public delegate bool OSHttpContentTypeChecker(OSHttpRequest req); | ||
68 | |||
69 | public abstract class OSHttpHandler | ||
70 | { | ||
71 | /// <summary> | ||
72 | /// Regular expression used to match against method of | ||
73 | /// the incoming HTTP request. If you want to match any string | ||
74 | /// either use '.*' or null. To match on the empty string use | ||
75 | /// '^$'. | ||
76 | /// </summary> | ||
77 | public virtual Regex Method | ||
78 | { | ||
79 | get { return _method; } | ||
80 | } | ||
81 | protected Regex _method; | ||
82 | |||
83 | /// <summary> | ||
84 | /// Regular expression used to match against path of the | ||
85 | /// incoming HTTP request. If you want to match any string | ||
86 | /// either use '.*' or null. To match on the emtpy string use | ||
87 | /// '^$'. | ||
88 | /// </summary> | ||
89 | public virtual Regex Path | ||
90 | { | ||
91 | get { return _path; } | ||
92 | } | ||
93 | protected Regex _path; | ||
94 | |||
95 | /// <summary> | ||
96 | /// Dictionary of (query name, regular expression) tuples, | ||
97 | /// allowing us to match on URI query fields. | ||
98 | /// </summary> | ||
99 | public virtual Dictionary<string, Regex> Query | ||
100 | { | ||
101 | get { return _query; } | ||
102 | } | ||
103 | protected Dictionary<string, Regex> _query; | ||
104 | |||
105 | /// <summary> | ||
106 | /// Dictionary of (header name, regular expression) tuples, | ||
107 | /// allowing us to match on HTTP header fields. | ||
108 | /// </summary> | ||
109 | public virtual Dictionary<string, Regex> Headers | ||
110 | { | ||
111 | get { return _headers; } | ||
112 | } | ||
113 | protected Dictionary<string, Regex> _headers; | ||
114 | |||
115 | /// <summary> | ||
116 | /// Dictionary of (header name, regular expression) tuples, | ||
117 | /// allowing us to match on HTTP header fields. | ||
118 | /// </summary> | ||
119 | /// <remarks> | ||
120 | /// This feature is currently not implemented as it requires | ||
121 | /// (trivial) changes to HttpServer.HttpListener that have not | ||
122 | /// been implemented. | ||
123 | /// </remarks> | ||
124 | public virtual Regex IPEndPointWhitelist | ||
125 | { | ||
126 | get { return _ipEndPointRegex; } | ||
127 | } | ||
128 | protected Regex _ipEndPointRegex; | ||
129 | |||
130 | |||
131 | /// <summary> | ||
132 | /// Base class constructor. | ||
133 | /// </summary> | ||
134 | /// <param name="path">null or path regex</param> | ||
135 | /// <param name="headers">null or dictionary of header | ||
136 | /// regexs</param> | ||
137 | /// <param name="contentType">null or content type | ||
138 | /// regex</param> | ||
139 | /// <param name="whitelist">null or IP address regex</param> | ||
140 | public OSHttpHandler(Regex method, Regex path, Dictionary<string, Regex> query, | ||
141 | Dictionary<string, Regex> headers, Regex contentType, Regex whitelist) | ||
142 | { | ||
143 | _method = method; | ||
144 | _path = path; | ||
145 | _query = query; | ||
146 | _ipEndPointRegex = whitelist; | ||
147 | |||
148 | if (null == _headers && null != contentType) | ||
149 | { | ||
150 | _headers = new Dictionary<string, Regex>(); | ||
151 | _headers.Add("content-type", contentType); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | |||
156 | /// <summary> | ||
157 | /// Process an incoming OSHttpRequest that matched our | ||
158 | /// requirements. | ||
159 | /// </summary> | ||
160 | /// <returns> | ||
161 | /// OSHttpHandlerResult.Pass if we are after all not | ||
162 | /// interested in the request; OSHttpHandlerResult.Done if we | ||
163 | /// did process the request. | ||
164 | /// </returns> | ||
165 | public abstract OSHttpHandlerResult Process(OSHttpRequest request); | ||
166 | |||
167 | public override string ToString() | ||
168 | { | ||
169 | StringWriter sw = new StringWriter(); | ||
170 | sw.WriteLine("{0}", base.ToString()); | ||
171 | sw.WriteLine(" method regex {0}", null == Method ? "null" : Method.ToString()); | ||
172 | sw.WriteLine(" path regex {0}", null == Path ? "null": Path.ToString()); | ||
173 | foreach (string tag in Headers.Keys) | ||
174 | { | ||
175 | sw.WriteLine(" header {0} : {1}", tag, Headers[tag].ToString()); | ||
176 | } | ||
177 | sw.WriteLine(" IP whitelist {0}", null == IPEndPointWhitelist ? "null" : IPEndPointWhitelist.ToString()); | ||
178 | sw.WriteLine(); | ||
179 | sw.Close(); | ||
180 | return sw.ToString(); | ||
181 | } | ||
182 | } | ||
183 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpHttpHandler.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpHttpHandler.cs new file mode 100644 index 0000000..09d6f52 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpHttpHandler.cs | |||
@@ -0,0 +1,145 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Net; | ||
33 | using System.Reflection; | ||
34 | using System.Text; | ||
35 | using System.Text.RegularExpressions; | ||
36 | using System.Xml; | ||
37 | using log4net; | ||
38 | using Nwc.XmlRpc; | ||
39 | |||
40 | namespace OpenSim.Framework.Servers.HttpServer | ||
41 | { | ||
42 | public delegate XmlRpcResponse OSHttpHttpProcessor(XmlRpcRequest request); | ||
43 | |||
44 | public class OSHttpHttpHandler: OSHttpHandler | ||
45 | { | ||
46 | private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | // contains handler for processing HTTP Request | ||
49 | private GenericHTTPMethod _handler; | ||
50 | |||
51 | /// <summary> | ||
52 | /// Instantiate an HTTP handler. | ||
53 | /// </summary> | ||
54 | /// <param name="handler">a GenericHTTPMethod</param> | ||
55 | /// <param name="method">null or HTTP method regex</param> | ||
56 | /// <param name="path">null or path regex</param> | ||
57 | /// <param name="query">null or dictionary with query regexs</param> | ||
58 | /// <param name="headers">null or dictionary with header | ||
59 | /// regexs</param> | ||
60 | /// <param name="whitelist">null or IP address whitelist</param> | ||
61 | public OSHttpHttpHandler(GenericHTTPMethod handler, Regex method, Regex path, | ||
62 | Dictionary<string, Regex> query, | ||
63 | Dictionary<string, Regex> headers, Regex whitelist) | ||
64 | : base(method, path, query, headers, new Regex(@"^text/html", RegexOptions.IgnoreCase | RegexOptions.Compiled), | ||
65 | whitelist) | ||
66 | { | ||
67 | _handler = handler; | ||
68 | } | ||
69 | |||
70 | /// <summary> | ||
71 | /// Instantiate an HTTP handler. | ||
72 | /// </summary> | ||
73 | /// <param name="handler">a GenericHTTPMethod</param> | ||
74 | public OSHttpHttpHandler(GenericHTTPMethod handler) | ||
75 | : this(handler, new Regex(@"^GET$", RegexOptions.IgnoreCase | RegexOptions.Compiled), null, null, null, null) | ||
76 | { | ||
77 | } | ||
78 | |||
79 | /// <summary> | ||
80 | /// Invoked by OSHttpRequestPump. | ||
81 | /// </summary> | ||
82 | public override OSHttpHandlerResult Process(OSHttpRequest request) | ||
83 | { | ||
84 | // call handler method | ||
85 | Hashtable responseData = _handler(request.Query); | ||
86 | |||
87 | int responseCode = (int)responseData["int_response_code"]; | ||
88 | string responseString = (string)responseData["str_response_string"]; | ||
89 | string contentType = (string)responseData["content_type"]; | ||
90 | |||
91 | //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this | ||
92 | //and should check for NullReferenceExceptions | ||
93 | |||
94 | if (string.IsNullOrEmpty(contentType)) | ||
95 | { | ||
96 | contentType = "text/html"; | ||
97 | } | ||
98 | |||
99 | OSHttpResponse response = new OSHttpResponse(request); | ||
100 | |||
101 | // We're forgoing the usual error status codes here because the client | ||
102 | // ignores anything but 200 and 301 | ||
103 | |||
104 | response.StatusCode = (int)OSHttpStatusCode.SuccessOk; | ||
105 | |||
106 | if (responseCode == (int)OSHttpStatusCode.RedirectMovedPermanently) | ||
107 | { | ||
108 | response.RedirectLocation = (string)responseData["str_redirect_location"]; | ||
109 | response.StatusCode = responseCode; | ||
110 | } | ||
111 | |||
112 | response.AddHeader("Content-type", contentType); | ||
113 | |||
114 | byte[] buffer; | ||
115 | |||
116 | if (!contentType.Contains("image")) | ||
117 | { | ||
118 | buffer = Encoding.UTF8.GetBytes(responseString); | ||
119 | } | ||
120 | else | ||
121 | { | ||
122 | buffer = Convert.FromBase64String(responseString); | ||
123 | } | ||
124 | |||
125 | response.SendChunked = false; | ||
126 | response.ContentLength64 = buffer.Length; | ||
127 | response.ContentEncoding = Encoding.UTF8; | ||
128 | |||
129 | try | ||
130 | { | ||
131 | response.Body.Write(buffer, 0, buffer.Length); | ||
132 | } | ||
133 | catch (Exception ex) | ||
134 | { | ||
135 | _log.ErrorFormat("[OSHttpHttpHandler]: Error: {0}", ex.Message); | ||
136 | } | ||
137 | finally | ||
138 | { | ||
139 | response.Send(); | ||
140 | } | ||
141 | |||
142 | return OSHttpHandlerResult.Done; | ||
143 | } | ||
144 | } | ||
145 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs new file mode 100644 index 0000000..0ca868c --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs | |||
@@ -0,0 +1,228 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Collections.Specialized; | ||
32 | using System.IO; | ||
33 | using System.Net; | ||
34 | using System.Reflection; | ||
35 | using System.Text; | ||
36 | using HttpServer; | ||
37 | using log4net; | ||
38 | |||
39 | namespace OpenSim.Framework.Servers.HttpServer | ||
40 | { | ||
41 | public class OSHttpRequest | ||
42 | { | ||
43 | private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
44 | |||
45 | protected IHttpRequest _request = null; | ||
46 | protected IHttpClientContext _context = null; | ||
47 | |||
48 | public string[] AcceptTypes | ||
49 | { | ||
50 | get { return _request.AcceptTypes; } | ||
51 | } | ||
52 | |||
53 | public Encoding ContentEncoding | ||
54 | { | ||
55 | get { return _contentEncoding; } | ||
56 | } | ||
57 | private Encoding _contentEncoding; | ||
58 | |||
59 | public long ContentLength | ||
60 | { | ||
61 | get { return _request.ContentLength; } | ||
62 | } | ||
63 | |||
64 | public long ContentLength64 | ||
65 | { | ||
66 | get { return ContentLength; } | ||
67 | } | ||
68 | |||
69 | public string ContentType | ||
70 | { | ||
71 | get { return _contentType; } | ||
72 | } | ||
73 | private string _contentType; | ||
74 | |||
75 | public bool HasEntityBody | ||
76 | { | ||
77 | get { return _request.ContentLength != 0; } | ||
78 | } | ||
79 | |||
80 | public NameValueCollection Headers | ||
81 | { | ||
82 | get { return _request.Headers; } | ||
83 | } | ||
84 | |||
85 | public string HttpMethod | ||
86 | { | ||
87 | get { return _request.Method; } | ||
88 | } | ||
89 | |||
90 | public Stream InputStream | ||
91 | { | ||
92 | get { return _request.Body; } | ||
93 | } | ||
94 | |||
95 | public bool IsSecured | ||
96 | { | ||
97 | get { return _context.Secured; } | ||
98 | } | ||
99 | |||
100 | public bool KeepAlive | ||
101 | { | ||
102 | get { return ConnectionType.KeepAlive == _request.Connection; } | ||
103 | } | ||
104 | |||
105 | public NameValueCollection QueryString | ||
106 | { | ||
107 | get { return _queryString; } | ||
108 | } | ||
109 | private NameValueCollection _queryString; | ||
110 | |||
111 | public Hashtable Query | ||
112 | { | ||
113 | get { return _query; } | ||
114 | } | ||
115 | private Hashtable _query; | ||
116 | |||
117 | public string RawUrl | ||
118 | { | ||
119 | get { return _request.Uri.AbsolutePath; } | ||
120 | } | ||
121 | |||
122 | public IPEndPoint RemoteIPEndPoint | ||
123 | { | ||
124 | get { return _remoteIPEndPoint; } | ||
125 | } | ||
126 | private IPEndPoint _remoteIPEndPoint; | ||
127 | |||
128 | public Uri Url | ||
129 | { | ||
130 | get { return _request.Uri; } | ||
131 | } | ||
132 | |||
133 | public string UserAgent | ||
134 | { | ||
135 | get { return _userAgent; } | ||
136 | } | ||
137 | private string _userAgent; | ||
138 | |||
139 | internal IHttpRequest IHttpRequest | ||
140 | { | ||
141 | get { return _request; } | ||
142 | } | ||
143 | |||
144 | internal IHttpClientContext IHttpClientContext | ||
145 | { | ||
146 | get { return _context; } | ||
147 | } | ||
148 | |||
149 | /// <summary> | ||
150 | /// Internal whiteboard for handlers to store temporary stuff | ||
151 | /// into. | ||
152 | /// </summary> | ||
153 | internal Dictionary<string, object> Whiteboard | ||
154 | { | ||
155 | get { return _whiteboard; } | ||
156 | } | ||
157 | private Dictionary<string, object> _whiteboard = new Dictionary<string, object>(); | ||
158 | |||
159 | |||
160 | public OSHttpRequest() {} | ||
161 | |||
162 | public OSHttpRequest(IHttpClientContext context, IHttpRequest req) | ||
163 | { | ||
164 | _request = req; | ||
165 | _context = context; | ||
166 | |||
167 | if (null != req.Headers["content-encoding"]) | ||
168 | _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]); | ||
169 | if (null != req.Headers["content-type"]) | ||
170 | _contentType = _request.Headers["content-type"]; | ||
171 | if (null != req.Headers["user-agent"]) | ||
172 | _userAgent = req.Headers["user-agent"]; | ||
173 | if (null != req.Headers["remote_addr"]) | ||
174 | { | ||
175 | try | ||
176 | { | ||
177 | IPAddress addr = IPAddress.Parse(req.Headers["remote_addr"]); | ||
178 | int port = Int32.Parse(req.Headers["remote_port"]); | ||
179 | _remoteIPEndPoint = new IPEndPoint(addr, port); | ||
180 | } | ||
181 | catch (FormatException) | ||
182 | { | ||
183 | _log.ErrorFormat("[OSHttpRequest]: format exception on addr/port {0}:{1}, ignoring", | ||
184 | req.Headers["remote_addr"], req.Headers["remote_port"]); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | _queryString = new NameValueCollection(); | ||
189 | _query = new Hashtable(); | ||
190 | try | ||
191 | { | ||
192 | foreach (HttpInputItem item in req.QueryString) | ||
193 | { | ||
194 | try | ||
195 | { | ||
196 | _queryString.Add(item.Name, item.Value); | ||
197 | _query[item.Name] = item.Value; | ||
198 | } | ||
199 | catch (InvalidCastException) | ||
200 | { | ||
201 | _log.DebugFormat("[OSHttpRequest]: error parsing {0} query item, skipping it", item.Name); | ||
202 | continue; | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | catch (Exception) | ||
207 | { | ||
208 | _log.ErrorFormat("[OSHttpRequest]: Error parsing querystring"); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | public override string ToString() | ||
213 | { | ||
214 | StringBuilder me = new StringBuilder(); | ||
215 | me.Append(String.Format("OSHttpRequest: {0} {1}\n", HttpMethod, RawUrl)); | ||
216 | foreach (string k in Headers.AllKeys) | ||
217 | { | ||
218 | me.Append(String.Format(" {0}: {1}\n", k, Headers[k])); | ||
219 | } | ||
220 | if (null != RemoteIPEndPoint) | ||
221 | { | ||
222 | me.Append(String.Format(" IP: {0}\n", RemoteIPEndPoint)); | ||
223 | } | ||
224 | |||
225 | return me.ToString(); | ||
226 | } | ||
227 | } | ||
228 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs new file mode 100644 index 0000000..893fa1b --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs | |||
@@ -0,0 +1,298 @@ | |||
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 | |||
28 | // #define DEBUGGING | ||
29 | |||
30 | using System; | ||
31 | using System.Collections.Generic; | ||
32 | using System.Collections.Specialized; | ||
33 | using System.Diagnostics; | ||
34 | using System.IO; | ||
35 | using System.Net; | ||
36 | using System.Reflection; | ||
37 | using System.Text.RegularExpressions; | ||
38 | using System.Threading; | ||
39 | using log4net; | ||
40 | using HttpServer; | ||
41 | |||
42 | namespace OpenSim.Framework.Servers.HttpServer | ||
43 | { | ||
44 | /// <summary> | ||
45 | /// An OSHttpRequestPump fetches incoming OSHttpRequest objects | ||
46 | /// from the OSHttpRequestQueue and feeds them to all subscribed | ||
47 | /// parties. Each OSHttpRequestPump encapsulates one thread to do | ||
48 | /// the work and there is a fixed number of pumps for each | ||
49 | /// OSHttpServer object. | ||
50 | /// </summary> | ||
51 | public class OSHttpRequestPump | ||
52 | { | ||
53 | private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
54 | |||
55 | protected OSHttpServer _server; | ||
56 | protected OSHttpRequestQueue _queue; | ||
57 | protected Thread _engine; | ||
58 | |||
59 | private int _id; | ||
60 | |||
61 | public string EngineID | ||
62 | { | ||
63 | get { return String.Format("{0} pump {1}", _server.EngineID, _id); } | ||
64 | } | ||
65 | |||
66 | public OSHttpRequestPump(OSHttpServer server, OSHttpRequestQueue queue, int id) | ||
67 | { | ||
68 | _server = server; | ||
69 | _queue = queue; | ||
70 | _id = id; | ||
71 | |||
72 | _engine = new Thread(new ThreadStart(Engine)); | ||
73 | _engine.Name = EngineID; | ||
74 | _engine.IsBackground = true; | ||
75 | _engine.Start(); | ||
76 | |||
77 | ThreadTracker.Add(_engine); | ||
78 | } | ||
79 | |||
80 | public static OSHttpRequestPump[] Pumps(OSHttpServer server, OSHttpRequestQueue queue, int poolSize) | ||
81 | { | ||
82 | OSHttpRequestPump[] pumps = new OSHttpRequestPump[poolSize]; | ||
83 | for (int i = 0; i < pumps.Length; i++) | ||
84 | { | ||
85 | pumps[i] = new OSHttpRequestPump(server, queue, i); | ||
86 | } | ||
87 | |||
88 | return pumps; | ||
89 | } | ||
90 | |||
91 | public void Start() | ||
92 | { | ||
93 | _engine = new Thread(new ThreadStart(Engine)); | ||
94 | _engine.Name = EngineID; | ||
95 | _engine.IsBackground = true; | ||
96 | _engine.Start(); | ||
97 | |||
98 | ThreadTracker.Add(_engine); | ||
99 | } | ||
100 | |||
101 | public void Engine() | ||
102 | { | ||
103 | OSHttpRequest req = null; | ||
104 | |||
105 | while (true) | ||
106 | { | ||
107 | try | ||
108 | { | ||
109 | // dequeue an OSHttpRequest from OSHttpServer's | ||
110 | // request queue | ||
111 | req = _queue.Dequeue(); | ||
112 | |||
113 | // get a copy of the list of registered handlers | ||
114 | List<OSHttpHandler> handlers = _server.OSHttpHandlers; | ||
115 | |||
116 | // prune list and have it sorted from most | ||
117 | // specific to least specific | ||
118 | handlers = MatchHandlers(req, handlers); | ||
119 | |||
120 | // process req: we try each handler in turn until | ||
121 | // we are either out of handlers or get back a | ||
122 | // Pass or Done | ||
123 | OSHttpHandlerResult rc = OSHttpHandlerResult.Unprocessed; | ||
124 | foreach (OSHttpHandler h in handlers) | ||
125 | { | ||
126 | rc = h.Process(req); | ||
127 | |||
128 | // Pass: handler did not process the request, | ||
129 | // try next handler | ||
130 | if (OSHttpHandlerResult.Pass == rc) continue; | ||
131 | |||
132 | // Handled: handler has processed the request | ||
133 | if (OSHttpHandlerResult.Done == rc) break; | ||
134 | |||
135 | // hmm, something went wrong | ||
136 | throw new Exception(String.Format("[{0}] got unexpected OSHttpHandlerResult {1}", EngineID, rc)); | ||
137 | } | ||
138 | |||
139 | if (OSHttpHandlerResult.Unprocessed == rc) | ||
140 | { | ||
141 | _log.InfoFormat("[{0}] OSHttpHandler: no handler registered for {1}", EngineID, req); | ||
142 | |||
143 | // set up response header | ||
144 | OSHttpResponse resp = new OSHttpResponse(req); | ||
145 | resp.StatusCode = (int)OSHttpStatusCode.ClientErrorNotFound; | ||
146 | resp.StatusDescription = String.Format("no handler on call for {0}", req); | ||
147 | resp.ContentType = "text/html"; | ||
148 | |||
149 | // add explanatory message | ||
150 | StreamWriter body = new StreamWriter(resp.Body); | ||
151 | body.WriteLine("<html>"); | ||
152 | body.WriteLine("<header><title>Ooops...</title><header>"); | ||
153 | body.WriteLine(String.Format("<body><p>{0}</p></body>", resp.StatusDescription)); | ||
154 | body.WriteLine("</html>"); | ||
155 | body.Flush(); | ||
156 | |||
157 | // and ship it back | ||
158 | resp.Send(); | ||
159 | } | ||
160 | } | ||
161 | catch (Exception e) | ||
162 | { | ||
163 | _log.DebugFormat("[{0}] OSHttpHandler problem: {1}", EngineID, e.ToString()); | ||
164 | _log.ErrorFormat("[{0}] OSHttpHandler problem: {1}", EngineID, e.Message); | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | |||
169 | protected List<OSHttpHandler> MatchHandlers(OSHttpRequest req, List<OSHttpHandler> handlers) | ||
170 | { | ||
171 | Dictionary<OSHttpHandler, int> scoredHandlers = new Dictionary<OSHttpHandler, int>(); | ||
172 | |||
173 | _log.DebugFormat("[{0}] MatchHandlers for {1}", EngineID, req); | ||
174 | foreach (OSHttpHandler h in handlers) | ||
175 | { | ||
176 | // initial anchor | ||
177 | scoredHandlers[h] = 0; | ||
178 | |||
179 | // first, check whether IPEndPointWhitelist applies | ||
180 | // and, if it does, whether client is on that white | ||
181 | // list. | ||
182 | if (null != h.IPEndPointWhitelist) | ||
183 | { | ||
184 | // TODO: following code requires code changes to | ||
185 | // HttpServer.HttpRequest to become functional | ||
186 | |||
187 | IPEndPoint remote = req.RemoteIPEndPoint; | ||
188 | if (null != remote) | ||
189 | { | ||
190 | Match epm = h.IPEndPointWhitelist.Match(remote.ToString()); | ||
191 | if (!epm.Success) | ||
192 | { | ||
193 | scoredHandlers.Remove(h); | ||
194 | continue; | ||
195 | } | ||
196 | } | ||
197 | } | ||
198 | |||
199 | if (null != h.Method) | ||
200 | { | ||
201 | Match m = h.Method.Match(req.HttpMethod); | ||
202 | if (!m.Success) | ||
203 | { | ||
204 | scoredHandlers.Remove(h); | ||
205 | continue; | ||
206 | } | ||
207 | scoredHandlers[h]++; | ||
208 | } | ||
209 | |||
210 | // whitelist ok, now check path | ||
211 | if (null != h.Path) | ||
212 | { | ||
213 | Match m = h.Path.Match(req.RawUrl); | ||
214 | if (!m.Success) | ||
215 | { | ||
216 | scoredHandlers.Remove(h); | ||
217 | continue; | ||
218 | } | ||
219 | scoredHandlers[h] += m.ToString().Length; | ||
220 | } | ||
221 | |||
222 | // whitelist & path ok, now check query string | ||
223 | if (null != h.Query) | ||
224 | { | ||
225 | int queriesMatch = MatchOnNameValueCollection(req.QueryString, h.Query); | ||
226 | if (0 == queriesMatch) | ||
227 | { | ||
228 | _log.DebugFormat("[{0}] request {1}", EngineID, req); | ||
229 | _log.DebugFormat("[{0}] dropping handler {1}", EngineID, h); | ||
230 | |||
231 | scoredHandlers.Remove(h); | ||
232 | continue; | ||
233 | } | ||
234 | scoredHandlers[h] += queriesMatch; | ||
235 | } | ||
236 | |||
237 | // whitelist, path, query string ok, now check headers | ||
238 | if (null != h.Headers) | ||
239 | { | ||
240 | int headersMatch = MatchOnNameValueCollection(req.Headers, h.Headers); | ||
241 | if (0 == headersMatch) | ||
242 | { | ||
243 | _log.DebugFormat("[{0}] request {1}", EngineID, req); | ||
244 | _log.DebugFormat("[{0}] dropping handler {1}", EngineID, h); | ||
245 | |||
246 | scoredHandlers.Remove(h); | ||
247 | continue; | ||
248 | } | ||
249 | scoredHandlers[h] += headersMatch; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | List<OSHttpHandler> matchingHandlers = new List<OSHttpHandler>(scoredHandlers.Keys); | ||
254 | matchingHandlers.Sort(delegate(OSHttpHandler x, OSHttpHandler y) | ||
255 | { | ||
256 | return scoredHandlers[x] - scoredHandlers[y]; | ||
257 | }); | ||
258 | LogDumpHandlerList(matchingHandlers); | ||
259 | return matchingHandlers; | ||
260 | } | ||
261 | |||
262 | protected int MatchOnNameValueCollection(NameValueCollection collection, Dictionary<string, Regex> regexs) | ||
263 | { | ||
264 | int matched = 0; | ||
265 | |||
266 | foreach (string tag in regexs.Keys) | ||
267 | { | ||
268 | // do we have a header "tag"? | ||
269 | if (null == collection[tag]) | ||
270 | { | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | // does the content of collection[tag] match | ||
275 | // the supplied regex? | ||
276 | Match cm = regexs[tag].Match(collection[tag]); | ||
277 | if (!cm.Success) | ||
278 | { | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | // ok: matches | ||
283 | matched++; | ||
284 | continue; | ||
285 | } | ||
286 | |||
287 | return matched; | ||
288 | } | ||
289 | |||
290 | [ConditionalAttribute("DEBUGGING")] | ||
291 | private void LogDumpHandlerList(List<OSHttpHandler> l) | ||
292 | { | ||
293 | _log.DebugFormat("[{0}] OSHttpHandlerList dump:", EngineID); | ||
294 | foreach (OSHttpHandler h in l) | ||
295 | _log.DebugFormat(" ", h.ToString()); | ||
296 | } | ||
297 | } | ||
298 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequestQueue.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestQueue.cs new file mode 100644 index 0000000..4e34b41 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestQueue.cs | |||
@@ -0,0 +1,68 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Threading; | ||
31 | using HttpServer; | ||
32 | |||
33 | namespace OpenSim.Framework.Servers.HttpServer | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// OSHttpRequestQueues are used to hand over incoming HTTP | ||
37 | /// requests to OSHttpRequestPump objects. | ||
38 | /// </summary> | ||
39 | public class OSHttpRequestQueue : Queue<OSHttpRequest> | ||
40 | { | ||
41 | private object _syncObject = new object(); | ||
42 | |||
43 | new public void Enqueue(OSHttpRequest req) | ||
44 | { | ||
45 | lock (_syncObject) | ||
46 | { | ||
47 | base.Enqueue(req); | ||
48 | Monitor.Pulse(_syncObject); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | new public OSHttpRequest Dequeue() | ||
53 | { | ||
54 | OSHttpRequest req = null; | ||
55 | |||
56 | lock (_syncObject) | ||
57 | { | ||
58 | while (null == req) | ||
59 | { | ||
60 | Monitor.Wait(_syncObject); | ||
61 | if (0 != this.Count) req = base.Dequeue(); | ||
62 | } | ||
63 | } | ||
64 | |||
65 | return req; | ||
66 | } | ||
67 | } | ||
68 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs new file mode 100644 index 0000000..210d122 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs | |||
@@ -0,0 +1,302 @@ | |||
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 | |||
28 | using System.IO; | ||
29 | using System.Net; | ||
30 | using System.Text; | ||
31 | using HttpServer; | ||
32 | |||
33 | namespace OpenSim.Framework.Servers.HttpServer | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// OSHttpResponse is the OpenSim representation of an HTTP | ||
37 | /// response. | ||
38 | /// </summary> | ||
39 | public class OSHttpResponse | ||
40 | { | ||
41 | /// <summary> | ||
42 | /// Content type property. | ||
43 | /// </summary> | ||
44 | /// <remarks> | ||
45 | /// Setting this property will also set IsContentTypeSet to | ||
46 | /// true. | ||
47 | /// </remarks> | ||
48 | public string ContentType | ||
49 | { | ||
50 | get | ||
51 | { | ||
52 | return _httpResponse.ContentType; | ||
53 | } | ||
54 | |||
55 | set | ||
56 | { | ||
57 | _httpResponse.ContentType = value; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | /// <summary> | ||
62 | /// Boolean property indicating whether the content type | ||
63 | /// property actively has been set. | ||
64 | /// </summary> | ||
65 | /// <remarks> | ||
66 | /// IsContentTypeSet will go away together with .NET base. | ||
67 | /// </remarks> | ||
68 | // public bool IsContentTypeSet | ||
69 | // { | ||
70 | // get { return _contentTypeSet; } | ||
71 | // } | ||
72 | // private bool _contentTypeSet; | ||
73 | |||
74 | |||
75 | /// <summary> | ||
76 | /// Length of the body content; 0 if there is no body. | ||
77 | /// </summary> | ||
78 | public long ContentLength | ||
79 | { | ||
80 | get | ||
81 | { | ||
82 | return _httpResponse.ContentLength; | ||
83 | } | ||
84 | |||
85 | set | ||
86 | { | ||
87 | _httpResponse.ContentLength = value; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | /// <summary> | ||
92 | /// Alias for ContentLength. | ||
93 | /// </summary> | ||
94 | public long ContentLength64 | ||
95 | { | ||
96 | get { return ContentLength; } | ||
97 | set { ContentLength = value; } | ||
98 | } | ||
99 | |||
100 | /// <summary> | ||
101 | /// Encoding of the body content. | ||
102 | /// </summary> | ||
103 | public Encoding ContentEncoding | ||
104 | { | ||
105 | get | ||
106 | { | ||
107 | return _httpResponse.Encoding; | ||
108 | } | ||
109 | |||
110 | set | ||
111 | { | ||
112 | _httpResponse.Encoding = value; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | public bool KeepAlive | ||
117 | { | ||
118 | get | ||
119 | { | ||
120 | return _httpResponse.Connection == ConnectionType.KeepAlive; | ||
121 | } | ||
122 | |||
123 | set | ||
124 | { | ||
125 | if (value) | ||
126 | _httpResponse.Connection = ConnectionType.KeepAlive; | ||
127 | else | ||
128 | _httpResponse.Connection = ConnectionType.Close; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | /// <summary> | ||
133 | /// Get or set the keep alive timeout property (default is | ||
134 | /// 20). Setting this to 0 also disables KeepAlive. Setting | ||
135 | /// this to something else but 0 also enable KeepAlive. | ||
136 | /// </summary> | ||
137 | public int KeepAliveTimeout | ||
138 | { | ||
139 | get | ||
140 | { | ||
141 | return _httpResponse.KeepAlive; | ||
142 | } | ||
143 | |||
144 | set | ||
145 | { | ||
146 | if (value == 0) | ||
147 | { | ||
148 | _httpResponse.Connection = ConnectionType.Close; | ||
149 | _httpResponse.KeepAlive = 0; | ||
150 | } | ||
151 | else | ||
152 | { | ||
153 | _httpResponse.Connection = ConnectionType.KeepAlive; | ||
154 | _httpResponse.KeepAlive = value; | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | |||
159 | /// <summary> | ||
160 | /// Return the output stream feeding the body. | ||
161 | /// </summary> | ||
162 | /// <remarks> | ||
163 | /// On its way out... | ||
164 | /// </remarks> | ||
165 | public Stream OutputStream | ||
166 | { | ||
167 | get | ||
168 | { | ||
169 | return _httpResponse.Body; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | public string ProtocolVersion | ||
174 | { | ||
175 | get | ||
176 | { | ||
177 | return _httpResponse.ProtocolVersion; | ||
178 | } | ||
179 | |||
180 | set | ||
181 | { | ||
182 | _httpResponse.ProtocolVersion = value; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | /// <summary> | ||
187 | /// Return the output stream feeding the body. | ||
188 | /// </summary> | ||
189 | public Stream Body | ||
190 | { | ||
191 | get | ||
192 | { | ||
193 | return _httpResponse.Body; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /// <summary> | ||
198 | /// Set a redirct location. | ||
199 | /// </summary> | ||
200 | public string RedirectLocation | ||
201 | { | ||
202 | // get { return _redirectLocation; } | ||
203 | set | ||
204 | { | ||
205 | _httpResponse.Redirect(value); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | |||
210 | /// <summary> | ||
211 | /// Chunk transfers. | ||
212 | /// </summary> | ||
213 | public bool SendChunked | ||
214 | { | ||
215 | get | ||
216 | { | ||
217 | return _httpResponse.Chunked; | ||
218 | } | ||
219 | |||
220 | set | ||
221 | { | ||
222 | _httpResponse.Chunked = value; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | /// <summary> | ||
227 | /// HTTP status code. | ||
228 | /// </summary> | ||
229 | public int StatusCode | ||
230 | { | ||
231 | get | ||
232 | { | ||
233 | return (int)_httpResponse.Status; | ||
234 | } | ||
235 | |||
236 | set | ||
237 | { | ||
238 | _httpResponse.Status = (HttpStatusCode)value; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | |||
243 | /// <summary> | ||
244 | /// HTTP status description. | ||
245 | /// </summary> | ||
246 | public string StatusDescription | ||
247 | { | ||
248 | get | ||
249 | { | ||
250 | return _httpResponse.Reason; | ||
251 | } | ||
252 | |||
253 | set | ||
254 | { | ||
255 | _httpResponse.Reason = value; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | |||
260 | protected IHttpResponse _httpResponse; | ||
261 | |||
262 | public OSHttpResponse() {} | ||
263 | |||
264 | public OSHttpResponse(IHttpResponse resp) | ||
265 | { | ||
266 | _httpResponse = resp; | ||
267 | } | ||
268 | |||
269 | /// <summary> | ||
270 | /// Instantiate an OSHttpResponse object from an OSHttpRequest | ||
271 | /// object. | ||
272 | /// </summary | ||
273 | /// <param name="req">Incoming OSHttpRequest to which we are | ||
274 | /// replying</param> | ||
275 | public OSHttpResponse(OSHttpRequest req) | ||
276 | { | ||
277 | _httpResponse = new HttpResponse(req.IHttpClientContext, req.IHttpRequest); | ||
278 | } | ||
279 | |||
280 | /// <summary> | ||
281 | /// Add a header field and content to the response. | ||
282 | /// </summary> | ||
283 | /// <param name="key">string containing the header field | ||
284 | /// name</param> | ||
285 | /// <param name="value">string containing the header field | ||
286 | /// value</param> | ||
287 | public void AddHeader(string key, string value) | ||
288 | { | ||
289 | _httpResponse.AddHeader(key, value); | ||
290 | } | ||
291 | |||
292 | /// <summary> | ||
293 | /// Send the response back to the remote client | ||
294 | /// </summary> | ||
295 | public void Send() | ||
296 | { | ||
297 | _httpResponse.Body.Flush(); | ||
298 | _httpResponse.Send(); | ||
299 | |||
300 | } | ||
301 | } | ||
302 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs new file mode 100644 index 0000000..e84f314 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs | |||
@@ -0,0 +1,210 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using System.Net.Sockets; | ||
32 | using System.Reflection; | ||
33 | using System.Text.RegularExpressions; | ||
34 | using System.Threading; | ||
35 | using System.Security.Cryptography.X509Certificates; | ||
36 | using log4net; | ||
37 | using HttpServer; | ||
38 | |||
39 | using HttpListener = HttpServer.HttpListener; | ||
40 | |||
41 | namespace OpenSim.Framework.Servers.HttpServer | ||
42 | { | ||
43 | /// <summary> | ||
44 | /// OSHttpServer provides an HTTP server bound to a specific | ||
45 | /// port. When instantiated with just address and port it uses | ||
46 | /// normal HTTP, when instantiated with address, port, and X509 | ||
47 | /// certificate, it uses HTTPS. | ||
48 | /// </summary> | ||
49 | public class OSHttpServer | ||
50 | { | ||
51 | private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
52 | |||
53 | private object _syncObject = new object(); | ||
54 | |||
55 | // underlying HttpServer.HttpListener | ||
56 | protected HttpListener _listener; | ||
57 | // underlying core/engine thread | ||
58 | protected Thread _engine; | ||
59 | |||
60 | // Queue containing (OS)HttpRequests | ||
61 | protected OSHttpRequestQueue _queue; | ||
62 | |||
63 | // OSHttpRequestPumps "pumping" incoming OSHttpRequests | ||
64 | // upwards | ||
65 | protected OSHttpRequestPump[] _pumps; | ||
66 | |||
67 | // thread identifier | ||
68 | protected string _engineId; | ||
69 | public string EngineID | ||
70 | { | ||
71 | get { return _engineId; } | ||
72 | } | ||
73 | |||
74 | /// <summary> | ||
75 | /// True if this is an HTTPS connection; false otherwise. | ||
76 | /// </summary> | ||
77 | protected bool _isSecure; | ||
78 | public bool IsSecure | ||
79 | { | ||
80 | get { return _isSecure; } | ||
81 | } | ||
82 | |||
83 | public int QueueSize | ||
84 | { | ||
85 | get { return _pumps.Length; } | ||
86 | } | ||
87 | |||
88 | /// <summary> | ||
89 | /// List of registered OSHttpHandlers for this OSHttpServer instance. | ||
90 | /// </summary> | ||
91 | protected List<OSHttpHandler> _httpHandlers = new List<OSHttpHandler>(); | ||
92 | public List<OSHttpHandler> OSHttpHandlers | ||
93 | { | ||
94 | get | ||
95 | { | ||
96 | lock (_httpHandlers) | ||
97 | { | ||
98 | return new List<OSHttpHandler>(_httpHandlers); | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | |||
104 | /// <summary> | ||
105 | /// Instantiate an HTTP server. | ||
106 | /// </summary> | ||
107 | public OSHttpServer(IPAddress address, int port, int poolSize) | ||
108 | { | ||
109 | _engineId = String.Format("OSHttpServer (HTTP:{0})", port); | ||
110 | _isSecure = false; | ||
111 | _log.DebugFormat("[{0}] HTTP server instantiated", EngineID); | ||
112 | |||
113 | _listener = new HttpListener(address, port); | ||
114 | _queue = new OSHttpRequestQueue(); | ||
115 | _pumps = OSHttpRequestPump.Pumps(this, _queue, poolSize); | ||
116 | } | ||
117 | |||
118 | /// <summary> | ||
119 | /// Instantiate an HTTPS server. | ||
120 | /// </summary> | ||
121 | public OSHttpServer(IPAddress address, int port, X509Certificate certificate, int poolSize) | ||
122 | { | ||
123 | _engineId = String.Format("OSHttpServer [HTTPS:{0}/ps:{1}]", port, poolSize); | ||
124 | _isSecure = true; | ||
125 | _log.DebugFormat("[{0}] HTTPS server instantiated", EngineID); | ||
126 | |||
127 | _listener = new HttpListener(address, port, certificate); | ||
128 | _queue = new OSHttpRequestQueue(); | ||
129 | _pumps = OSHttpRequestPump.Pumps(this, _queue, poolSize); | ||
130 | } | ||
131 | |||
132 | /// <summary> | ||
133 | /// Turn an HttpRequest into an OSHttpRequestItem and place it | ||
134 | /// in the queue. The OSHttpRequestQueue object will pulse the | ||
135 | /// next available idle pump. | ||
136 | /// </summary> | ||
137 | protected void OnHttpRequest(HttpClientContext client, HttpRequest request) | ||
138 | { | ||
139 | // turn request into OSHttpRequest | ||
140 | OSHttpRequest req = new OSHttpRequest(client, request); | ||
141 | |||
142 | // place OSHttpRequest into _httpRequestQueue, will | ||
143 | // trigger Pulse to idle waiting pumps | ||
144 | _queue.Enqueue(req); | ||
145 | } | ||
146 | |||
147 | /// <summary> | ||
148 | /// Start the HTTP server engine. | ||
149 | /// </summary> | ||
150 | public void Start() | ||
151 | { | ||
152 | _engine = new Thread(new ThreadStart(Engine)); | ||
153 | _engine.Name = _engineId; | ||
154 | _engine.IsBackground = true; | ||
155 | _engine.Start(); | ||
156 | |||
157 | ThreadTracker.Add(_engine); | ||
158 | |||
159 | // start the pumps... | ||
160 | for (int i = 0; i < _pumps.Length; i++) | ||
161 | _pumps[i].Start(); | ||
162 | } | ||
163 | |||
164 | public void Stop() | ||
165 | { | ||
166 | lock (_syncObject) Monitor.Pulse(_syncObject); | ||
167 | } | ||
168 | |||
169 | /// <summary> | ||
170 | /// Engine keeps the HTTP server running. | ||
171 | /// </summary> | ||
172 | private void Engine() | ||
173 | { | ||
174 | try { | ||
175 | _listener.RequestHandler += OnHttpRequest; | ||
176 | _listener.Start(QueueSize); | ||
177 | _log.InfoFormat("[{0}] HTTP server started", EngineID); | ||
178 | |||
179 | lock (_syncObject) Monitor.Wait(_syncObject); | ||
180 | } | ||
181 | catch (Exception ex) | ||
182 | { | ||
183 | _log.DebugFormat("[{0}] HTTP server startup failed: {1}", EngineID, ex.ToString()); | ||
184 | } | ||
185 | |||
186 | _log.InfoFormat("[{0}] HTTP server terminated", EngineID); | ||
187 | } | ||
188 | |||
189 | |||
190 | /// <summary> | ||
191 | /// Add an HTTP request handler. | ||
192 | /// </summary> | ||
193 | /// <param name="handler">OSHttpHandler delegate</param> | ||
194 | /// <param name="path">regex object for path matching</parm> | ||
195 | /// <param name="headers">dictionary containing header names | ||
196 | /// and regular expressions to match against header values</param> | ||
197 | public void AddHandler(OSHttpHandler handler) | ||
198 | { | ||
199 | lock (_httpHandlers) | ||
200 | { | ||
201 | if (_httpHandlers.Contains(handler)) | ||
202 | { | ||
203 | _log.DebugFormat("[OSHttpServer] attempt to add already existing handler ignored"); | ||
204 | return; | ||
205 | } | ||
206 | _httpHandlers.Add(handler); | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs new file mode 100644 index 0000000..2f1ca0f --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs | |||
@@ -0,0 +1,170 @@ | |||
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 | |||
28 | namespace OpenSim.Framework.Servers.HttpServer | ||
29 | { | ||
30 | /// <summary> | ||
31 | /// HTTP status codes (almost) as defined by W3C in | ||
32 | /// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html | ||
33 | /// </summary> | ||
34 | public enum OSHttpStatusCode: int | ||
35 | { | ||
36 | // 1xx Informational status codes providing a provisional | ||
37 | // response. | ||
38 | // 100 Tells client that to keep on going sending its request | ||
39 | InfoContinue = 100, | ||
40 | // 101 Server understands request, proposes to switch to different | ||
41 | // application level protocol | ||
42 | InfoSwitchingProtocols = 101, | ||
43 | |||
44 | |||
45 | // 2xx Success codes | ||
46 | // 200 Request successful | ||
47 | SuccessOk = 200, | ||
48 | // 201 Request successful, new resource created | ||
49 | SuccessOkCreated = 201, | ||
50 | // 202 Request accepted, processing still on-going | ||
51 | SuccessOkAccepted = 202, | ||
52 | // 203 Request successful, meta information not authoritative | ||
53 | SuccessOkNonAuthoritativeInformation = 203, | ||
54 | // 204 Request successful, nothing to return in the body | ||
55 | SuccessOkNoContent = 204, | ||
56 | // 205 Request successful, reset displayed content | ||
57 | SuccessOkResetContent = 205, | ||
58 | // 206 Request successful, partial content returned | ||
59 | SuccessOkPartialContent = 206, | ||
60 | |||
61 | // 3xx Redirect code: user agent needs to go somewhere else | ||
62 | // 300 Redirect: different presentation forms available, take | ||
63 | // a pick | ||
64 | RedirectMultipleChoices = 300, | ||
65 | // 301 Redirect: requested resource has moved and now lives | ||
66 | // somewhere else | ||
67 | RedirectMovedPermanently = 301, | ||
68 | // 302 Redirect: Resource temporarily somewhere else, location | ||
69 | // might change | ||
70 | RedirectFound = 302, | ||
71 | // 303 Redirect: See other as result of a POST | ||
72 | RedirectSeeOther = 303, | ||
73 | // 304 Redirect: Resource still the same as before | ||
74 | RedirectNotModified = 304, | ||
75 | // 305 Redirect: Resource must be accessed via proxy provided | ||
76 | // in location field | ||
77 | RedirectUseProxy = 305, | ||
78 | // 307 Redirect: Resource temporarily somewhere else, location | ||
79 | // might change | ||
80 | RedirectMovedTemporarily = 307, | ||
81 | |||
82 | // 4xx Client error: the client borked the request | ||
83 | // 400 Client error: bad request, server does not grok what | ||
84 | // the client wants | ||
85 | ClientErrorBadRequest = 400, | ||
86 | // 401 Client error: the client is not authorized, response | ||
87 | // provides WWW-Authenticate header field with a challenge | ||
88 | ClientErrorUnauthorized = 401, | ||
89 | // 402 Client error: Payment required (reserved for future use) | ||
90 | ClientErrorPaymentRequired = 402, | ||
91 | // 403 Client error: Server understood request, will not | ||
92 | // deliver, do not try again. | ||
93 | ClientErrorForbidden = 403, | ||
94 | // 404 Client error: Server cannot find anything matching the | ||
95 | // client request. | ||
96 | ClientErrorNotFound = 404, | ||
97 | // 405 Client error: The method specified by the client in the | ||
98 | // request is not allowed for the resource requested | ||
99 | ClientErrorMethodNotAllowed = 405, | ||
100 | // 406 Client error: Server cannot generate suitable response | ||
101 | // for the resource and content characteristics requested by | ||
102 | // the client | ||
103 | ClientErrorNotAcceptable = 406, | ||
104 | // 407 Client error: Similar to 401, Server requests that | ||
105 | // client authenticate itself with the proxy first | ||
106 | ClientErrorProxyAuthRequired = 407, | ||
107 | // 408 Client error: Server got impatient with client and | ||
108 | // decided to give up waiting for the client's request to | ||
109 | // arrive | ||
110 | ClientErrorRequestTimeout = 408, | ||
111 | // 409 Client error: Server could not fulfill the request for | ||
112 | // a resource as there is a conflict with the current state of | ||
113 | // the resource but thinks client can do something about this | ||
114 | ClientErrorConflict = 409, | ||
115 | // 410 Client error: The resource has moved somewhere else, | ||
116 | // but server has no clue where. | ||
117 | ClientErrorGone = 410, | ||
118 | // 411 Client error: The server is picky again and insists on | ||
119 | // having a content-length header field in the request | ||
120 | ClientErrorLengthRequired = 411, | ||
121 | // 412 Client error: one or more preconditions supplied in the | ||
122 | // client's request is false | ||
123 | ClientErrorPreconditionFailed = 412, | ||
124 | // 413 Client error: For fear of reflux, the server refuses to | ||
125 | // swallow that much data. | ||
126 | ClientErrorRequestEntityToLarge = 413, | ||
127 | // 414 Client error: The server considers the Request-URI to | ||
128 | // be indecently long and refuses to even look at it. | ||
129 | ClientErrorRequestURITooLong = 414, | ||
130 | // 415 Client error: The server has no clue about the media | ||
131 | // type requested by the client (contrary to popular belief it | ||
132 | // is not a warez server) | ||
133 | ClientErrorUnsupportedMediaType = 415, | ||
134 | // 416 Client error: The requested range cannot be delivered | ||
135 | // by the server. | ||
136 | ClientErrorRequestRangeNotSatisfiable = 416, | ||
137 | // 417 Client error: The expectations of the client as | ||
138 | // expressed in one or more Expect header fields cannot be met | ||
139 | // by the server, the server is awfully sorry about this. | ||
140 | ClientErrorExpectationFailed = 417, | ||
141 | // 499 Client error: Wildcard error. | ||
142 | ClientErrorJoker = 499, | ||
143 | |||
144 | // 5xx Server errors (rare) | ||
145 | // 500 Server error: something really strange and unexpected | ||
146 | // happened | ||
147 | ServerErrorInternalError = 500, | ||
148 | // 501 Server error: The server does not do the functionality | ||
149 | // required to carry out the client request. not at | ||
150 | // all. certainly not before breakfast. but also not after | ||
151 | // breakfast. | ||
152 | ServerErrorNotImplemented = 501, | ||
153 | // 502 Server error: While acting as a proxy or a gateway, the | ||
154 | // server got ditched by the upstream server and as a | ||
155 | // consequence regretfully cannot fulfill the client's request | ||
156 | ServerErrorBadGateway = 502, | ||
157 | // 503 Server error: Due to unforseen circumstances the server | ||
158 | // cannot currently deliver the service requested. Retry-After | ||
159 | // header might indicate when to try again. | ||
160 | ServerErrorServiceUnavailable = 503, | ||
161 | // 504 Server error: The server blames the upstream server | ||
162 | // for not being able to deliver the service requested and | ||
163 | // claims that the upstream server is too slow delivering the | ||
164 | // goods. | ||
165 | ServerErrorGatewayTimeout = 504, | ||
166 | // 505 Server error: The server does not support the HTTP | ||
167 | // version conveyed in the client's request. | ||
168 | ServerErrorHttpVersionNotSupported = 505, | ||
169 | } | ||
170 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpXmlRpcHandler.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpXmlRpcHandler.cs new file mode 100644 index 0000000..49bae48 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpXmlRpcHandler.cs | |||
@@ -0,0 +1,180 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Text; | ||
34 | using System.Text.RegularExpressions; | ||
35 | using System.Xml; | ||
36 | using log4net; | ||
37 | using Nwc.XmlRpc; | ||
38 | |||
39 | namespace OpenSim.Framework.Servers.HttpServer | ||
40 | { | ||
41 | public delegate XmlRpcResponse OSHttpXmlRpcProcessor(XmlRpcRequest request); | ||
42 | |||
43 | public class OSHttpXmlRpcHandler: OSHttpHandler | ||
44 | { | ||
45 | private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
46 | |||
47 | /// <summary> | ||
48 | /// XmlRpcMethodMatch tries to reify (deserialize) an incoming | ||
49 | /// XmlRpc request (and posts it to the "whiteboard") and | ||
50 | /// checks whether the method name is one we are interested | ||
51 | /// in. | ||
52 | /// </summary> | ||
53 | /// <returns>true if the handler is interested in the content; | ||
54 | /// false otherwise</returns> | ||
55 | protected bool XmlRpcMethodMatch(OSHttpRequest req) | ||
56 | { | ||
57 | XmlRpcRequest xmlRpcRequest = null; | ||
58 | |||
59 | // check whether req is already reified | ||
60 | // if not: reify (and post to whiteboard) | ||
61 | try | ||
62 | { | ||
63 | if (req.Whiteboard.ContainsKey("xmlrequest")) | ||
64 | { | ||
65 | xmlRpcRequest = req.Whiteboard["xmlrequest"] as XmlRpcRequest; | ||
66 | } | ||
67 | else | ||
68 | { | ||
69 | StreamReader body = new StreamReader(req.InputStream); | ||
70 | string requestBody = body.ReadToEnd(); | ||
71 | xmlRpcRequest = (XmlRpcRequest)(new XmlRpcRequestDeserializer()).Deserialize(requestBody); | ||
72 | req.Whiteboard["xmlrequest"] = xmlRpcRequest; | ||
73 | } | ||
74 | } | ||
75 | catch (XmlException) | ||
76 | { | ||
77 | _log.ErrorFormat("[OSHttpXmlRpcHandler] failed to deserialize XmlRpcRequest from {0}", req.ToString()); | ||
78 | return false; | ||
79 | } | ||
80 | |||
81 | // check against methodName | ||
82 | if ((null != xmlRpcRequest) | ||
83 | && !String.IsNullOrEmpty(xmlRpcRequest.MethodName) | ||
84 | && xmlRpcRequest.MethodName == _methodName) | ||
85 | { | ||
86 | _log.DebugFormat("[OSHttpXmlRpcHandler] located handler {0} for {1}", _methodName, req.ToString()); | ||
87 | return true; | ||
88 | } | ||
89 | |||
90 | return false; | ||
91 | } | ||
92 | |||
93 | // contains handler for processing XmlRpc Request | ||
94 | private XmlRpcMethod _handler; | ||
95 | |||
96 | // contains XmlRpc method name | ||
97 | private string _methodName; | ||
98 | |||
99 | |||
100 | /// <summary> | ||
101 | /// Instantiate an XmlRpc handler. | ||
102 | /// </summary> | ||
103 | /// <param name="handler">XmlRpcMethod | ||
104 | /// delegate</param> | ||
105 | /// <param name="methodName">XmlRpc method name</param> | ||
106 | /// <param name="path">XmlRpc path prefix (regular expression)</param> | ||
107 | /// <param name="headers">Dictionary with header names and | ||
108 | /// regular expressions to match content of headers</param> | ||
109 | /// <param name="whitelist">IP whitelist of remote end points | ||
110 | /// to accept (regular expression)</param> | ||
111 | /// <remarks> | ||
112 | /// Except for handler and methodName, all other parameters | ||
113 | /// can be null, in which case they are not taken into account | ||
114 | /// when the handler is being looked up. | ||
115 | /// </remarks> | ||
116 | public OSHttpXmlRpcHandler(XmlRpcMethod handler, string methodName, Regex path, | ||
117 | Dictionary<string, Regex> headers, Regex whitelist) | ||
118 | : base(new Regex(@"^POST$", RegexOptions.IgnoreCase | RegexOptions.Compiled), path, null, headers, | ||
119 | new Regex(@"^(text|application)/xml", RegexOptions.IgnoreCase | RegexOptions.Compiled), | ||
120 | whitelist) | ||
121 | { | ||
122 | _handler = handler; | ||
123 | _methodName = methodName; | ||
124 | } | ||
125 | |||
126 | |||
127 | /// <summary> | ||
128 | /// Instantiate an XmlRpc handler. | ||
129 | /// </summary> | ||
130 | /// <param name="handler">XmlRpcMethod | ||
131 | /// delegate</param> | ||
132 | /// <param name="methodName">XmlRpc method name</param> | ||
133 | public OSHttpXmlRpcHandler(XmlRpcMethod handler, string methodName) | ||
134 | : this(handler, methodName, null, null, null) | ||
135 | { | ||
136 | } | ||
137 | |||
138 | |||
139 | /// <summary> | ||
140 | /// Invoked by OSHttpRequestPump. | ||
141 | /// </summary> | ||
142 | public override OSHttpHandlerResult Process(OSHttpRequest request) | ||
143 | { | ||
144 | XmlRpcResponse xmlRpcResponse; | ||
145 | string responseString; | ||
146 | |||
147 | // check whether we are interested in this request | ||
148 | if (!XmlRpcMethodMatch(request)) return OSHttpHandlerResult.Pass; | ||
149 | |||
150 | |||
151 | OSHttpResponse resp = new OSHttpResponse(request); | ||
152 | try | ||
153 | { | ||
154 | // reified XmlRpcRequest must still be on the whiteboard | ||
155 | XmlRpcRequest xmlRpcRequest = request.Whiteboard["xmlrequest"] as XmlRpcRequest; | ||
156 | xmlRpcResponse = _handler(xmlRpcRequest); | ||
157 | responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); | ||
158 | |||
159 | resp.ContentType = "text/xml"; | ||
160 | byte[] buffer = Encoding.UTF8.GetBytes(responseString); | ||
161 | |||
162 | resp.SendChunked = false; | ||
163 | resp.ContentLength = buffer.Length; | ||
164 | resp.ContentEncoding = Encoding.UTF8; | ||
165 | |||
166 | resp.Body.Write(buffer, 0, buffer.Length); | ||
167 | resp.Body.Flush(); | ||
168 | |||
169 | resp.Send(); | ||
170 | |||
171 | } | ||
172 | catch (Exception ex) | ||
173 | { | ||
174 | _log.WarnFormat("[OSHttpXmlRpcHandler]: Error: {0}", ex.Message); | ||
175 | return OSHttpHandlerResult.Pass; | ||
176 | } | ||
177 | return OSHttpHandlerResult.Done; | ||
178 | } | ||
179 | } | ||
180 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj new file mode 100644 index 0000000..097a251 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj | |||
@@ -0,0 +1,180 @@ | |||
1 | <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" > | ||
2 | <PropertyGroup> | ||
3 | <ProjectType>Local</ProjectType> | ||
4 | <ProductVersion>8.0.50727</ProductVersion> | ||
5 | <SchemaVersion>2.0</SchemaVersion> | ||
6 | <ProjectGuid>{1CBD339A-0000-0000-0000-000000000000}</ProjectGuid> | ||
7 | <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
8 | <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
9 | <ApplicationIcon></ApplicationIcon> | ||
10 | <AssemblyKeyContainerName> | ||
11 | </AssemblyKeyContainerName> | ||
12 | <AssemblyName>OpenSim.Framework.Servers.HttpServer</AssemblyName> | ||
13 | <DefaultClientScript>JScript</DefaultClientScript> | ||
14 | <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout> | ||
15 | <DefaultTargetSchema>IE50</DefaultTargetSchema> | ||
16 | <DelaySign>false</DelaySign> | ||
17 | <TargetFrameworkVersion>v2.0</TargetFrameworkVersion> | ||
18 | <OutputType>Library</OutputType> | ||
19 | <AppDesignerFolder></AppDesignerFolder> | ||
20 | <RootNamespace>OpenSim.Framework.Servers.HttpServer</RootNamespace> | ||
21 | <StartupObject></StartupObject> | ||
22 | <StartArguments></StartArguments> | ||
23 | <FileUpgradeFlags> | ||
24 | </FileUpgradeFlags> | ||
25 | </PropertyGroup> | ||
26 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
27 | <AllowUnsafeBlocks>False</AllowUnsafeBlocks> | ||
28 | <BaseAddress>285212672</BaseAddress> | ||
29 | <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> | ||
30 | <ConfigurationOverrideFile> | ||
31 | </ConfigurationOverrideFile> | ||
32 | <DefineConstants>TRACE;DEBUG</DefineConstants> | ||
33 | <DocumentationFile></DocumentationFile> | ||
34 | <DebugSymbols>True</DebugSymbols> | ||
35 | <FileAlignment>4096</FileAlignment> | ||
36 | <Optimize>False</Optimize> | ||
37 | <OutputPath>../../../../bin/</OutputPath> | ||
38 | <RegisterForComInterop>False</RegisterForComInterop> | ||
39 | <RemoveIntegerChecks>False</RemoveIntegerChecks> | ||
40 | <TreatWarningsAsErrors>False</TreatWarningsAsErrors> | ||
41 | <WarningLevel>4</WarningLevel> | ||
42 | <NoStdLib>False</NoStdLib> | ||
43 | <NoWarn></NoWarn> | ||
44 | </PropertyGroup> | ||
45 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
46 | <AllowUnsafeBlocks>False</AllowUnsafeBlocks> | ||
47 | <BaseAddress>285212672</BaseAddress> | ||
48 | <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> | ||
49 | <ConfigurationOverrideFile> | ||
50 | </ConfigurationOverrideFile> | ||
51 | <DefineConstants>TRACE</DefineConstants> | ||
52 | <DocumentationFile></DocumentationFile> | ||
53 | <DebugSymbols>False</DebugSymbols> | ||
54 | <FileAlignment>4096</FileAlignment> | ||
55 | <Optimize>True</Optimize> | ||
56 | <OutputPath>../../../../bin/</OutputPath> | ||
57 | <RegisterForComInterop>False</RegisterForComInterop> | ||
58 | <RemoveIntegerChecks>False</RemoveIntegerChecks> | ||
59 | <TreatWarningsAsErrors>False</TreatWarningsAsErrors> | ||
60 | <WarningLevel>4</WarningLevel> | ||
61 | <NoStdLib>False</NoStdLib> | ||
62 | <NoWarn></NoWarn> | ||
63 | </PropertyGroup> | ||
64 | <ItemGroup> | ||
65 | <Reference Include="HttpServer_OpenSim.dll" > | ||
66 | <Name>HttpServer_OpenSim.dll</Name> | ||
67 | <Private>False</Private> | ||
68 | </Reference> | ||
69 | <Reference Include="log4net.dll" > | ||
70 | <Name>log4net.dll</Name> | ||
71 | <Private>False</Private> | ||
72 | </Reference> | ||
73 | <Reference Include="OpenMetaverse.StructuredData.dll" > | ||
74 | <Name>OpenMetaverse.StructuredData.dll</Name> | ||
75 | <Private>False</Private> | ||
76 | </Reference> | ||
77 | <Reference Include="OpenMetaverseTypes.dll" > | ||
78 | <Name>OpenMetaverseTypes.dll</Name> | ||
79 | <Private>False</Private> | ||
80 | </Reference> | ||
81 | <Reference Include="System" > | ||
82 | <Name>System</Name> | ||
83 | <Private>False</Private> | ||
84 | </Reference> | ||
85 | <Reference Include="System.Xml" > | ||
86 | <Name>System.Xml</Name> | ||
87 | <Private>False</Private> | ||
88 | </Reference> | ||
89 | <Reference Include="XMLRPC.dll" > | ||
90 | <Name>XMLRPC.dll</Name> | ||
91 | <Private>False</Private> | ||
92 | </Reference> | ||
93 | </ItemGroup> | ||
94 | <ItemGroup> | ||
95 | <ProjectReference Include="../../../Data/OpenSim.Data.csproj"> | ||
96 | <Name>OpenSim.Data</Name> | ||
97 | <Project>{B75A430B-0000-0000-0000-000000000000}</Project> | ||
98 | <Package>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</Package> | ||
99 | <Private>False</Private> | ||
100 | </ProjectReference> | ||
101 | </ItemGroup> | ||
102 | <ItemGroup> | ||
103 | <Compile Include="BaseHTTPHandler.cs"> | ||
104 | <SubType>Code</SubType> | ||
105 | </Compile> | ||
106 | <Compile Include="BaseHttpServer.cs"> | ||
107 | <SubType>Code</SubType> | ||
108 | </Compile> | ||
109 | <Compile Include="BaseRequestHandler.cs"> | ||
110 | <SubType>Code</SubType> | ||
111 | </Compile> | ||
112 | <Compile Include="BaseStreamHandler.cs"> | ||
113 | <SubType>Code</SubType> | ||
114 | </Compile> | ||
115 | <Compile Include="BinaryStreamHandler.cs"> | ||
116 | <SubType>Code</SubType> | ||
117 | </Compile> | ||
118 | <Compile Include="GenericHTTPMethod.cs"> | ||
119 | <SubType>Code</SubType> | ||
120 | </Compile> | ||
121 | <Compile Include="LLSDMethod.cs"> | ||
122 | <SubType>Code</SubType> | ||
123 | </Compile> | ||
124 | <Compile Include="LLSDMethodString.cs"> | ||
125 | <SubType>Code</SubType> | ||
126 | </Compile> | ||
127 | <Compile Include="OSHttpRequest.cs"> | ||
128 | <SubType>Code</SubType> | ||
129 | </Compile> | ||
130 | <Compile Include="OSHttpResponse.cs"> | ||
131 | <SubType>Code</SubType> | ||
132 | </Compile> | ||
133 | <Compile Include="OSHttpStatusCodes.cs"> | ||
134 | <SubType>Code</SubType> | ||
135 | </Compile> | ||
136 | <Compile Include="RestDeserialiseHandler.cs"> | ||
137 | <SubType>Code</SubType> | ||
138 | </Compile> | ||
139 | <Compile Include="RestHTTPHandler.cs"> | ||
140 | <SubType>Code</SubType> | ||
141 | </Compile> | ||
142 | <Compile Include="RestMethod.cs"> | ||
143 | <SubType>Code</SubType> | ||
144 | </Compile> | ||
145 | <Compile Include="RestObjectPoster.cs"> | ||
146 | <SubType>Code</SubType> | ||
147 | </Compile> | ||
148 | <Compile Include="RestObjectPosterResponse.cs"> | ||
149 | <SubType>Code</SubType> | ||
150 | </Compile> | ||
151 | <Compile Include="RestSessionService.cs"> | ||
152 | <SubType>Code</SubType> | ||
153 | </Compile> | ||
154 | <Compile Include="RestStreamHandler.cs"> | ||
155 | <SubType>Code</SubType> | ||
156 | </Compile> | ||
157 | <Compile Include="SynchronousRestObjectPoster.cs"> | ||
158 | <SubType>Code</SubType> | ||
159 | </Compile> | ||
160 | <Compile Include="XmlRpcMethod.cs"> | ||
161 | <SubType>Code</SubType> | ||
162 | </Compile> | ||
163 | <Compile Include="Interfaces/IHttpAgentHandler.cs"> | ||
164 | <SubType>Code</SubType> | ||
165 | </Compile> | ||
166 | <Compile Include="Interfaces/IHttpServer.cs"> | ||
167 | <SubType>Code</SubType> | ||
168 | </Compile> | ||
169 | <Compile Include="Interfaces/IStreamHandler.cs"> | ||
170 | <SubType>Code</SubType> | ||
171 | </Compile> | ||
172 | </ItemGroup> | ||
173 | <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" /> | ||
174 | <PropertyGroup> | ||
175 | <PreBuildEvent> | ||
176 | </PreBuildEvent> | ||
177 | <PostBuildEvent> | ||
178 | </PostBuildEvent> | ||
179 | </PropertyGroup> | ||
180 | </Project> | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj.user b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj.user new file mode 100644 index 0000000..b73b33f --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj.user | |||
@@ -0,0 +1,12 @@ | |||
1 | <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
2 | <PropertyGroup> | ||
3 | <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
4 | <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
5 | <ReferencePath>/root/opensim-commit/bin/</ReferencePath> | ||
6 | <LastOpenVersion>8.0.50727</LastOpenVersion> | ||
7 | <ProjectView>ProjectFiles</ProjectView> | ||
8 | <ProjectTrust>0</ProjectTrust> | ||
9 | </PropertyGroup> | ||
10 | <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' " /> | ||
11 | <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> | ||
12 | </Project> | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.dll.build b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.dll.build new file mode 100644 index 0000000..f814703 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.dll.build | |||
@@ -0,0 +1,74 @@ | |||
1 | <?xml version="1.0" ?> | ||
2 | <project name="OpenSim.Framework.Servers.HttpServer" default="build"> | ||
3 | <target name="build"> | ||
4 | <echo message="Build Directory is ${project::get-base-directory()}/${build.dir}" /> | ||
5 | <mkdir dir="${project::get-base-directory()}/${build.dir}" /> | ||
6 | <copy todir="${project::get-base-directory()}/${build.dir}" flatten="true"> | ||
7 | <fileset basedir="${project::get-base-directory()}"> | ||
8 | </fileset> | ||
9 | </copy> | ||
10 | <copy todir="${project::get-base-directory()}/${build.dir}"> | ||
11 | <fileset basedir="."> | ||
12 | </fileset> | ||
13 | </copy> | ||
14 | <csc target="library" debug="${build.debug}" unsafe="False" warnaserror="False" define="TRACE;DEBUG" nostdlib="False" main="" output="${project::get-base-directory()}/${build.dir}/${project::get-name()}.dll"> | ||
15 | <resources prefix="OpenSim.Framework.Servers.HttpServer" dynamicprefix="true" > | ||
16 | </resources> | ||
17 | <sources failonempty="true"> | ||
18 | <include name="BaseHTTPHandler.cs" /> | ||
19 | <include name="BaseHttpServer.cs" /> | ||
20 | <include name="BaseRequestHandler.cs" /> | ||
21 | <include name="BaseStreamHandler.cs" /> | ||
22 | <include name="BinaryStreamHandler.cs" /> | ||
23 | <include name="GenericHTTPMethod.cs" /> | ||
24 | <include name="LLSDMethod.cs" /> | ||
25 | <include name="LLSDMethodString.cs" /> | ||
26 | <include name="OSHttpRequest.cs" /> | ||
27 | <include name="OSHttpResponse.cs" /> | ||
28 | <include name="OSHttpStatusCodes.cs" /> | ||
29 | <include name="RestDeserialiseHandler.cs" /> | ||
30 | <include name="RestHTTPHandler.cs" /> | ||
31 | <include name="RestMethod.cs" /> | ||
32 | <include name="RestObjectPoster.cs" /> | ||
33 | <include name="RestObjectPosterResponse.cs" /> | ||
34 | <include name="RestSessionService.cs" /> | ||
35 | <include name="RestStreamHandler.cs" /> | ||
36 | <include name="SynchronousRestObjectPoster.cs" /> | ||
37 | <include name="XmlRpcMethod.cs" /> | ||
38 | <include name="Interfaces/IHttpAgentHandler.cs" /> | ||
39 | <include name="Interfaces/IHttpServer.cs" /> | ||
40 | <include name="Interfaces/IStreamHandler.cs" /> | ||
41 | </sources> | ||
42 | <references basedir="${project::get-base-directory()}"> | ||
43 | <lib> | ||
44 | <include name="${project::get-base-directory()}" /> | ||
45 | <include name="${project::get-base-directory()}/../../../../bin" /> | ||
46 | </lib> | ||
47 | <include name="../../../../bin/HttpServer_OpenSim.dll" /> | ||
48 | <include name="../../../../bin/log4net.dll" /> | ||
49 | <include name="../../../../bin/OpenMetaverse.StructuredData.dll" /> | ||
50 | <include name="../../../../bin/OpenMetaverseTypes.dll" /> | ||
51 | <include name="OpenSim.Data.dll" /> | ||
52 | <include name="System.dll" /> | ||
53 | <include name="System.Xml.dll" /> | ||
54 | <include name="../../../../bin/XMLRPC.dll" /> | ||
55 | </references> | ||
56 | </csc> | ||
57 | <echo message="Copying from [${project::get-base-directory()}/${build.dir}/] to [${project::get-base-directory()}/../../../../bin/" /> | ||
58 | <mkdir dir="${project::get-base-directory()}/../../../../bin/"/> | ||
59 | <copy todir="${project::get-base-directory()}/../../../../bin/"> | ||
60 | <fileset basedir="${project::get-base-directory()}/${build.dir}/" > | ||
61 | <include name="*.dll"/> | ||
62 | <include name="*.exe"/> | ||
63 | <include name="*.mdb" if='${build.debug}'/> | ||
64 | <include name="*.pdb" if='${build.debug}'/> | ||
65 | </fileset> | ||
66 | </copy> | ||
67 | </target> | ||
68 | <target name="clean"> | ||
69 | <delete dir="${bin.dir}" failonerror="false" /> | ||
70 | <delete dir="${obj.dir}" failonerror="false" /> | ||
71 | </target> | ||
72 | <target name="doc" description="Creates documentation."> | ||
73 | </target> | ||
74 | </project> | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.mdp b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.mdp new file mode 100644 index 0000000..7556d59 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.mdp | |||
@@ -0,0 +1,54 @@ | |||
1 | <Project name="OpenSim.Framework.Servers.HttpServer" description="" standardNamespace="OpenSim.Framework.Servers.HttpServer" newfilesearch="None" enableviewstate="True" fileversion="2.0" language="C#" clr-version="Net_2_0" ctype="DotNetProject"> | ||
2 | <Configurations active="Debug"> | ||
3 | <Configuration name="Debug" ctype="DotNetProjectConfiguration"> | ||
4 | <Output directory="./../../../../bin/" assembly="OpenSim.Framework.Servers.HttpServer" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" /> | ||
5 | <Build debugmode="True" target="Library" /> | ||
6 | <Execution runwithwarnings="True" consolepause="True" runtime="MsNet" clr-version="Net_2_0" /> | ||
7 | <CodeGeneration compiler="Csc" warninglevel="4" nowarn="" includedebuginformation="True" optimize="False" unsafecodeallowed="False" generateoverflowchecks="False" mainclass="" target="Library" definesymbols="TRACE;DEBUG" generatexmldocumentation="False" win32Icon="" ctype="CSharpCompilerParameters" /> | ||
8 | </Configuration> | ||
9 | <Configuration name="Release" ctype="DotNetProjectConfiguration"> | ||
10 | <Output directory="./../../../../bin/" assembly="OpenSim.Framework.Servers.HttpServer" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" /> | ||
11 | <Build debugmode="True" target="Library" /> | ||
12 | <Execution runwithwarnings="True" consolepause="True" runtime="MsNet" clr-version="Net_2_0" /> | ||
13 | <CodeGeneration compiler="Csc" warninglevel="4" nowarn="" includedebuginformation="False" optimize="True" unsafecodeallowed="False" generateoverflowchecks="False" mainclass="" target="Library" definesymbols="TRACE" generatexmldocumentation="False" win32Icon="" ctype="CSharpCompilerParameters" /> | ||
14 | </Configuration> | ||
15 | </Configurations> | ||
16 | <DeploymentInformation target="" script="" strategy="File"> | ||
17 | <excludeFiles /> | ||
18 | </DeploymentInformation> | ||
19 | <Contents> | ||
20 | <File name="./BaseHTTPHandler.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
21 | <File name="./BaseHttpServer.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
22 | <File name="./BaseRequestHandler.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
23 | <File name="./BaseStreamHandler.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
24 | <File name="./BinaryStreamHandler.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
25 | <File name="./GenericHTTPMethod.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
26 | <File name="./LLSDMethod.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
27 | <File name="./LLSDMethodString.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
28 | <File name="./OSHttpRequest.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
29 | <File name="./OSHttpResponse.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
30 | <File name="./OSHttpStatusCodes.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
31 | <File name="./RestDeserialiseHandler.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
32 | <File name="./RestHTTPHandler.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
33 | <File name="./RestMethod.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
34 | <File name="./RestObjectPoster.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
35 | <File name="./RestObjectPosterResponse.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
36 | <File name="./RestSessionService.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
37 | <File name="./RestStreamHandler.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
38 | <File name="./SynchronousRestObjectPoster.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
39 | <File name="./XmlRpcMethod.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
40 | <File name="./Interfaces/IHttpAgentHandler.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
41 | <File name="./Interfaces/IHttpServer.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
42 | <File name="./Interfaces/IStreamHandler.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
43 | </Contents> | ||
44 | <References> | ||
45 | <ProjectReference type="Assembly" refto="../../../../bin/HttpServer_OpenSim.dll" localcopy="False" /> | ||
46 | <ProjectReference type="Assembly" refto="../../../../bin/log4net.dll" localcopy="False" /> | ||
47 | <ProjectReference type="Assembly" refto="../../../../bin/OpenMetaverse.StructuredData.dll" localcopy="False" /> | ||
48 | <ProjectReference type="Assembly" refto="../../../../bin/OpenMetaverseTypes.dll" localcopy="False" /> | ||
49 | <ProjectReference type="Project" localcopy="False" refto="OpenSim.Data" /> | ||
50 | <ProjectReference type="Gac" localcopy="False" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> | ||
51 | <ProjectReference type="Gac" localcopy="False" refto="System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> | ||
52 | <ProjectReference type="Assembly" refto="../../../../bin/XMLRPC.dll" localcopy="False" /> | ||
53 | </References> | ||
54 | </Project> | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs new file mode 100644 index 0000000..d5ab926 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs | |||
@@ -0,0 +1,66 @@ | |||
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 | |||
28 | using System.IO; | ||
29 | using System.Xml; | ||
30 | using System.Xml.Serialization; | ||
31 | |||
32 | namespace OpenSim.Framework.Servers.HttpServer | ||
33 | { | ||
34 | public delegate TResponse RestDeserialiseMethod<TRequest, TResponse>(TRequest request); | ||
35 | |||
36 | public class RestDeserialiseHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler | ||
37 | where TRequest : new() | ||
38 | { | ||
39 | private RestDeserialiseMethod<TRequest, TResponse> m_method; | ||
40 | |||
41 | public RestDeserialiseHandler(string httpMethod, string path, RestDeserialiseMethod<TRequest, TResponse> method) | ||
42 | : base(httpMethod, path) | ||
43 | { | ||
44 | m_method = method; | ||
45 | } | ||
46 | |||
47 | public void Handle(string path, Stream request, Stream responseStream, | ||
48 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
49 | { | ||
50 | TRequest deserial; | ||
51 | using (XmlTextReader xmlReader = new XmlTextReader(request)) | ||
52 | { | ||
53 | XmlSerializer deserializer = new XmlSerializer(typeof (TRequest)); | ||
54 | deserial = (TRequest) deserializer.Deserialize(xmlReader); | ||
55 | } | ||
56 | |||
57 | TResponse response = m_method(deserial); | ||
58 | |||
59 | using (XmlWriter xmlWriter = XmlTextWriter.Create(responseStream)) | ||
60 | { | ||
61 | XmlSerializer serializer = new XmlSerializer(typeof (TResponse)); | ||
62 | serializer.Serialize(xmlWriter, response); | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/RestHTTPHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestHTTPHandler.cs new file mode 100644 index 0000000..175a0f2 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestHTTPHandler.cs | |||
@@ -0,0 +1,56 @@ | |||
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 | |||
28 | using System.Collections; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | public class RestHTTPHandler : BaseHTTPHandler | ||
33 | { | ||
34 | private GenericHTTPMethod m_dhttpMethod; | ||
35 | |||
36 | public GenericHTTPMethod Method | ||
37 | { | ||
38 | get { return m_dhttpMethod; } | ||
39 | } | ||
40 | |||
41 | public override Hashtable Handle(string path, Hashtable request) | ||
42 | { | ||
43 | |||
44 | string param = GetParam(path); | ||
45 | request.Add("param", param); | ||
46 | request.Add("path", path); | ||
47 | return m_dhttpMethod(request); | ||
48 | } | ||
49 | |||
50 | public RestHTTPHandler(string httpMethod, string path, GenericHTTPMethod dhttpMethod) | ||
51 | : base(httpMethod, path) | ||
52 | { | ||
53 | m_dhttpMethod = dhttpMethod; | ||
54 | } | ||
55 | } | ||
56 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/RestMethod.cs b/OpenSim/Framework/Servers/HttpServer/RestMethod.cs new file mode 100644 index 0000000..08ee35a --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestMethod.cs | |||
@@ -0,0 +1,32 @@ | |||
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 | |||
28 | namespace OpenSim.Framework.Servers.HttpServer | ||
29 | { | ||
30 | public delegate string RestMethod(string request, string path, string param, | ||
31 | OSHttpRequest httpRequest, OSHttpResponse httpResponse); | ||
32 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs b/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs new file mode 100644 index 0000000..5a424d8 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs | |||
@@ -0,0 +1,84 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Net; | ||
31 | using System.Text; | ||
32 | using System.Xml; | ||
33 | using System.Xml.Serialization; | ||
34 | |||
35 | namespace OpenSim.Framework.Servers.HttpServer | ||
36 | { | ||
37 | /// <summary> | ||
38 | /// Makes an asynchronous REST request which doesn't require us to do anything with the response. | ||
39 | /// </summary> | ||
40 | public class RestObjectPoster | ||
41 | { | ||
42 | public static void BeginPostObject<TRequest>(string requestUrl, TRequest obj) | ||
43 | { | ||
44 | BeginPostObject("POST", requestUrl, obj); | ||
45 | } | ||
46 | |||
47 | public static void BeginPostObject<TRequest>(string verb, string requestUrl, TRequest obj) | ||
48 | { | ||
49 | Type type = typeof (TRequest); | ||
50 | |||
51 | WebRequest request = WebRequest.Create(requestUrl); | ||
52 | request.Method = verb; | ||
53 | request.ContentType = "text/xml"; | ||
54 | |||
55 | MemoryStream buffer = new MemoryStream(); | ||
56 | |||
57 | XmlWriterSettings settings = new XmlWriterSettings(); | ||
58 | settings.Encoding = Encoding.UTF8; | ||
59 | |||
60 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) | ||
61 | { | ||
62 | XmlSerializer serializer = new XmlSerializer(type); | ||
63 | serializer.Serialize(writer, obj); | ||
64 | writer.Flush(); | ||
65 | } | ||
66 | |||
67 | int length = (int) buffer.Length; | ||
68 | request.ContentLength = length; | ||
69 | |||
70 | Stream requestStream = request.GetRequestStream(); | ||
71 | requestStream.Write(buffer.ToArray(), 0, length); | ||
72 | // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); | ||
73 | request.BeginGetResponse(AsyncCallback, request); | ||
74 | } | ||
75 | |||
76 | private static void AsyncCallback(IAsyncResult result) | ||
77 | { | ||
78 | WebRequest request = (WebRequest) result.AsyncState; | ||
79 | using (WebResponse resp = request.EndGetResponse(result)) | ||
80 | { | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs b/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs new file mode 100644 index 0000000..690c583 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs | |||
@@ -0,0 +1,107 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Net; | ||
31 | using System.Text; | ||
32 | using System.Xml; | ||
33 | using System.Xml.Serialization; | ||
34 | |||
35 | namespace OpenSim.Framework.Servers.HttpServer | ||
36 | { | ||
37 | public delegate void ReturnResponse<T>(T reponse); | ||
38 | |||
39 | /// <summary> | ||
40 | /// Makes an asynchronous REST request with a callback to invoke with the response. | ||
41 | /// </summary> | ||
42 | public class RestObjectPosterResponse<TResponse> | ||
43 | { | ||
44 | // private static readonly log4net.ILog m_log | ||
45 | // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
46 | |||
47 | public ReturnResponse<TResponse> ResponseCallback; | ||
48 | |||
49 | public void BeginPostObject<TRequest>(string requestUrl, TRequest obj) | ||
50 | { | ||
51 | BeginPostObject("POST", requestUrl, obj); | ||
52 | } | ||
53 | |||
54 | public void BeginPostObject<TRequest>(string verb, string requestUrl, TRequest obj) | ||
55 | { | ||
56 | Type type = typeof (TRequest); | ||
57 | |||
58 | WebRequest request = WebRequest.Create(requestUrl); | ||
59 | request.Method = verb; | ||
60 | request.ContentType = "text/xml"; | ||
61 | request.Timeout = 10000; | ||
62 | |||
63 | MemoryStream buffer = new MemoryStream(); | ||
64 | |||
65 | XmlWriterSettings settings = new XmlWriterSettings(); | ||
66 | settings.Encoding = Encoding.UTF8; | ||
67 | |||
68 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) | ||
69 | { | ||
70 | XmlSerializer serializer = new XmlSerializer(type); | ||
71 | serializer.Serialize(writer, obj); | ||
72 | writer.Flush(); | ||
73 | } | ||
74 | |||
75 | int length = (int) buffer.Length; | ||
76 | request.ContentLength = length; | ||
77 | |||
78 | Stream requestStream = request.GetRequestStream(); | ||
79 | requestStream.Write(buffer.ToArray(), 0, length); | ||
80 | requestStream.Close(); | ||
81 | // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); | ||
82 | request.BeginGetResponse(AsyncCallback, request); | ||
83 | } | ||
84 | |||
85 | private void AsyncCallback(IAsyncResult result) | ||
86 | { | ||
87 | WebRequest request = (WebRequest) result.AsyncState; | ||
88 | using (WebResponse resp = request.EndGetResponse(result)) | ||
89 | { | ||
90 | TResponse deserial; | ||
91 | XmlSerializer deserializer = new XmlSerializer(typeof (TResponse)); | ||
92 | Stream stream = resp.GetResponseStream(); | ||
93 | |||
94 | // This is currently a bad debug stanza since it gobbles us the response... | ||
95 | // StreamReader reader = new StreamReader(stream); | ||
96 | // m_log.DebugFormat("[REST OBJECT POSTER RESPONSE]: Received {0}", reader.ReadToEnd()); | ||
97 | |||
98 | deserial = (TResponse) deserializer.Deserialize(stream); | ||
99 | |||
100 | if (deserial != null && ResponseCallback != null) | ||
101 | { | ||
102 | ResponseCallback(deserial); | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs new file mode 100644 index 0000000..f5e4248 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs | |||
@@ -0,0 +1,291 @@ | |||
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.IO; | ||
30 | using System.Net; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using System.Xml; | ||
34 | using System.Xml.Serialization; | ||
35 | using log4net; | ||
36 | |||
37 | namespace OpenSim.Framework.Servers.HttpServer | ||
38 | { | ||
39 | public class RestSessionObject<TRequest> | ||
40 | { | ||
41 | private string sid; | ||
42 | private string aid; | ||
43 | private TRequest request_body; | ||
44 | |||
45 | public string SessionID | ||
46 | { | ||
47 | get { return sid; } | ||
48 | set { sid = value; } | ||
49 | } | ||
50 | |||
51 | public string AvatarID | ||
52 | { | ||
53 | get { return aid; } | ||
54 | set { aid = value; } | ||
55 | } | ||
56 | |||
57 | public TRequest Body | ||
58 | { | ||
59 | get { return request_body; } | ||
60 | set { request_body = value; } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | public class SynchronousRestSessionObjectPoster<TRequest, TResponse> | ||
65 | { | ||
66 | public static TResponse BeginPostObject(string verb, string requestUrl, TRequest obj, string sid, string aid) | ||
67 | { | ||
68 | RestSessionObject<TRequest> sobj = new RestSessionObject<TRequest>(); | ||
69 | sobj.SessionID = sid; | ||
70 | sobj.AvatarID = aid; | ||
71 | sobj.Body = obj; | ||
72 | |||
73 | Type type = typeof(RestSessionObject<TRequest>); | ||
74 | |||
75 | WebRequest request = WebRequest.Create(requestUrl); | ||
76 | request.Method = verb; | ||
77 | request.ContentType = "text/xml"; | ||
78 | |||
79 | MemoryStream buffer = new MemoryStream(); | ||
80 | |||
81 | XmlWriterSettings settings = new XmlWriterSettings(); | ||
82 | settings.Encoding = Encoding.UTF8; | ||
83 | |||
84 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) | ||
85 | { | ||
86 | XmlSerializer serializer = new XmlSerializer(type); | ||
87 | serializer.Serialize(writer, sobj); | ||
88 | writer.Flush(); | ||
89 | } | ||
90 | |||
91 | int length = (int)buffer.Length; | ||
92 | request.ContentLength = length; | ||
93 | |||
94 | Stream requestStream = request.GetRequestStream(); | ||
95 | requestStream.Write(buffer.ToArray(), 0, length); | ||
96 | TResponse deserial = default(TResponse); | ||
97 | using (WebResponse resp = request.GetResponse()) | ||
98 | { | ||
99 | XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); | ||
100 | deserial = (TResponse)deserializer.Deserialize(resp.GetResponseStream()); | ||
101 | } | ||
102 | return deserial; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | public class RestSessionObjectPosterResponse<TRequest, TResponse> | ||
107 | { | ||
108 | public ReturnResponse<TResponse> ResponseCallback; | ||
109 | |||
110 | public void BeginPostObject(string requestUrl, TRequest obj, string sid, string aid) | ||
111 | { | ||
112 | BeginPostObject("POST", requestUrl, obj, sid, aid); | ||
113 | } | ||
114 | |||
115 | public void BeginPostObject(string verb, string requestUrl, TRequest obj, string sid, string aid) | ||
116 | { | ||
117 | RestSessionObject<TRequest> sobj = new RestSessionObject<TRequest>(); | ||
118 | sobj.SessionID = sid; | ||
119 | sobj.AvatarID = aid; | ||
120 | sobj.Body = obj; | ||
121 | |||
122 | Type type = typeof(RestSessionObject<TRequest>); | ||
123 | |||
124 | WebRequest request = WebRequest.Create(requestUrl); | ||
125 | request.Method = verb; | ||
126 | request.ContentType = "text/xml"; | ||
127 | request.Timeout = 10000; | ||
128 | |||
129 | MemoryStream buffer = new MemoryStream(); | ||
130 | |||
131 | XmlWriterSettings settings = new XmlWriterSettings(); | ||
132 | settings.Encoding = Encoding.UTF8; | ||
133 | |||
134 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) | ||
135 | { | ||
136 | XmlSerializer serializer = new XmlSerializer(type); | ||
137 | serializer.Serialize(writer, sobj); | ||
138 | writer.Flush(); | ||
139 | } | ||
140 | |||
141 | int length = (int)buffer.Length; | ||
142 | request.ContentLength = length; | ||
143 | |||
144 | Stream requestStream = request.GetRequestStream(); | ||
145 | requestStream.Write(buffer.ToArray(), 0, length); | ||
146 | requestStream.Close(); | ||
147 | // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); | ||
148 | request.BeginGetResponse(AsyncCallback, request); | ||
149 | } | ||
150 | |||
151 | private void AsyncCallback(IAsyncResult result) | ||
152 | { | ||
153 | WebRequest request = (WebRequest)result.AsyncState; | ||
154 | using (WebResponse resp = request.EndGetResponse(result)) | ||
155 | { | ||
156 | TResponse deserial; | ||
157 | XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); | ||
158 | Stream stream = resp.GetResponseStream(); | ||
159 | |||
160 | // This is currently a bad debug stanza since it gobbles us the response... | ||
161 | // StreamReader reader = new StreamReader(stream); | ||
162 | // m_log.DebugFormat("[REST OBJECT POSTER RESPONSE]: Received {0}", reader.ReadToEnd()); | ||
163 | |||
164 | deserial = (TResponse)deserializer.Deserialize(stream); | ||
165 | |||
166 | if (deserial != null && ResponseCallback != null) | ||
167 | { | ||
168 | ResponseCallback(deserial); | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | |||
174 | public delegate bool CheckIdentityMethod(string sid, string aid); | ||
175 | |||
176 | public class RestDeserialiseSecureHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler | ||
177 | where TRequest : new() | ||
178 | { | ||
179 | private static readonly ILog m_log | ||
180 | = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
181 | |||
182 | private RestDeserialiseMethod<TRequest, TResponse> m_method; | ||
183 | private CheckIdentityMethod m_smethod; | ||
184 | |||
185 | public RestDeserialiseSecureHandler( | ||
186 | string httpMethod, string path, | ||
187 | RestDeserialiseMethod<TRequest, TResponse> method, CheckIdentityMethod smethod) | ||
188 | : base(httpMethod, path) | ||
189 | { | ||
190 | m_smethod = smethod; | ||
191 | m_method = method; | ||
192 | } | ||
193 | |||
194 | public void Handle(string path, Stream request, Stream responseStream, | ||
195 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
196 | { | ||
197 | RestSessionObject<TRequest> deserial = default(RestSessionObject<TRequest>); | ||
198 | bool fail = false; | ||
199 | |||
200 | using (XmlTextReader xmlReader = new XmlTextReader(request)) | ||
201 | { | ||
202 | try | ||
203 | { | ||
204 | XmlSerializer deserializer = new XmlSerializer(typeof(RestSessionObject<TRequest>)); | ||
205 | deserial = (RestSessionObject<TRequest>)deserializer.Deserialize(xmlReader); | ||
206 | } | ||
207 | catch (Exception e) | ||
208 | { | ||
209 | m_log.Error("[REST]: Deserialization problem. Ignoring request. " + e); | ||
210 | fail = true; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | TResponse response = default(TResponse); | ||
215 | if (!fail && m_smethod(deserial.SessionID, deserial.AvatarID)) | ||
216 | { | ||
217 | response = m_method(deserial.Body); | ||
218 | } | ||
219 | |||
220 | using (XmlWriter xmlWriter = XmlTextWriter.Create(responseStream)) | ||
221 | { | ||
222 | XmlSerializer serializer = new XmlSerializer(typeof(TResponse)); | ||
223 | serializer.Serialize(xmlWriter, response); | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | |||
228 | public delegate bool CheckTrustedSourceMethod(IPEndPoint peer); | ||
229 | |||
230 | public class RestDeserialiseTrustedHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler | ||
231 | where TRequest : new() | ||
232 | { | ||
233 | private static readonly ILog m_log | ||
234 | = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
235 | |||
236 | /// <summary> | ||
237 | /// The operation to perform once trust has been established. | ||
238 | /// </summary> | ||
239 | /// <param name="httpMethod"></param> | ||
240 | /// <param name="path"></param> | ||
241 | /// <param name="method"></param> | ||
242 | /// <param name="tmethod"></param> | ||
243 | private RestDeserialiseMethod<TRequest, TResponse> m_method; | ||
244 | |||
245 | /// <summary> | ||
246 | /// The method used to check whether a request is trusted. | ||
247 | /// </summary> | ||
248 | private CheckTrustedSourceMethod m_tmethod; | ||
249 | |||
250 | public RestDeserialiseTrustedHandler(string httpMethod, string path, RestDeserialiseMethod<TRequest, TResponse> method, CheckTrustedSourceMethod tmethod) | ||
251 | : base(httpMethod, path) | ||
252 | { | ||
253 | m_tmethod = tmethod; | ||
254 | m_method = method; | ||
255 | } | ||
256 | |||
257 | public void Handle(string path, Stream request, Stream responseStream, | ||
258 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
259 | { | ||
260 | TRequest deserial = default(TRequest); | ||
261 | bool fail = false; | ||
262 | |||
263 | using (XmlTextReader xmlReader = new XmlTextReader(request)) | ||
264 | { | ||
265 | try | ||
266 | { | ||
267 | XmlSerializer deserializer = new XmlSerializer(typeof(TRequest)); | ||
268 | deserial = (TRequest)deserializer.Deserialize(xmlReader); | ||
269 | } | ||
270 | catch (Exception e) | ||
271 | { | ||
272 | m_log.Error("[REST]: Deserialization problem. Ignoring request. " + e); | ||
273 | fail = true; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | TResponse response = default(TResponse); | ||
278 | if (!fail && m_tmethod(httpRequest.RemoteIPEndPoint)) | ||
279 | { | ||
280 | response = m_method(deserial); | ||
281 | } | ||
282 | |||
283 | using (XmlWriter xmlWriter = XmlTextWriter.Create(responseStream)) | ||
284 | { | ||
285 | XmlSerializer serializer = new XmlSerializer(typeof(TResponse)); | ||
286 | serializer.Serialize(xmlWriter, response); | ||
287 | } | ||
288 | } | ||
289 | } | ||
290 | |||
291 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs new file mode 100644 index 0000000..f213c15 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs | |||
@@ -0,0 +1,61 @@ | |||
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 | |||
28 | using System.IO; | ||
29 | using System.Text; | ||
30 | |||
31 | namespace OpenSim.Framework.Servers.HttpServer | ||
32 | { | ||
33 | public class RestStreamHandler : BaseStreamHandler | ||
34 | { | ||
35 | private RestMethod m_restMethod; | ||
36 | |||
37 | public RestMethod Method | ||
38 | { | ||
39 | get { return m_restMethod; } | ||
40 | } | ||
41 | |||
42 | public override byte[] Handle(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
43 | { | ||
44 | Encoding encoding = Encoding.UTF8; | ||
45 | StreamReader streamReader = new StreamReader(request, encoding); | ||
46 | |||
47 | string requestBody = streamReader.ReadToEnd(); | ||
48 | streamReader.Close(); | ||
49 | |||
50 | string param = GetParam(path); | ||
51 | string responseString = m_restMethod(requestBody, path, param, httpRequest, httpResponse); | ||
52 | |||
53 | return Encoding.UTF8.GetBytes(responseString); | ||
54 | } | ||
55 | |||
56 | public RestStreamHandler(string httpMethod, string path, RestMethod restMethod) : base(httpMethod, path) | ||
57 | { | ||
58 | m_restMethod = restMethod; | ||
59 | } | ||
60 | } | ||
61 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectPoster.cs b/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectPoster.cs new file mode 100644 index 0000000..b754c36 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectPoster.cs | |||
@@ -0,0 +1,83 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Net; | ||
31 | using System.Text; | ||
32 | using System.Xml; | ||
33 | using System.Xml.Serialization; | ||
34 | |||
35 | namespace OpenSim.Framework.Servers.HttpServer | ||
36 | { | ||
37 | public class SynchronousRestObjectPoster | ||
38 | { | ||
39 | /// <summary> | ||
40 | /// Perform a synchronous REST request. | ||
41 | /// </summary> | ||
42 | /// <param name="verb"></param> | ||
43 | /// <param name="requestUrl"></param> | ||
44 | /// <param name="obj"> </param> | ||
45 | /// <returns></returns> | ||
46 | /// | ||
47 | /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting | ||
48 | /// the request. You'll want to make sure you deal with this as they're not uncommon</exception> | ||
49 | public static TResponse BeginPostObject<TRequest, TResponse>(string verb, string requestUrl, TRequest obj) | ||
50 | { | ||
51 | Type type = typeof (TRequest); | ||
52 | |||
53 | WebRequest request = WebRequest.Create(requestUrl); | ||
54 | request.Method = verb; | ||
55 | request.ContentType = "text/xml"; | ||
56 | |||
57 | MemoryStream buffer = new MemoryStream(); | ||
58 | |||
59 | XmlWriterSettings settings = new XmlWriterSettings(); | ||
60 | settings.Encoding = Encoding.UTF8; | ||
61 | |||
62 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) | ||
63 | { | ||
64 | XmlSerializer serializer = new XmlSerializer(type); | ||
65 | serializer.Serialize(writer, obj); | ||
66 | writer.Flush(); | ||
67 | } | ||
68 | |||
69 | int length = (int) buffer.Length; | ||
70 | request.ContentLength = length; | ||
71 | |||
72 | Stream requestStream = request.GetRequestStream(); | ||
73 | requestStream.Write(buffer.ToArray(), 0, length); | ||
74 | TResponse deserial = default(TResponse); | ||
75 | using (WebResponse resp = request.GetResponse()) | ||
76 | { | ||
77 | XmlSerializer deserializer = new XmlSerializer(typeof (TResponse)); | ||
78 | deserial = (TResponse) deserializer.Deserialize(resp.GetResponseStream()); | ||
79 | } | ||
80 | return deserial; | ||
81 | } | ||
82 | } | ||
83 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/XmlRpcMethod.cs b/OpenSim/Framework/Servers/HttpServer/XmlRpcMethod.cs new file mode 100644 index 0000000..843b3f7 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/XmlRpcMethod.cs | |||
@@ -0,0 +1,33 @@ | |||
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 | |||
28 | using Nwc.XmlRpc; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | public delegate XmlRpcResponse XmlRpcMethod(XmlRpcRequest request); | ||
33 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll b/OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll new file mode 100755 index 0000000..a191346 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll | |||
Binary files differ | |||
diff --git a/OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll.mdb b/OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll.mdb new file mode 100644 index 0000000..25a50b9 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll.mdb | |||
Binary files differ | |||
diff --git a/OpenSim/Framework/Servers/MessageServerInfo.cs b/OpenSim/Framework/Servers/MessageServerInfo.cs new file mode 100644 index 0000000..17b5f10 --- /dev/null +++ b/OpenSim/Framework/Servers/MessageServerInfo.cs | |||
@@ -0,0 +1,48 @@ | |||
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 | |||
28 | using System.Collections.Generic; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers | ||
31 | { | ||
32 | public class MessageServerInfo | ||
33 | { | ||
34 | public string URI; | ||
35 | public string sendkey; | ||
36 | public string recvkey; | ||
37 | public List<ulong> responsibleForRegions; | ||
38 | |||
39 | public MessageServerInfo() | ||
40 | { | ||
41 | } | ||
42 | |||
43 | public override string ToString() | ||
44 | { | ||
45 | return URI; | ||
46 | } | ||
47 | } | ||
48 | } | ||
diff --git a/OpenSim/Framework/Servers/PostAssetStreamHandler.cs b/OpenSim/Framework/Servers/PostAssetStreamHandler.cs new file mode 100644 index 0000000..419b408 --- /dev/null +++ b/OpenSim/Framework/Servers/PostAssetStreamHandler.cs | |||
@@ -0,0 +1,72 @@ | |||
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.IO; | ||
29 | using System.Reflection; | ||
30 | using System.Xml.Serialization; | ||
31 | using log4net; | ||
32 | using OpenMetaverse; | ||
33 | using OpenSim.Data; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Servers.HttpServer; | ||
36 | |||
37 | namespace OpenSim.Framework.Servers | ||
38 | { | ||
39 | public class PostAssetStreamHandler : BaseStreamHandler | ||
40 | { | ||
41 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
42 | |||
43 | // private OpenAsset_Main m_assetManager; | ||
44 | private IAssetDataPlugin m_assetProvider; | ||
45 | |||
46 | public override byte[] Handle(string path, Stream request, | ||
47 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
48 | { | ||
49 | string param = GetParam(path); | ||
50 | |||
51 | UUID assetId; | ||
52 | if (param.Length > 0) | ||
53 | UUID.TryParse(param, out assetId); | ||
54 | // byte[] txBuffer = new byte[4096]; | ||
55 | |||
56 | XmlSerializer xs = new XmlSerializer(typeof (AssetBase)); | ||
57 | AssetBase asset = (AssetBase) xs.Deserialize(request); | ||
58 | |||
59 | m_log.InfoFormat("[REST]: Creating asset {0}", asset.FullID); | ||
60 | m_assetProvider.CreateAsset(asset); | ||
61 | |||
62 | return new byte[] {}; | ||
63 | } | ||
64 | |||
65 | public PostAssetStreamHandler(IAssetDataPlugin assetProvider) | ||
66 | : base("POST", "/assets") | ||
67 | { | ||
68 | // m_assetManager = assetManager; | ||
69 | m_assetProvider = assetProvider; | ||
70 | } | ||
71 | } | ||
72 | } | ||
diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs new file mode 100644 index 0000000..ee8ab09 --- /dev/null +++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs | |||
@@ -0,0 +1,394 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Specialized; | ||
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Net.Sockets; | ||
33 | using System.Text; | ||
34 | using HttpServer; | ||
35 | using HttpServer.FormDecoders; | ||
36 | using NUnit.Framework; | ||
37 | using NUnit.Framework.SyntaxHelpers; | ||
38 | using OpenSim.Framework.Servers.HttpServer; | ||
39 | |||
40 | namespace OpenSim.Framework.Servers.Tests | ||
41 | { | ||
42 | [TestFixture] | ||
43 | public class OSHttpTests | ||
44 | { | ||
45 | // we need an IHttpClientContext for our tests | ||
46 | public class TestHttpClientContext: IHttpClientContext | ||
47 | { | ||
48 | private bool _secured; | ||
49 | public bool Secured | ||
50 | { | ||
51 | get { return _secured; } | ||
52 | } | ||
53 | |||
54 | public TestHttpClientContext(bool secured) | ||
55 | { | ||
56 | _secured = secured; | ||
57 | } | ||
58 | |||
59 | public void Disconnect(SocketError error) {} | ||
60 | public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {} | ||
61 | public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {} | ||
62 | public void Respond(string body) {} | ||
63 | public void Send(byte[] buffer) {} | ||
64 | public void Send(byte[] buffer, int offset, int size) {} | ||
65 | } | ||
66 | |||
67 | public class TestHttpRequest: IHttpRequest | ||
68 | { | ||
69 | public bool BodyIsComplete | ||
70 | { | ||
71 | get { return true; } | ||
72 | } | ||
73 | public string[] AcceptTypes | ||
74 | { | ||
75 | get {return _acceptTypes; } | ||
76 | } | ||
77 | private string[] _acceptTypes; | ||
78 | public Stream Body | ||
79 | { | ||
80 | get { return _body; } | ||
81 | set { _body = value;} | ||
82 | } | ||
83 | private Stream _body; | ||
84 | public ConnectionType Connection | ||
85 | { | ||
86 | get { return _connection; } | ||
87 | set { _connection = value; } | ||
88 | } | ||
89 | private ConnectionType _connection; | ||
90 | public int ContentLength | ||
91 | { | ||
92 | get { return _contentLength; } | ||
93 | set { _contentLength = value; } | ||
94 | } | ||
95 | private int _contentLength; | ||
96 | public NameValueCollection Headers | ||
97 | { | ||
98 | get { return _headers; } | ||
99 | } | ||
100 | private NameValueCollection _headers = new NameValueCollection(); | ||
101 | public string HttpVersion | ||
102 | { | ||
103 | get { return _httpVersion; } | ||
104 | set { _httpVersion = value; } | ||
105 | } | ||
106 | private string _httpVersion = null; | ||
107 | public string Method | ||
108 | { | ||
109 | get { return _method; } | ||
110 | set { _method = value; } | ||
111 | } | ||
112 | private string _method = null; | ||
113 | public HttpInput QueryString | ||
114 | { | ||
115 | get { return _queryString; } | ||
116 | } | ||
117 | private HttpInput _queryString = null; | ||
118 | public Uri Uri | ||
119 | { | ||
120 | get { return _uri; } | ||
121 | set { _uri = value; } | ||
122 | } | ||
123 | private Uri _uri = null; | ||
124 | public string[] UriParts | ||
125 | { | ||
126 | get { return _uri.Segments; } | ||
127 | } | ||
128 | public HttpParam Param | ||
129 | { | ||
130 | get { return null; } | ||
131 | } | ||
132 | public HttpForm Form | ||
133 | { | ||
134 | get { return null; } | ||
135 | } | ||
136 | public bool IsAjax | ||
137 | { | ||
138 | get { return false; } | ||
139 | } | ||
140 | public RequestCookies Cookies | ||
141 | { | ||
142 | get { return null; } | ||
143 | } | ||
144 | |||
145 | public TestHttpRequest() {} | ||
146 | |||
147 | public TestHttpRequest(string contentEncoding, string contentType, string userAgent, | ||
148 | string remoteAddr, string remotePort, string[] acceptTypes, | ||
149 | ConnectionType connectionType, int contentLength, Uri uri) | ||
150 | { | ||
151 | _headers["content-encoding"] = contentEncoding; | ||
152 | _headers["content-type"] = contentType; | ||
153 | _headers["user-agent"] = userAgent; | ||
154 | _headers["remote_addr"] = remoteAddr; | ||
155 | _headers["remote_port"] = remotePort; | ||
156 | |||
157 | _acceptTypes = acceptTypes; | ||
158 | _connection = connectionType; | ||
159 | _contentLength = contentLength; | ||
160 | _uri = uri; | ||
161 | } | ||
162 | |||
163 | public void DecodeBody(FormDecoderProvider providers) {} | ||
164 | public void SetCookies(RequestCookies cookies) {} | ||
165 | public void AddHeader(string name, string value) | ||
166 | { | ||
167 | _headers.Add(name, value); | ||
168 | } | ||
169 | public int AddToBody(byte[] bytes, int offset, int length) | ||
170 | { | ||
171 | return 0; | ||
172 | } | ||
173 | public void Clear() {} | ||
174 | |||
175 | public object Clone() | ||
176 | { | ||
177 | TestHttpRequest clone = new TestHttpRequest(); | ||
178 | clone._acceptTypes = _acceptTypes; | ||
179 | clone._connection = _connection; | ||
180 | clone._contentLength = _contentLength; | ||
181 | clone._uri = _uri; | ||
182 | clone._headers = new NameValueCollection(_headers); | ||
183 | |||
184 | return clone; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | public class TestHttpResponse: IHttpResponse | ||
189 | { | ||
190 | public Stream Body | ||
191 | { | ||
192 | get { return _body; } | ||
193 | |||
194 | set { _body = value; } | ||
195 | } | ||
196 | private Stream _body; | ||
197 | |||
198 | public string ProtocolVersion | ||
199 | { | ||
200 | get { return _protocolVersion; } | ||
201 | set { _protocolVersion = value; } | ||
202 | } | ||
203 | private string _protocolVersion; | ||
204 | |||
205 | public bool Chunked | ||
206 | { | ||
207 | get { return _chunked; } | ||
208 | |||
209 | set { _chunked = value; } | ||
210 | } | ||
211 | private bool _chunked; | ||
212 | |||
213 | public ConnectionType Connection | ||
214 | { | ||
215 | get { return _connection; } | ||
216 | |||
217 | set { _connection = value; } | ||
218 | } | ||
219 | private ConnectionType _connection; | ||
220 | |||
221 | public Encoding Encoding | ||
222 | { | ||
223 | get { return _encoding; } | ||
224 | |||
225 | set { _encoding = value; } | ||
226 | } | ||
227 | private Encoding _encoding; | ||
228 | |||
229 | public int KeepAlive | ||
230 | { | ||
231 | get { return _keepAlive; } | ||
232 | |||
233 | set { _keepAlive = value; } | ||
234 | } | ||
235 | private int _keepAlive; | ||
236 | |||
237 | public HttpStatusCode Status | ||
238 | { | ||
239 | get { return _status; } | ||
240 | |||
241 | set { _status = value; } | ||
242 | } | ||
243 | private HttpStatusCode _status; | ||
244 | |||
245 | public string Reason | ||
246 | { | ||
247 | get { return _reason; } | ||
248 | |||
249 | set { _reason = value; } | ||
250 | } | ||
251 | private string _reason; | ||
252 | |||
253 | public long ContentLength | ||
254 | { | ||
255 | get { return _contentLength; } | ||
256 | |||
257 | set { _contentLength = value; } | ||
258 | } | ||
259 | private long _contentLength; | ||
260 | |||
261 | public string ContentType | ||
262 | { | ||
263 | get { return _contentType; } | ||
264 | |||
265 | set { _contentType = value; } | ||
266 | } | ||
267 | private string _contentType; | ||
268 | |||
269 | public bool HeadersSent | ||
270 | { | ||
271 | get { return _headersSent; } | ||
272 | } | ||
273 | private bool _headersSent; | ||
274 | |||
275 | public bool Sent | ||
276 | { | ||
277 | get { return _sent; } | ||
278 | } | ||
279 | private bool _sent; | ||
280 | |||
281 | public ResponseCookies Cookies | ||
282 | { | ||
283 | get { return _cookies; } | ||
284 | } | ||
285 | private ResponseCookies _cookies = null; | ||
286 | |||
287 | public TestHttpResponse() | ||
288 | { | ||
289 | _headersSent = false; | ||
290 | _sent = false; | ||
291 | } | ||
292 | |||
293 | public void AddHeader(string name, string value) {} | ||
294 | public void Send() | ||
295 | { | ||
296 | if (!_headersSent) SendHeaders(); | ||
297 | if (_sent) throw new InvalidOperationException("stuff already sent"); | ||
298 | _sent = true; | ||
299 | } | ||
300 | |||
301 | public void SendBody(byte[] buffer, int offset, int count) | ||
302 | { | ||
303 | if (!_headersSent) SendHeaders(); | ||
304 | _sent = true; | ||
305 | } | ||
306 | public void SendBody(byte[] buffer) | ||
307 | { | ||
308 | if (!_headersSent) SendHeaders(); | ||
309 | _sent = true; | ||
310 | } | ||
311 | |||
312 | public void SendHeaders() | ||
313 | { | ||
314 | if (_headersSent) throw new InvalidOperationException("headers already sent"); | ||
315 | _headersSent = true; | ||
316 | } | ||
317 | |||
318 | public void Redirect(Uri uri) {} | ||
319 | public void Redirect(string url) {} | ||
320 | } | ||
321 | |||
322 | |||
323 | public OSHttpRequest req0; | ||
324 | public OSHttpRequest req1; | ||
325 | |||
326 | public OSHttpResponse rsp0; | ||
327 | |||
328 | public IPEndPoint ipEP0; | ||
329 | |||
330 | [TestFixtureSetUp] | ||
331 | public void Init() | ||
332 | { | ||
333 | TestHttpRequest threq0 = new TestHttpRequest("utf-8", "text/xml", "OpenSim Test Agent", "192.168.0.1", "4711", | ||
334 | new string[] {"text/xml"}, | ||
335 | ConnectionType.KeepAlive, 4711, | ||
336 | new Uri("http://127.0.0.1/admin/inventory/Dr+Who/Tardis")); | ||
337 | threq0.Method = "GET"; | ||
338 | threq0.HttpVersion = HttpHelper.HTTP10; | ||
339 | |||
340 | TestHttpRequest threq1 = new TestHttpRequest("utf-8", "text/xml", "OpenSim Test Agent", "192.168.0.1", "4711", | ||
341 | new string[] {"text/xml"}, | ||
342 | ConnectionType.KeepAlive, 4711, | ||
343 | new Uri("http://127.0.0.1/admin/inventory/Dr+Who/Tardis?a=0&b=1&c=2")); | ||
344 | threq1.Method = "POST"; | ||
345 | threq1.HttpVersion = HttpHelper.HTTP11; | ||
346 | threq1.Headers["x-wuff"] = "wuffwuff"; | ||
347 | threq1.Headers["www-authenticate"] = "go away"; | ||
348 | |||
349 | req0 = new OSHttpRequest(new TestHttpClientContext(false), threq0); | ||
350 | req1 = new OSHttpRequest(new TestHttpClientContext(false), threq1); | ||
351 | |||
352 | rsp0 = new OSHttpResponse(new TestHttpResponse()); | ||
353 | |||
354 | ipEP0 = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 4711); | ||
355 | |||
356 | } | ||
357 | |||
358 | [Test] | ||
359 | public void T000_OSHttpRequest() | ||
360 | { | ||
361 | Assert.That(req0.HttpMethod, Is.EqualTo("GET")); | ||
362 | Assert.That(req0.ContentType, Is.EqualTo("text/xml")); | ||
363 | Assert.That(req0.ContentLength, Is.EqualTo(4711)); | ||
364 | |||
365 | Assert.That(req1.HttpMethod, Is.EqualTo("POST")); | ||
366 | } | ||
367 | |||
368 | [Test] | ||
369 | public void T001_OSHttpRequestHeaderAccess() | ||
370 | { | ||
371 | Assert.That(req1.Headers["x-wuff"], Is.EqualTo("wuffwuff")); | ||
372 | Assert.That(req1.Headers.Get("x-wuff"), Is.EqualTo("wuffwuff")); | ||
373 | |||
374 | Assert.That(req1.Headers["www-authenticate"], Is.EqualTo("go away")); | ||
375 | Assert.That(req1.Headers.Get("www-authenticate"), Is.EqualTo("go away")); | ||
376 | |||
377 | Assert.That(req0.RemoteIPEndPoint, Is.EqualTo(ipEP0)); | ||
378 | } | ||
379 | |||
380 | [Test] | ||
381 | public void T002_OSHttpRequestUriParsing() | ||
382 | { | ||
383 | Assert.That(req0.RawUrl, Is.EqualTo("/admin/inventory/Dr+Who/Tardis")); | ||
384 | Assert.That(req1.Url.ToString(), Is.EqualTo("http://127.0.0.1/admin/inventory/Dr+Who/Tardis?a=0&b=1&c=2")); | ||
385 | } | ||
386 | |||
387 | [Test] | ||
388 | public void T100_OSHttpResponse() | ||
389 | { | ||
390 | rsp0.ContentType = "text/xml"; | ||
391 | Assert.That(rsp0.ContentType, Is.EqualTo("text/xml")); | ||
392 | } | ||
393 | } | ||
394 | } | ||
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs new file mode 100644 index 0000000..bdf9354 --- /dev/null +++ b/OpenSim/Framework/Servers/VersionInfo.cs | |||
@@ -0,0 +1,53 @@ | |||
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 | |||
28 | namespace OpenSim | ||
29 | { | ||
30 | public class VersionInfo | ||
31 | { | ||
32 | /// <value> | ||
33 | /// This is the OpenSim version string. Change this if you are releasing a new OpenSim version. | ||
34 | /// </value> | ||
35 | public readonly static string Version = "OpenSimulator Server 0.6.4"; // stay with 27 chars (used in regioninfo) | ||
36 | |||
37 | /// <value> | ||
38 | /// This is the external interface version. It is separate from the OpenSimulator project version. | ||
39 | /// | ||
40 | /// This version number should be | ||
41 | /// increased by 1 every time a code change makes the previous OpenSimulator revision incompatible | ||
42 | /// with the new revision. This will usually be due to interregion or grid facing interface changes. | ||
43 | /// | ||
44 | /// Changes which are compatible with an older revision (e.g. older revisions experience degraded functionality | ||
45 | /// but not outright failure) do not need a version number increment. | ||
46 | /// | ||
47 | /// Having this version number allows the grid service to reject connections from regions running a version | ||
48 | /// of the code that is too old. | ||
49 | /// | ||
50 | /// </value> | ||
51 | public readonly static int MajorInterfaceVersion = 3; | ||
52 | } | ||
53 | } | ||