diff options
author | onefang | 2019-08-11 22:21:39 +1000 |
---|---|---|
committer | onefang | 2019-08-11 22:21:39 +1000 |
commit | 7dffa1fa67ed668872d96036a508e2be64cb8b5c (patch) | |
tree | 20cfaf31973092dd013cc0b252c111df46aee3df /OpenSim/Server/Handlers/Web/WebServerConnector.cs | |
parent | Various clean ups. (diff) | |
download | opensim-SC_OLD-7dffa1fa67ed668872d96036a508e2be64cb8b5c.zip opensim-SC_OLD-7dffa1fa67ed668872d96036a508e2be64cb8b5c.tar.gz opensim-SC_OLD-7dffa1fa67ed668872d96036a508e2be64cb8b5c.tar.bz2 opensim-SC_OLD-7dffa1fa67ed668872d96036a508e2be64cb8b5c.tar.xz |
WebServerInConnector -> WebServerConnector
Just a name change.
Diffstat (limited to 'OpenSim/Server/Handlers/Web/WebServerConnector.cs')
-rw-r--r-- | OpenSim/Server/Handlers/Web/WebServerConnector.cs | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/OpenSim/Server/Handlers/Web/WebServerConnector.cs b/OpenSim/Server/Handlers/Web/WebServerConnector.cs new file mode 100644 index 0000000..2607386 --- /dev/null +++ b/OpenSim/Server/Handlers/Web/WebServerConnector.cs | |||
@@ -0,0 +1,368 @@ | |||
1 | using System; | ||
2 | using System.Collections; | ||
3 | using System.Collections.Generic; | ||
4 | using System.IO; | ||
5 | using System.Net; | ||
6 | using System.Reflection; | ||
7 | using System.Security; | ||
8 | using System.Text; | ||
9 | using log4net; | ||
10 | using Nini.Config; | ||
11 | using OpenMetaverse; | ||
12 | using OpenMetaverse.StructuredData; | ||
13 | using OpenSim.Data.MySQL; | ||
14 | using OpenSim.Framework; | ||
15 | using OpenSim.Framework.Servers.HttpServer; | ||
16 | using OpenSim.Server.Handlers.Base; | ||
17 | |||
18 | namespace OpenSim.Server.Handlers.Web | ||
19 | { | ||
20 | public class WebServerConnector : ServiceConnector | ||
21 | { | ||
22 | // This is all slow and clunky, it's not a real web server, just something to use if you don't want a real one. | ||
23 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
24 | private IConfigSource m_Config; | ||
25 | protected MySQLRaw m_database = null; | ||
26 | private Hashtable mime = new Hashtable(); | ||
27 | private Hashtable ssi = new Hashtable(); | ||
28 | |||
29 | public WebServerConnector(IConfigSource config, IHttpServer server, string configName) : base(config, server, configName) | ||
30 | { | ||
31 | string dllName = String.Empty; | ||
32 | string connString = String.Empty; | ||
33 | |||
34 | m_Config = config; | ||
35 | |||
36 | // Try reading the [DatabaseService] section, if it exists | ||
37 | IConfig dbConfig = m_Config.Configs["DatabaseService"]; | ||
38 | if (dbConfig != null) | ||
39 | { | ||
40 | if (dllName == String.Empty) | ||
41 | dllName = dbConfig.GetString("StorageProvider", String.Empty); | ||
42 | if (connString == String.Empty) | ||
43 | connString = dbConfig.GetString("ConnectionString", String.Empty); | ||
44 | } | ||
45 | if (dllName.Equals(String.Empty)) | ||
46 | throw new Exception("No StorageProvider configured"); | ||
47 | |||
48 | //// TODO - Should do the plugin thing to pick between database backends. | ||
49 | //// Or not, we are all using MariaDB anyway. | ||
50 | // m_Database = LoadPlugin<SQLGenericHandler>(dllName, new Object[] { connString }); | ||
51 | |||
52 | m_database = new MySQLRaw(connString); | ||
53 | |||
54 | mime.Add(".gz", "application/gzip"); | ||
55 | mime.Add(".js", "application/javascript"); | ||
56 | mime.Add(".json", "application/json"); | ||
57 | mime.Add(".pdf", "application/pdf"); | ||
58 | mime.Add(".rtf", "application/rtf"); | ||
59 | mime.Add(".zip", "application/zip"); | ||
60 | mime.Add(".xz", "application/x-xz"); | ||
61 | mime.Add(".gif", "image/gif"); | ||
62 | mime.Add(".png", "image/png"); | ||
63 | mime.Add(".jp2", "image/jp2"); | ||
64 | mime.Add(".jpg2", "image/jp2"); | ||
65 | mime.Add(".jpe", "image/jpeg"); | ||
66 | mime.Add(".jpg", "image/jpeg"); | ||
67 | mime.Add(".jpeg", "image/jpeg"); | ||
68 | mime.Add(".svg", "image/svg+xml"); | ||
69 | mime.Add(".svgz", "image/svg+xml"); | ||
70 | mime.Add(".tif", "image/tiff"); | ||
71 | mime.Add(".tiff", "image/tiff"); | ||
72 | mime.Add(".css", "text/css"); | ||
73 | mime.Add(".html", "text/html"); | ||
74 | mime.Add(".htm", "text/html"); | ||
75 | mime.Add(".shtml", "text/html"); | ||
76 | // mime.Add(".md", "text/markdown"); | ||
77 | // mime.Add(".markdown","text/markdown"); | ||
78 | mime.Add(".txt", "text/plain"); | ||
79 | |||
80 | IConfig cfg = m_Config.Configs["GridInfoService"]; | ||
81 | string HomeURI = Util.GetConfigVarFromSections<string>(m_Config, "HomeURI", new string[] { "Startup", "Hypergrid" }, String.Empty); | ||
82 | ssi.Add("grid", cfg.GetString("gridname", "my grid")); | ||
83 | ssi.Add("uri", cfg.GetString("login", HomeURI)); | ||
84 | ssi.Add("version", VersionInfo.Version); | ||
85 | server.AddHTTPHandler("/web/", WebRequestHandler); | ||
86 | } | ||
87 | |||
88 | private Hashtable WebRequestHandler(Hashtable request) | ||
89 | { | ||
90 | long locIn = m_database.Count("Presence", "RegionID != '00000000-0000-0000-0000-000000000000'"); // Locals online but not HGing, and HGers in world. | ||
91 | long HGin = m_database.Count("Presence", "UserID NOT IN (SELECT PrincipalID FROM UserAccounts)"); // HGers in world. | ||
92 | long locOut = m_database.Count("hg_traveling_data", "GridExternalName != '" + ssi["uri"] + "'"); // Locals that are HGing. | ||
93 | Hashtable reply = new Hashtable(); | ||
94 | ssi["members"] = m_database.Count("UserAccounts").ToString(); | ||
95 | ssi["sims"] = m_database.Count("regions").ToString(); | ||
96 | ssi["inworld"] = (locIn - HGin).ToString(); | ||
97 | ssi["outworld"] = locOut.ToString(); | ||
98 | ssi["hgers"] = HGin.ToString(); | ||
99 | ssi["month"] = m_database.Count("GridUser", "Login > UNIX_TIMESTAMP(FROM_UNIXTIME(UNIX_TIMESTAMP(now()) - 2419200))").ToString(); | ||
100 | |||
101 | string reqpath = (string) request["uri"]; | ||
102 | string[] query = (string[]) request["querystringkeys"]; | ||
103 | Hashtable headers = (Hashtable) request["headers"]; | ||
104 | string method = (string) request["http-method"]; | ||
105 | string type = (string) request["content-type"]; | ||
106 | string body = (string) request["body"]; | ||
107 | string file = reqpath.Remove(0, 5); | ||
108 | string path = Path.Combine(Util.webDir(), file); | ||
109 | |||
110 | m_log.InfoFormat("[WEB SERVICE]: {0} method path {1} type {2} body {3}.", method, reqpath, type, body); | ||
111 | foreach (DictionaryEntry h in headers) | ||
112 | m_log.InfoFormat("[WEB SERVICE]: {0} method path {1} header {2} = {3}", method, reqpath, (string) h.Key, (string) h.Value); | ||
113 | foreach (String q in query) | ||
114 | m_log.InfoFormat("[WEB SERVICE]: {0} method path {1} query {2} value {3}", method, reqpath, q, (string) request[q]); | ||
115 | |||
116 | reply["int_response_code"] = 200; | ||
117 | if ("GET" == method) | ||
118 | { | ||
119 | if (File.Exists(path)) | ||
120 | { | ||
121 | string m = (string) mime[Path.GetExtension(path).ToLower()]; | ||
122 | reply["content_type"] = m; | ||
123 | if ((null == m) || ("text/" != m.Substring(0, 5))) | ||
124 | reply["bin_response_data"] = File.ReadAllBytes(path); | ||
125 | else | ||
126 | { | ||
127 | StreamReader csr = File.OpenText(path); | ||
128 | string content = csr.ReadToEnd(); | ||
129 | // Slow and wasteful, but I'm expecting only tiny web files, not accessed very often. | ||
130 | foreach (DictionaryEntry v in ssi) | ||
131 | { | ||
132 | content = content.Replace("<!--#echo var=\"" + ((string) v.Key) + "\" -->", (string) v.Value); | ||
133 | } | ||
134 | reply["str_response_string"] = content; | ||
135 | csr.Close(); | ||
136 | } | ||
137 | } | ||
138 | else | ||
139 | { | ||
140 | if ("account.html" == file) | ||
141 | reply["str_response_string"] = loginPage(null, ""); | ||
142 | else | ||
143 | { | ||
144 | m_log.ErrorFormat("[WEB SERVICE]: Unable to read {0}.", path); | ||
145 | reply["int_response_code"] = 404; | ||
146 | reply["content_type"] = "text/html"; | ||
147 | reply["str_response_string"] = "<html><title>404 Unknown page</title><head></head><body bgcolor=\"black\" text=\"white\" alink=\"red\" link=\"blue\" vlink=\"purple\">" + | ||
148 | "404 error, can't find the " + reqpath + " page.<p> </p></body></html>"; | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | else if ("POST" == method) | ||
153 | { | ||
154 | Hashtable fields = new Hashtable(); | ||
155 | string[] bdy = body.Split('&'); | ||
156 | body = ""; | ||
157 | foreach (String bd in bdy) | ||
158 | { | ||
159 | string[] b = bd.Split('='); | ||
160 | if (b.Length == 0) | ||
161 | continue; | ||
162 | String n = System.Web.HttpUtility.UrlDecode(b[0]); | ||
163 | String v = ""; | ||
164 | if (b.Length > 1) | ||
165 | v = System.Web.HttpUtility.UrlDecode(b[1]); | ||
166 | fields[n] = v; | ||
167 | body = body + "<p>" + n + " = " + v + "</p>\n"; | ||
168 | } | ||
169 | |||
170 | if ("account.html" == file) | ||
171 | { | ||
172 | if ("logout" == fields["doit"].ToString()) | ||
173 | reply["str_response_string"] = loginPage(null, "Logged out."); | ||
174 | else if ("create" == fields["doit"].ToString()) | ||
175 | { | ||
176 | if ("" == fields["email"].ToString()) | ||
177 | reply["str_response_string"] = loginPage(fields, "Please supply an email address when creating an account."); | ||
178 | else | ||
179 | { | ||
180 | reply["str_response_string"] = loggedOnPage(body, fields); | ||
181 | } | ||
182 | } | ||
183 | else if ("list" == fields["doit"].ToString()) | ||
184 | { | ||
185 | List< Hashtable > rows = m_database.Select("UserAccounts", | ||
186 | "CONCAT(FirstName,' ',LastName) as Name,UserTitle as Title,UserLevel as Level,UserFlags as Flags,PrincipalID as UUID", | ||
187 | "", "Name"); | ||
188 | reply["str_response_string"] = "<html><title>member accounts</title><head></head><body bgcolor=\"black\" text=\"white\" alink=\"red\" link=\"blue\" vlink=\"purple\">" + | ||
189 | table(rows, new string[5] {"Name", "Title", "Level", "Flags", "UUID"}, "member accounts", | ||
190 | "account.html?doit=edit&token=" + fields["token"].ToString(), "UUID") + "<p>" + button("my account") + "</p></body></html>"; | ||
191 | } | ||
192 | else | ||
193 | { | ||
194 | reply["str_response_string"] = loggedOnPage(body, fields); | ||
195 | } | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | m_log.ErrorFormat("[WEB SERVICE]: No such POST target {0}.", path); | ||
200 | reply["int_response_code"] = 404; | ||
201 | reply["content_type"] = "text/html"; | ||
202 | reply["str_response_string"] = "<html><title>404 Unknown page</title><head></head><body bgcolor=\"black\" text=\"white\" alink=\"red\" link=\"blue\" vlink=\"purple\">" + | ||
203 | "404 error, can't find the " + reqpath + " page.<p> </p></body></html>"; | ||
204 | } | ||
205 | } | ||
206 | else | ||
207 | { | ||
208 | m_log.ErrorFormat("[WEB SERVICE]: UNKNOWN method {0} path {1}.", method, reqpath); | ||
209 | reply["int_response_code"] = 404; | ||
210 | reply["content_type"] = "text/html"; | ||
211 | reply["str_response_string"] = "<html><title>Unknown method</title><head></head><body bgcolor=\"black\" text=\"white\" alink=\"red\" link=\"blue\" vlink=\"purple\">" + | ||
212 | "HUH! For " + reqpath + " page.<p> </p></body></html>"; | ||
213 | } | ||
214 | |||
215 | m_log.Info("[WEB SERVICE]: "); | ||
216 | return reply; | ||
217 | } | ||
218 | |||
219 | private string loginPage(Hashtable fields, string message) | ||
220 | { | ||
221 | string f = ""; | ||
222 | string l = ""; | ||
223 | string e = ""; | ||
224 | if (null != fields) | ||
225 | { | ||
226 | f = fields["firstName"].ToString(); | ||
227 | l = fields["lastName"].ToString(); | ||
228 | e = fields["email"].ToString(); | ||
229 | } | ||
230 | return header(ssi["grid"] + " account") | ||
231 | + form("account.html", "", | ||
232 | text("text", "first name", "firstName", f, 16, true) | ||
233 | + text("text", "last name", "lastName", l, 16, true) | ||
234 | + text("email", "email", "email", e, 0, false) | ||
235 | + text("password", "password", "password", "", 14,true) | ||
236 | + button("create") | ||
237 | + button("login") | ||
238 | ) | ||
239 | + "<p>" + message + "</p>" | ||
240 | + footer(); | ||
241 | } | ||
242 | |||
243 | private string loggedOnPage(string body, Hashtable fields) | ||
244 | { | ||
245 | return header(ssi["grid"] + " account") | ||
246 | + "<h1>" + ssi["grid"] + " account for " + fields["firstName"].ToString() + " " + fields["lastName"].ToString() + "</h1>" | ||
247 | + form("account.html", fields["token"].ToString(), | ||
248 | hidden("firstName", fields["firstName"].ToString()) | ||
249 | + hidden("lastName", fields["lastName"].ToString()) | ||
250 | // + hidden("UUID", fields["UUID"].ToString()) | ||
251 | + text("email", "email", "email", fields["email"].ToString(), 0, false) | ||
252 | + text("password", "password", "password", "", 14, false) | ||
253 | // + text("title", "text", "title", fields["title"].ToString(), 0, false) | ||
254 | + select("type", "type", | ||
255 | option("", false) | ||
256 | + option("approved", true) | ||
257 | + option("disabled", false) | ||
258 | + option("god", false) | ||
259 | ) | ||
260 | + button("delete") | ||
261 | + button("list") | ||
262 | + button("logout") | ||
263 | // + button("read") | ||
264 | + button("update") | ||
265 | ) | ||
266 | + body | ||
267 | + footer(); | ||
268 | } | ||
269 | |||
270 | private string header(string title) | ||
271 | { | ||
272 | return "<html>\n <head>\n <title>" + title + "</title>\n </head>\n <body>\n"; | ||
273 | } | ||
274 | |||
275 | private string table(List< Hashtable > rows, string[] fields, string caption, string URL, string id) | ||
276 | { | ||
277 | string tbl = "<table border=\"1\"><caption>" + caption + "</caption>"; | ||
278 | bool head = true; | ||
279 | string address = ""; | ||
280 | string addrend = ""; | ||
281 | foreach (Hashtable row in rows) | ||
282 | { | ||
283 | if (0 == fields.Length) | ||
284 | { | ||
285 | int c = 0; | ||
286 | foreach (DictionaryEntry r in row) | ||
287 | c++; | ||
288 | fields = new string[c]; | ||
289 | c = 0; | ||
290 | foreach (DictionaryEntry r in row) | ||
291 | fields[c++] = (string) r.Key; | ||
292 | } | ||
293 | string line = "<tr>"; | ||
294 | address = ""; | ||
295 | if ("" != URL) | ||
296 | { | ||
297 | address = "<a href=\"" + URL; | ||
298 | addrend = "</a>"; | ||
299 | } | ||
300 | if ("" != id) | ||
301 | address = address + "&" + id + "=" + row[id] + "\">"; | ||
302 | if (head) | ||
303 | { | ||
304 | foreach (string s in fields) | ||
305 | line = line + "<th>" + s + "</th>"; | ||
306 | tbl = tbl + line + "</tr>\n"; | ||
307 | head = false; | ||
308 | } | ||
309 | line = "<tr>"; | ||
310 | foreach (string s in fields) | ||
311 | { | ||
312 | if (s == id) | ||
313 | line = line + "<td>" + address + row[s] + addrend + "</td>"; | ||
314 | else | ||
315 | line = line + "<td>" + row[s] + "</td>"; | ||
316 | } | ||
317 | tbl = tbl + line + "</tr>\n"; | ||
318 | } | ||
319 | return tbl + "</table>"; | ||
320 | } | ||
321 | |||
322 | private string form(string action, string token, string form) | ||
323 | { | ||
324 | return " <form action=\"" + action + "\" method=\"POST\">\n" + hidden("token", token) + form + " </form>\n"; | ||
325 | } | ||
326 | |||
327 | private string hidden(string name, string val) | ||
328 | { | ||
329 | return " <input type=\"hidden\" name=\"" + name + "\" value=\"" + val + "\">\n"; | ||
330 | } | ||
331 | |||
332 | private string text(string type, string title, string name, string val, int max, bool required) | ||
333 | { | ||
334 | string extra = ""; | ||
335 | if (0 < max) | ||
336 | extra = extra + " maxlength=\"" + max.ToString() + "\""; | ||
337 | if (required) | ||
338 | extra = extra + " required"; | ||
339 | if ("" != val) | ||
340 | val = "value=\"" + val + "\""; | ||
341 | return " <p>" + title + " : <input type=\"" + type + "\" name=\"" + name + "\"" + val + extra + "></p>\n"; | ||
342 | } | ||
343 | |||
344 | private string select(string title, string name, string options) | ||
345 | { | ||
346 | return " <p>" + title + " : \n <select name=\"" + name + "\">\n" + options + " </select>\n </p>\n"; | ||
347 | } | ||
348 | |||
349 | private string option(string title, bool selected) | ||
350 | { | ||
351 | string sel = ""; | ||
352 | if (selected) | ||
353 | sel = " selected"; | ||
354 | return " <option value=\"" + title + "\"" + sel + ">" + title + "</option>\n"; | ||
355 | } | ||
356 | |||
357 | private string button(string title) | ||
358 | { | ||
359 | return " <button type=\"submit\" name=\"doit\" value=\"" + title + "\">" + title + "</button>\n"; | ||
360 | } | ||
361 | |||
362 | private string footer() | ||
363 | { | ||
364 | return " </body>\n</html>\n"; | ||
365 | } | ||
366 | |||
367 | } | ||
368 | } | ||