aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authoronefang2022-06-04 09:49:14 +1000
committeronefang2022-06-04 09:49:14 +1000
commit7e848f1e72a3717ae524d912e370c207b0e79c57 (patch)
treed016ebe8b91479c0358e722ed6bc97aeb1961df0
parentAdd a web option to sledjchisl, to start the web stuff. (diff)
downloadopensim-SC-7e848f1e72a3717ae524d912e370c207b0e79c57.zip
opensim-SC-7e848f1e72a3717ae524d912e370c207b0e79c57.tar.gz
opensim-SC-7e848f1e72a3717ae524d912e370c207b0e79c57.tar.bz2
opensim-SC-7e848f1e72a3717ae524d912e370c207b0e79c57.tar.xz
Add experimental XMPP chat stuff.
-rw-r--r--src/sledjchisl/sledjchisl.c263
1 files changed, 236 insertions, 27 deletions
diff --git a/src/sledjchisl/sledjchisl.c b/src/sledjchisl/sledjchisl.c
index 317d079..4f91fae 100644
--- a/src/sledjchisl/sledjchisl.c
+++ b/src/sledjchisl/sledjchisl.c
@@ -140,6 +140,9 @@ extern char **environ;
140#include "lib/fcgi_SC.h" 140#include "lib/fcgi_SC.h"
141#include "lib/handlekeys.h" 141#include "lib/handlekeys.h"
142 142
143#include "lib/json.h"
144#include "lib/json-builder.h"
145
143// Both my_config.h and fcgi_config.h define the same PACKAGE* variables, which we don't use anyway, 146// Both my_config.h and fcgi_config.h define the same PACKAGE* variables, which we don't use anyway,
144// I deal with that by using a sed invokation when building fcgi2. 147// I deal with that by using a sed invokation when building fcgi2.
145 148
@@ -518,7 +521,7 @@ static void showSesh(qgrow_t *reply, sesh *shs)
518} 521}
519 522
520 523
521char toybuf[4096]; 524//char toybuf[4096];
522lua_State *L; 525lua_State *L;
523qhashtbl_t *configs; 526qhashtbl_t *configs;
524MYSQL *database, *dbconn; 527MYSQL *database, *dbconn;
@@ -548,6 +551,7 @@ int startPort = 8002;
548char *backupIARsim = "Sandbox"; 551char *backupIARsim = "Sandbox";
549char *rSync = ""; 552char *rSync = "";
550int rSyncPort = 0; 553int rSyncPort = 0;
554char *webHost = "localhost";
551char *webRoot = "/var/www/html"; 555char *webRoot = "/var/www/html";
552char *webSocket = "sledjchisl.socket"; 556char *webSocket = "sledjchisl.socket";
553char *ToS = "Be good."; 557char *ToS = "Be good.";
@@ -808,6 +812,87 @@ char *myHMACkey(char *key, char *in, boolean b64)
808} 812}
809 813
810 814
815static void print_depth_shift(int depth)
816{
817 int j;
818 for (j=0; j < depth; j++) {
819 printf(" ");
820 }
821}
822static void process_value(json_value* value, int depth);
823static void process_object(json_value* value, int depth)
824{
825 int length, x;
826 if (value == NULL) {
827 return;
828 }
829 length = value->u.object.length;
830 for (x = 0; x < length; x++) {
831 print_depth_shift(depth);
832 printf("object[%d].name = %s\n", x, value->u.object.values[x].name);
833 process_value(value->u.object.values[x].value, depth+1);
834 }
835}
836static void process_array(json_value* value, int depth)
837{
838 int length, x;
839 if (value == NULL) {
840 return;
841 }
842 length = value->u.array.length;
843 printf("array\n");
844 for (x = 0; x < length; x++) {
845 process_value(value->u.array.values[x], depth);
846 }
847}
848static void process_value(json_value* value, int depth)
849{
850 if (value == NULL) {
851 return;
852 }
853 if (value->type != json_object) {
854 print_depth_shift(depth);
855 }
856 switch (value->type) {
857 case json_none:
858 printf("none\n");
859 break;
860 case json_null:
861 printf("null\n");
862 break;
863 case json_object:
864 process_object(value, depth+1);
865 break;
866 case json_array:
867 process_array(value, depth+1);
868 break;
869 case json_integer:
870 printf("int: %10ld\n", (long)value->u.integer);
871 break;
872 case json_double:
873 printf("double: %f\n", value->u.dbl);
874 break;
875 case json_string:
876 printf("string: %s\n", value->u.string.ptr);
877 break;
878 case json_boolean:
879 printf("bool: %d\n", value->u.boolean);
880 break;
881 }
882}
883void PrintJSON(json_char* json)
884{
885 json_value* value = json_parse(json, strlen((char *) json));
886
887 if (value == NULL)
888 {
889 E("Unable to parse data! - %s", (char *) json);
890 return;
891 }
892 process_value(value, 0);
893 json_value_free(value);
894}
895
811// In Lua 5.0 reference manual is a table traversal example at page 29. 896// In Lua 5.0 reference manual is a table traversal example at page 29.
812void PrintTable(lua_State *L) 897void PrintTable(lua_State *L)
813{ 898{
@@ -4626,8 +4711,17 @@ static void HTMLheader(qgrow_t *reply, char *title)
4626 " <head>\n" 4711 " <head>\n"
4627 " <title>%s</title>\n" 4712 " <title>%s</title>\n"
4628 " <meta charset=\"UTF-8\">\n" 4713 " <meta charset=\"UTF-8\">\n"
4714 " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"
4715 " <meta name=\"viewport\" content=\"width=device-width, initial-scale=0.5\" />\n"
4716// " <meta name=\"description\" content=\"Converse XMPP/Jabber Chat\"/>\n"
4717// " <meta name=\"author\" content=\"JC Brand\" />\n"
4718 " <link rel=\"manifest\" href=\"/converse.js/manifest.json\">\n"
4719 " <link type='text/css' rel='stylesheet' href='/converse.js/dist/converse.min.css' media='screen' />\n"
4720 " <script src='/converse.js/3rdparty/libsignal-protocol.min.js'></script>\n"
4721 " <script src='/converse.js/dist/converse.min.js'></script>\n"
4629 " <link rel=\"shortcut icon\" href=\"/SledjHamrIconSmall.png\">\n" 4722 " <link rel=\"shortcut icon\" href=\"/SledjHamrIconSmall.png\">\n"
4630 " <link type='text/css' rel='stylesheet' href='/SledjChisl.css' media='all' />\n" 4723 " <link type='text/css' rel='stylesheet' href='/SledjChisl.css' media='all' />\n"
4724
4631 , title); 4725 , title);
4632 4726
4633 if (DEBUG) 4727 if (DEBUG)
@@ -4635,7 +4729,7 @@ static void HTMLheader(qgrow_t *reply, char *title)
4635 4729
4636 reply->addstrf(reply, 4730 reply->addstrf(reply,
4637 " </head>\n" 4731 " </head>\n"
4638 " <body bgcolor='black' text='white' link='aqua' vlink='fuchsia' alink='red'>\n" 4732 " <body bgcolor='black' text='white' link='aqua' vlink='fuchsia' alink='red' id='page-top' data-spy='scroll' class='converse-website'>\n"
4639 " <font face='sans-serif'>\n" 4733 " <font face='sans-serif'>\n"
4640 ); 4734 );
4641 reply->addstrf(reply, " <div class='top-left'>\n"); 4735 reply->addstrf(reply, " <div class='top-left'>\n");
@@ -4979,10 +5073,10 @@ void HTMLfill(reqData *Rd, enum fragmentType type, char *text, int length)
4979 } 5073 }
4980} 5074}
4981 5075
4982static void HTMLfooter(qgrow_t *reply) 5076static void HTMLfooter(reqData *Rd)
4983{ 5077{
4984 reply->addstrf(reply, " </div>\n"); 5078 Rd->reply->addstrf(Rd->reply, " </div>\n");
4985 reply->addstr(reply, 5079 Rd->reply->addstr(Rd->reply,
4986 " <div class='top-right'>\n" 5080 " <div class='top-right'>\n"
4987 " <h1>Experimental account manager</h1>\n" 5081 " <h1>Experimental account manager</h1>\n"
4988 " <p>This account manager system is currently experimental, and under heavy development. &nbsp; " 5082 " <p>This account manager system is currently experimental, and under heavy development. &nbsp; "
@@ -4994,16 +5088,48 @@ static void HTMLfooter(qgrow_t *reply)
4994 " <p>You will then be logged off. &nbsp; Now you have to wait for an admin to approve your new account. &nbsp; " 5088 " <p>You will then be logged off. &nbsp; Now you have to wait for an admin to approve your new account. &nbsp; "
4995 " They should check with the person you listed as vouching for you first. &nbsp; They will tell you after they approve your account.</p>" 5089 " They should check with the person you listed as vouching for you first. &nbsp; They will tell you after they approve your account.</p>"
4996 " <p>Missing bits that are still being written - editing accounts, listing accounts, deleting accounts.</p>\n" 5090 " <p>Missing bits that are still being written - editing accounts, listing accounts, deleting accounts.</p>\n"
5091 " <h1>Experimental chat thingy</h1>\n"
5092 " <p>In the bottom right corner is an experimental chat thingy, based on Jabber / XMPP.</p>\n"
5093 " <p>Click on the 'Toggle chat' button to pop it up, then use your grid user name for the 'XMPP Address:' field. &nbsp; "
5094 " Your user name has to be in the format 'first.last', two words with a dot in the middle. &nbsp; "
5095 " Then put your grid account password in the 'Password' field and click the 'Log in' button. &nbsp; "
5096 " Ignore the 'Don't have a chat account? Create an account' bit.</p>\n"
5097 " <p>Note that the chat windows can be resized by dragging their top or left edges, which I suggest you do, coz the default size is too small.</p>\n"
5098 " <p>You can also use any other Jabber / XMPP client as well.</p>\n"
5099 " <p>Remember this is <b>EXPERIMENTAL</b>, I'll be changing things. &nbsp; Next I'll make it so you don't have to log in to both this chat thingy and the account page separataly.<p>"
5100 " <p>P.S. &nbsp; Yes, I hate the default theme to. &nbsp; lol</p>\n"
4997 " </div>\n"); 5101 " </div>\n");
4998// reply->addstr(reply, " <div class='centre'>\n </div>\n"); 5102// Rd->reply->addstr(Rd->reply, " <div class='centre'>\n </div>\n");
4999 reply->addstr(reply, 5103 Rd->reply->addstrf(Rd->reply,
5000// " <div class='bottom-left'>\n" 5104 " <div class='bottom-left'>\n"
5001// " </div>\n"
5002 " <div class='bottom-right'>\n"
5003 " <iframe src='stats.html' style='border:none;height:100%;width:100%;'></iframe>\n" 5105 " <iframe src='stats.html' style='border:none;height:100%;width:100%;'></iframe>\n"
5004 " </div>\n" 5106 " </div>\n"
5107 " <div class='bottom-right'>\n"
5108 " </div>\n"
5005 " </font>\n" 5109 " </font>\n"
5006 "</body>\n</html>\n"); 5110 "</body>\n"
5111
5112 "<script>\n"
5113 " converse.initialize({\n"
5114 " assets_path: '/converse.js/dist/',\n"
5115 " bosh_service_url: 'https://%s:5281/http-bind/',\n"
5116 " view_mode: 'overlayed',\n"
5117 " default_domain: '%s',\n"
5118 " muc_clear_messages_on_leave: false,\n"
5119 " muc_domain: 'chat.%s',\n"
5120 " muc_history_max_stanzas: 0,\n"
5121 " muc_send_probes: true,\n"
5122 " notify_all_room_messages: true,\n"
5123 " notification_delay:500000,\n"
5124 " play_sounds: true,\n"
5125 " registration_domain: '%s',\n"
5126 " show_chat_state_notifications: true,\n"
5127 " show_message_avatar: false,\n"
5128 " theme: 'dracula',\n"
5129 " time_format: 'dddd YYYY-MMM-DD HH:mm:ss'\n"
5130 " });\n"
5131 "</script>\n"
5132 "</html>\n", webHost, webHost, webHost, webHost);
5007} 5133}
5008 5134
5009 5135
@@ -6995,7 +7121,7 @@ static void accountWebFooter(reqData *Rd, inputForm *oF)
6995 if (0 != Rd->errors->size(Rd->errors)) 7121 if (0 != Rd->errors->size(Rd->errors))
6996 HTMLlist(Rd->reply, "errors -", Rd->errors); 7122 HTMLlist(Rd->reply, "errors -", Rd->errors);
6997 HTMLformEnd(Rd->reply); 7123 HTMLformEnd(Rd->reply);
6998 HTMLfooter(Rd->reply); 7124 HTMLfooter(Rd);
6999} 7125}
7000 7126
7001static void accountAddWeb(reqData *Rd, inputForm *oF, inputValue *oV) 7127static void accountAddWeb(reqData *Rd, inputForm *oF, inputValue *oV)
@@ -7176,6 +7302,8 @@ static int accountRead(reqData *Rd, char *uuid, char *firstName, char *lastName)
7176d("accountRead() single name |%s| |%s|", first, last); 7302d("accountRead() single name |%s| |%s|", first, last);
7177 if (NULL == t) 7303 if (NULL == t)
7178 t = strchr(first, '+'); 7304 t = strchr(first, '+');
7305 if (NULL == t)
7306 t = strchr(first, '.');
7179 if (NULL != t) 7307 if (NULL != t)
7180 { 7308 {
7181 *t++ = '\0'; 7309 *t++ = '\0';
@@ -8344,6 +8472,47 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
8344 C("Ending dynamic page %s %s", Rd->RUri, form); 8472 C("Ending dynamic page %s %s", Rd->RUri, form);
8345} 8473}
8346 8474
8475// TODO - This is arse about, I get JSON, but send plain text. Need to set content type ehaders in the mod_auth_custom_http, and maybe send json back as well.
8476void prosody_mod_auth_custom_http_json(char *file, reqData *Rd, HTMLfile *thisFile)
8477{
8478 char *user = getStrH(Rd->body, "username"), *password = getStrH(Rd->body, "password");
8479 int c = accountRead(Rd, NULL, user, NULL);
8480
8481 C("Starting dynamic page %s [ %s ]", Rd->RUri, user);
8482// TODO - check it's HTTPS, and check it came from the same server. Same as account,html does, except no external iFrame allowed this time maybe.
8483// On the other hand, prosody can't handle 301 redirections?
8484
8485 if (1 != c)
8486 bitch(Rd, "Cannot validate account.", "Account doesn't exist.");
8487 else
8488 {
8489 char *salt = getStrH(Rd->database, "auth.passwordSalt"), *hash = getStrH(Rd->database, "auth.passwordHash");
8490
8491 c = 0;
8492 if ((NULL == password) || ('\0' == password[0]))
8493 bitch(Rd, "Cannot validate account.", "No password supplied.");
8494 else if (('\0' != salt[0]) && ('\0' != hash[0]))
8495 {
8496 D("Comparing passwords. %s %s %s", password, salt, hash);
8497 char *h = checkSLOSpassword(Rd, salt, password, hash, "Passwords are not the same.");
8498
8499 if (NULL == h)
8500 bitch(Rd, "Cannot validate account.", "Passwords are not the same.");
8501 else
8502 {
8503 I("Authenticated XMPP user %s@%s", user, Rd->Host);
8504 c = 1;
8505 free(h);
8506 }
8507 }
8508 else
8509 bitch(Rd, "Cannot validate account.", "No salted hash.");
8510 }
8511
8512 Rd->reply->addstrf(Rd->reply, (1 == c) ? "true" : "false");
8513 C("Ending dynamic page %s", Rd->RUri);
8514}
8515
8347 8516
8348void forEachMember(char *verb, simFunction func, simFunction not) 8517void forEachMember(char *verb, simFunction func, simFunction not)
8349{ 8518{
@@ -8550,6 +8719,7 @@ int scanForConfigs(char **cPaths)
8550 if ((tmp = configs->getstr(configs, "backupIARsim", false)) != NULL) {backupIARsim = tmp; D("Setting backupIARsim = %s", backupIARsim);} 8719 if ((tmp = configs->getstr(configs, "backupIARsim", false)) != NULL) {backupIARsim = tmp; D("Setting backupIARsim = %s", backupIARsim);}
8551 if ((tmp = configs->getstr(configs, "rsync", false)) != NULL) {rSync = tmp; D("Setting rsync = %s", rSync);} 8720 if ((tmp = configs->getstr(configs, "rsync", false)) != NULL) {rSync = tmp; D("Setting rsync = %s", rSync);}
8552 if ((vd = configs->getstr(configs, "rsyncPort", false)) != NULL) {rSyncPort = (int) *((float *) vd); D("Setting rsyncPort = %d", rSyncPort);} 8721 if ((vd = configs->getstr(configs, "rsyncPort", false)) != NULL) {rSyncPort = (int) *((float *) vd); D("Setting rsyncPort = %d", rSyncPort);}
8722 if ((tmp = configs->getstr(configs, "webHost", false)) != NULL) {webHost = tmp; D("Setting webHost = %s", webHost);}
8553 if ((tmp = configs->getstr(configs, "webRoot", false)) != NULL) {webRoot = tmp; D("Setting webRoot = %s", webRoot);} 8723 if ((tmp = configs->getstr(configs, "webRoot", false)) != NULL) {webRoot = tmp; D("Setting webRoot = %s", webRoot);}
8554 if ((tmp = configs->getstr(configs, "webSocket", false)) != NULL) {webSocket = tmp; D("Setting webSocket = %s", webSocket);} 8724 if ((tmp = configs->getstr(configs, "webSocket", false)) != NULL) {webSocket = tmp; D("Setting webSocket = %s", webSocket);}
8555 if ((vd = configs->get (configs, "seshRenew", NULL, false)) != NULL) {seshRenew = (int) *((float *) vd); D("Setting seshRenew = %d", seshRenew);} 8725 if ((vd = configs->get (configs, "seshRenew", NULL, false)) != NULL) {seshRenew = (int) *((float *) vd); D("Setting seshRenew = %d", seshRenew);}
@@ -9362,11 +9532,12 @@ V("Doing %s for %s '%s' %s %s", modeStrings[currentMode], FLAG(m) ? "member" :
9362// Start of web wrangling section. 9532// Start of web wrangling section.
9363//////////////////////////////////////////////////////////////////////////////////////////////////// 9533////////////////////////////////////////////////////////////////////////////////////////////////////
9364 char **initialEnv = environ; 9534 char **initialEnv = environ;
9365 char *tmp0, *tmp1; 9535 char *tmp0, *tmp1, *type;
9366 int count = 0, entries, bytes; 9536 int count = 0, entries, bytes;
9367 9537
9368 dynPages = qhashtbl(0, 0); 9538 dynPages = qhashtbl(0, 0);
9369 newDynPage("account.html", (pageFunction) account_html); 9539 newDynPage("account.html", (pageFunction) account_html);
9540 newDynPage("prosody_mod_auth_custom_http.json", (pageFunction) prosody_mod_auth_custom_http_json);
9370 9541
9371 // FCGI_LISTENSOCK_FILENO is the socket to the web server. 9542 // FCGI_LISTENSOCK_FILENO is the socket to the web server.
9372 // STDOUT and STDERR go to the web servers error log, or at least it does in Apache 2 mod_fcgid. 9543 // STDOUT and STDERR go to the web servers error log, or at least it does in Apache 2 mod_fcgid.
@@ -9492,6 +9663,14 @@ t("ignoring QUERY");
9492 Rd->RUri = xmprintf("%s%s", Rd->Script, Rd->Path); 9663 Rd->RUri = xmprintf("%s%s", Rd->Script, Rd->Path);
9493 } 9664 }
9494t("BODY"); 9665t("BODY");
9666
9667// TODO - is there any sort of content type on the incoming request headers I could maybe use here?
9668 memset(toybuf, 0, sizeof(toybuf));
9669 snprintf(toybuf, sizeof(toybuf), "%s%s%s", scRoot, webRoot, Rd->Path);
9670 tmp0 = qfile_get_ext(toybuf);
9671 type = mimeTypes->getstr(mimeTypes, tmp0, false);
9672 free(tmp0);
9673
9495 char *Body = NULL; 9674 char *Body = NULL;
9496 if (Length != NULL) 9675 if (Length != NULL)
9497 { 9676 {
@@ -9499,16 +9678,51 @@ t("BODY");
9499 Body = xmalloc(len + 1); 9678 Body = xmalloc(len + 1);
9500 int c = FCGI_fread(Body, 1, len, FCGI_stdin); 9679 int c = FCGI_fread(Body, 1, len, FCGI_stdin);
9501 if (c != len) 9680 if (c != len)
9502 {
9503 E("Tried to read %d of the body, only got %d!", len, c); 9681 E("Tried to read %d of the body, only got %d!", len, c);
9504 }
9505 Body[len] = '\0'; 9682 Body[len] = '\0';
9506 } 9683 }
9507 else 9684 else
9508 Length = "0"; 9685 {
9509 Rd->body = toknize(Body, "=&"); 9686 Length = "0";
9687 Body = xmalloc(1);
9688 Body[0] = '\0';
9689 }
9690 if (strcmp("application/json", type) == 0)
9691 {
9692 json_char *json = (json_char*) Body;
9693 json_value* value = json_parse(json, strtol(Length, NULL, 10));
9694
9695 Rd->body = qhashtbl(0, 0);
9696 if (value == NULL)
9697 E("Unable to parse NULL data!");
9698 else
9699 {
9700// PrintJSON(json);
9701 if (value->type == json_object)
9702 {
9703 int length = value->u.object.length, x;
9704
9705 for (x = 0; x < length; x++)
9706 {
9707 char *name = value->u.object.values[x].name;
9708
9709 if (value->u.object.values[x].value->type == json_string)
9710 {
9711 D("%s = %s", name, value->u.object.values[x].value->u.string.ptr);
9712 Rd->body->putstr(Rd->body, name, value->u.object.values[x].value->u.string.ptr);
9713 }
9714
9715 }
9716 }
9717 }
9718 json_value_free(value);
9719 }
9720 else
9721 {
9722 Rd->body = toknize(Body, "=&");
9723 santize(Rd->body);
9724 }
9510 free(Body); 9725 free(Body);
9511 santize(Rd->body);
9512 9726
9513 D("%s %s://%s%s -> %s%s%s", Rd->Method, Rd->Scheme, Rd->Host, Rd->RUri, scRoot, webRoot, Rd->Path); 9727 D("%s %s://%s%s -> %s%s%s", Rd->Method, Rd->Scheme, Rd->Host, Rd->RUri, scRoot, webRoot, Rd->Path);
9514 D("Started FCGI web request ROLE = %s, body is %s bytes, pid %d.", Role, Length, getpid()); 9728 D("Started FCGI web request ROLE = %s, body is %s bytes, pid %d.", Role, Length, getpid());
@@ -9555,10 +9769,10 @@ t("BODY");
9555 // Content-Security-Policy can get complex, and I first wrote that when it was very simple. lol 9769 // Content-Security-Policy can get complex, and I first wrote that when it was very simple. lol
9556 if ('\0' != webIframers[0]) 9770 if ('\0' != webIframers[0])
9557 Rd->Rheaders->putstrf(Rd->Rheaders, "Content-Security-Policy", 9771 Rd->Rheaders->putstrf(Rd->Rheaders, "Content-Security-Policy",
9558 "default-src 'self'; script-src 'none'; form-action 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self' %s", webIframers); 9772 "default-src 'self'; script-src 'self' 'unsafe-inline'; form-action 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self' %s; connect-src 'self' %s:5281/http-bind/;", webIframers, webHost);
9559 else 9773 else
9560 { 9774 {
9561 Rd->Rheaders->putstr(Rd->Rheaders, "Content-Security-Policy", "default-src 'self'; script-src 'none'; form-action 'self'; style-src 'self' 'unsafe-inline'"); 9775 Rd->Rheaders->putstrf(Rd->Rheaders, "Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline'; form-action 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' %s:5281/http-bind/;", webHost);
9562 Rd->Rheaders->putstr(Rd->Rheaders, "X-Frame-Options", "SAMEORIGIN"); // This is deprecated, and is an all or nothing thing. 9776 Rd->Rheaders->putstr(Rd->Rheaders, "X-Frame-Options", "SAMEORIGIN"); // This is deprecated, and is an all or nothing thing.
9563 } 9777 }
9564 Rd->Rheaders->putstr(Rd->Rheaders, "X-XSS-Protection", "1;mode=block"); 9778 Rd->Rheaders->putstr(Rd->Rheaders, "X-XSS-Protection", "1;mode=block");
@@ -9573,8 +9787,6 @@ t("BODY");
9573 goto sendReply; 9787 goto sendReply;
9574 } 9788 }
9575 9789
9576 memset(toybuf, 0, sizeof(toybuf));
9577 snprintf(toybuf, sizeof(toybuf), "%s%s%s", scRoot, webRoot, Rd->Path);
9578 HTMLfile *thisFile = checkHTMLcache(toybuf); 9790 HTMLfile *thisFile = checkHTMLcache(toybuf);
9579 if (NULL == thisFile) 9791 if (NULL == thisFile)
9580 { 9792 {
@@ -9597,12 +9809,9 @@ t("BODY");
9597goto sendReply; 9809goto sendReply;
9598 } 9810 }
9599 9811
9600 tmp0 = qfile_get_ext(toybuf); 9812 if (NULL != type)
9601 tmp1 = mimeTypes->getstr(mimeTypes, tmp0, false);
9602 free(tmp0);
9603 if (NULL != tmp1)
9604 { 9813 {
9605 if (strncmp("text/", tmp1, 5) != 0) 9814 if (strncmp("text/", type, 5) != 0)
9606 { 9815 {
9607 E("Only text formats are supported - %s", toybuf); 9816 E("Only text formats are supported - %s", toybuf);
9608 Rd->Rheaders->putstr(Rd->Rheaders, "Status", "415 Unsupported Media Type"); 9817 Rd->Rheaders->putstr(Rd->Rheaders, "Status", "415 Unsupported Media Type");