1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00

v2.10.3.1

This commit is contained in:
gnosygnu
2015-10-18 22:17:57 -04:00
parent 8e18af05b6
commit 4f43f51b18
1935 changed files with 12500 additions and 12889 deletions

View File

@@ -0,0 +1,36 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*;
class File_retrieve_mode {
public static String Xto_str(byte v) {
switch (v) {
case Mode_skip: return "skip";
case Mode_wait: return "wait";
case Mode_async_server: return "async_server";
default: throw Err_.new_unimplemented();
}
}
public static byte Xto_byte(String s) {
if (String_.Eq(s, "skip")) return Mode_skip;
else if (String_.Eq(s, "wait")) return Mode_wait;
else if (String_.Eq(s, "async_server")) return Mode_async_server;
else throw Err_.new_unimplemented();
}
public static final byte Mode_skip = 1, Mode_wait = 2, Mode_async_server = 3;
public static KeyVal[] Options__list = KeyVal_.Ary(KeyVal_.new_("wait"), KeyVal_.new_("skip"), KeyVal_.new_("async_server", "async server"));
}

View File

@@ -0,0 +1,27 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*;
import gplx.langs.jsons.*;
public class Http_data__client {
public Http_data__client(byte[] server_host, String ip_address_str) {
this.server_host = server_host;
this.ip_address = Bry_.new_a7(ip_address_str);
}
public byte[] Server_host() {return server_host;} private final byte[] server_host;
public byte[] Ip_address() {return ip_address;} private final byte[] ip_address;
}

View File

@@ -0,0 +1,141 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This file is part of XOWA: the XOWA Offline Wiki Application
Copyright (C) 2013 matthiasjasny@gmail.com
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*;
import gplx.core.threads.*; import gplx.core.net.*; import gplx.core.primitives.*; import gplx.langs.jsons.*; import gplx.langs.htmls.encoders.*;
import gplx.xowa.wikis.pages.*;
public class Http_server_mgr implements GfoInvkAble {
private final Object thread_lock = new Object();
private final Gfo_usr_dlg usr_dlg;
private Http_server_socket wkr;
private byte retrieve_mode = File_retrieve_mode.Mode_wait;
private boolean running, init_gui_done;
public Http_server_mgr(Xoae_app app) {
this.app = app;
this.usr_dlg = app.Usr_dlg();
this.request_parser = new Http_request_parser(server_wtr, false);
}
public Xoae_app App() {return app;} private final Xoae_app app;
public Http_server_wtr Server_wtr() {return server_wtr;} private final Http_server_wtr server_wtr = Http_server_wtr_.new_console();
public Http_request_parser Request_parser() {return request_parser;} private final Http_request_parser request_parser;
public Url_encoder Encoder() {return encoder;} private final Url_encoder encoder = Url_encoder.new_http_url_();
public int Port() {return port;} public Http_server_mgr Port_(int v) {port = v; return this;} private int port = 8080;
public Http_server_wkr_pool Wkr_pool() {return wkr_pool;} private final Http_server_wkr_pool wkr_pool = new Http_server_wkr_pool();
public Int_pool Uid_pool() {return uid_pool;} private final Int_pool uid_pool = new Int_pool();
public byte[] Home() {return home;} public void Home_(byte[] v) {home = Bry_.Add(Byte_ascii.Slash_bry, v);} private byte[] home = Bry_.new_a7("/home/wiki/Main_Page");
private void Init_gui() { // create a shim gui to automatically handle default XOWA gui JS calls
if (init_gui_done) return;
init_gui_done = true;
Gxw_html_server.Init_gui_for_server(app, null);
}
private void Running_(boolean val) {
if (val) {
if (running)
Note("HTTP Server already started");
else {
Run();
}
}
else {
if (running) {
wkr.Canceled_(true);
wkr = null;
Note("HTTP Server stopped");
}
else
Note("HTTP Server not started");
}
running = val;
}
public void Run() {
if (wkr == null) wkr = new Http_server_socket(this);
Thread_adp_.invk_("thread:xowa.http_server.server", wkr, Http_server_socket.Invk_run).Start();
Note("HTTP Server started: Navigate to http://localhost:" + Int_.To_str(port));
}
public void Run_xowa_cmd(Xoae_app app, String url_encoded_str) {
Url_encoder url_converter = Url_encoder.new_http_url_(); // create instance for each call
String cmd = url_converter.Decode_str(url_encoded_str);
app.Gfs_mgr().Run_str(cmd);
}
public String Parse_page_to_html(Http_data__client data__client, byte[] wiki_domain, byte[] page_ttl) {
synchronized (thread_lock) {
Init_gui();
Xowe_wiki wiki = (Xowe_wiki)app.Wiki_mgr().Get_by_key_or_make_init_y(wiki_domain); // get the wiki; assert init for Main_Page; EX:click zh.w on wiki sidebar; DATE:2015-07-19
if (Env_.System_memory_total() > Io_mgr.Len_gb) Xow_wiki_.Rls_mem(wiki, true); // release memory at 1 GB; DATE:2015-09-11
if (Bry_.Len_eq_0(page_ttl)) page_ttl = wiki.Props().Main_page();
Xoa_url page_url = wiki.Utl__url_parser().Parse(page_ttl); // get the url (needed for query args)
Xoa_ttl ttl = Xoa_ttl.parse(wiki, page_ttl); // get the ttl
Xoae_page page = wiki.Data_mgr().Load_page_by_ttl(page_url, ttl); // get page and parse it
Gxw_html_server.Assert_tab(app, page); // HACK: assert at least 1 tab
app.Gui_mgr().Browser_win().Active_page_(page); // HACK: init gui_mgr's page for output (which server ordinarily doesn't need)
if (page.Missing()) { // if page does not exist, replace with message; else null_ref error; DATE:2014-03-08
page.Data_raw_(Bry_.new_a7("'''Page not found.'''"));
wiki.Parser_mgr().Parse(page, false);
}
page.Html_data().Head_mgr().Itm__server().Init_by_http(data__client).Enabled_y_();
byte[] output_html = wiki.Html_mgr().Page_wtr_mgr().Gen(page, Xopg_page_.Tid_read); // write html from page data
switch (retrieve_mode) {
case File_retrieve_mode.Mode_skip: break; // noop
case File_retrieve_mode.Mode_async_server: app.Gui_mgr().Browser_win().Page__async__bgn(page.Tab_data().Tab()); break;
case File_retrieve_mode.Mode_wait:
if (page.File_queue().Count() > 0) {
app.Gui_mgr().Browser_win().Active_tab().Async();
output_html = wiki.Html_mgr().Page_wtr_mgr().Gen(page, Xopg_page_.Tid_read);
}
break;
}
return String_.new_u8(output_html);
}
}
private void Note(String s) {
// usr_dlg.Prog_many("", "", s); // messages should write to progress bar for gui
usr_dlg.Note_many("", "", s);
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_port)) return port;
else if (ctx.Match(k, Invk_port_)) Port_(m.ReadInt("v"));
else if (ctx.Match(k, Invk_running)) return Yn.To_str(running);
else if (ctx.Match(k, Invk_running_)) Running_(m.ReadYn("v"));
else if (ctx.Match(k, Invk_retrieve_mode)) return File_retrieve_mode.Xto_str(retrieve_mode);
else if (ctx.Match(k, Invk_retrieve_mode_)) retrieve_mode = File_retrieve_mode.Xto_byte(m.ReadStr("v"));
else if (ctx.Match(k, Invk_retrieve_mode_list)) return File_retrieve_mode.Options__list;
else return GfoInvkAble_.Rv_unhandled;
return this;
}
private static final String
Invk_port = "port", Invk_port_ = "port_"
, Invk_running = "running", Invk_running_ = "running_"
, Invk_retrieve_mode = "retrieve_mode", Invk_retrieve_mode_ = "retrieve_mode_", Invk_retrieve_mode_list = "retrieve_mode_list"
;
}

View File

@@ -0,0 +1,64 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*;
import gplx.core.net.*; import gplx.core.threads.*; import gplx.core.primitives.*;
class Http_server_socket implements GfoInvkAble {
private final Http_server_mgr server_mgr;
private Server_socket_adp server_socket;
public Http_server_socket(Http_server_mgr server_mgr) {this.server_mgr = server_mgr;}
public boolean Canceled() {return canceled;}
public Http_server_socket Canceled_(boolean v) {
canceled = v;
if (canceled) {
server_socket.Rls();
server_socket = null;
}
return this;
} private boolean canceled;
public void Run() {
if (server_socket == null) server_socket = new Server_socket_adp__base().Ctor(server_mgr.Port());
while (true) { // listen for incoming requests
Socket_adp client_socket = server_socket.Accept(); // NOTE: blocking call
int wkr_uid = -1; // NOTE: default to -1 to handle cases when http_server.max_clients is not set; DATE:2015-10-11
Http_server_wkr_pool wkr_pool = server_mgr.Wkr_pool();
if (wkr_pool.Enabled()) {
Http_server_wtr server_wtr = server_mgr.Server_wtr();
int timeout = wkr_pool.Timeout();
boolean print_msg = true;
while (wkr_pool.Full()) {
if (print_msg) {
print_msg = false;
server_wtr.Write_str_w_nl("maximum # of concurrent connections reached; max=" + wkr_pool.Max() + " timeout=" + timeout);
}
Thread_adp_.Sleep(timeout);
}
wkr_uid = server_mgr.Uid_pool().Get_next();
wkr_pool.Add(wkr_uid);
// server_wtr.Write_str_w_nl("added new worker; uid=" + wkr_uid);
}
Http_server_wkr_v2 wkr = new Http_server_wkr_v2(server_mgr, wkr_uid);
wkr.Init_by_thread(client_socket);
Thread_adp_.invk_("thread:xowa.http_server.client", wkr, Http_server_wkr_v2.Invk_run).Start();
}
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_run)) this.Run();
else return GfoInvkAble_.Rv_unhandled;
return this;
} public static final String Invk_run = "run";
}

View File

@@ -0,0 +1,39 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*;
import gplx.xowa.wikis.domains.*; import gplx.xowa.langs.*;
class Http_server_wkr_ {
public static String Assert_main_page(Xoae_app app, String req) {
int mode = -1;
String[] req_array = String_.Split(req, "/");
if (String_.Has_at_end(req, "wiki/")) mode = 0;
else if (String_.Has_at_end(req, "wiki")) mode = 1;
else if (req_array.length == 3) mode = 2;
if (mode == -1) return req; // not a link to a Main Page; EX:localhost:8080/en.wikipedia.org/wiki/Earth
if (req_array.length < 3) return req; // shouldn't happen; EX: "localhost:8080wiki"
byte[] wiki_domain = Bry_.new_u8(req_array[1]);
Xow_domain_itm domain_itm = Xow_domain_itm_.parse(wiki_domain);
if (domain_itm.Domain_type_id() == Xow_domain_tid_.Int__other && domain_itm.Lang_actl_itm().Id() == Xol_lang_stub_.Id__intl) return req;
Xowe_wiki wiki = app.Wiki_mgr().Get_by_key_or_make(wiki_domain);
wiki.Init_assert();
String main_page = String_.new_u8(wiki.Props().Main_page());
if (mode == 1) main_page = "/" + main_page;
else if (mode == 2) main_page = "wiki/" + main_page;
return req + main_page;
}
}

View File

@@ -0,0 +1,42 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*;
import org.junit.*;
public class Http_server_wkr__tst {
@Before public void init() {fxt.Clear();} private Http_server_wkr__fxt fxt = new Http_server_wkr__fxt();
@Test public void Assert_main_page() {
fxt.Init_wiki_main_page("fr.wikiversity.org", "Accueil");
fxt.Test_assert_main_page("/fr.wikiversity.org/" , "/fr.wikiversity.org/wiki/Accueil");
fxt.Test_assert_main_page("/fr.wikiversity.org/wiki" , "/fr.wikiversity.org/wiki/Accueil");
fxt.Test_assert_main_page("/fr.wikiversity.org/wiki/" , "/fr.wikiversity.org/wiki/Accueil");
fxt.Test_assert_main_page("/fr.wikiversity.org/wiki/A" , "/fr.wikiversity.org/wiki/A");
}
}
class Http_server_wkr__fxt {
private Xoae_app app;
public void Clear() {
this.app = Xoa_app_fxt.app_();
}
public void Init_wiki_main_page(String domain, String main_page) {
Xowe_wiki wiki = app.Wiki_mgr().Get_by_key_or_make(Bry_.new_u8(domain));
wiki.Props().Main_page_(Bry_.new_u8(main_page));
}
public void Test_assert_main_page(String url, String expd) {
Tfds.Eq(expd, Http_server_wkr_.Assert_main_page(app, url));
}
}

View File

@@ -0,0 +1,43 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*;
import gplx.core.primitives.*;
public class Http_server_wkr_pool {
private final Ordered_hash hash = Ordered_hash_.New(); private final Int_obj_ref hash_key = Int_obj_ref.neg1_();
public boolean Enabled() {return max != 0;}
public int Max() {return max;} private int max;
public int Timeout() {return timeout;} private int timeout;
public int Len() {return len;} private int len;
public boolean Full() {return len >= max;}
public void Init(int max, int timeout) {this.max = max; this.timeout = timeout;}
public void Add(int uid) {
if (max == 0) return; // disabled
synchronized (hash) {
Int_obj_ref wkr_key = Int_obj_ref.new_(uid);
hash.Add(wkr_key, wkr_key);
++len;
}
}
public void Del(int uid) {
if (max == 0) return; // disabled
synchronized (hash) {
hash.Del(hash_key.Val_(uid));
--len;
}
}
}

View File

@@ -0,0 +1,173 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*;
import gplx.core.net.*; import gplx.core.threads.*; import gplx.langs.htmls.encoders.*;
import java.io.*;
import java.net.*;
import java.nio.charset.Charset;
class Http_server_wkr_v1 implements Runnable{
private static final String CRLF = "\r\n";
private Socket socket;
private Xoae_app app;
private String app_root_dir;
public Http_server_wkr_v1(Socket socket, Xoae_app app){
this.socket = socket;
this.app = app;
this.app_root_dir = app.Fsys_mgr().Root_dir().To_http_file_str();
}
public void run(){
String err_line = "00";
try {
InputStream is = socket.getInputStream(); err_line = "01";
DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); err_line = "02";
BufferedReader br = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); err_line = "03";
String request = br.readLine(); err_line = "04";
//System.out.println(request); err_line = "03";
String req = request.substring(4, request.length() - 9).trim(); err_line = "05";
String wiki_domain = "home"; err_line = "06";
String page_name = "Main_Page"; err_line = "07";
if(!req.contains("%file%")){
if(req.equals("/")) { // no page; EX:"localhost:8080" vs "localhost:8080/en.wikipedia.org/wiki/Earth"
String home_url = String_.new_u8(app.Http_server().Home()); err_line = "08";
if (String_.Has_at_bgn(home_url, "file://")) {
Io_url file_url = Io_url_.http_any_(home_url, Op_sys.Cur().Tid_is_wnt()); err_line = "09";
String page_html = Io_mgr.Instance.LoadFilStr(file_url); err_line = "10";
Write_page(dos, page_html, app_root_dir, wiki_domain); err_line = "11";
}
else {
req += app.Http_server().Home(); err_line = "12";
}
}
req = Http_server_wkr_.Assert_main_page(app, req); err_line = "13";
}
if(req.contains("%xowa-cmd%") || req.contains("/xowa-cmd:")){
System.out.println("Command output:"); err_line = "14";
String cmd = ""; err_line = "15";
if (req.contains("%xowa-cmd%"))
cmd = req.substring(req.indexOf("%xowa-cmd%")+20);
else
cmd = req.substring(req.indexOf("/xowa-cmd:")+10);
System.out.println(cmd); err_line = "15";
app.Http_server().Run_xowa_cmd(app, cmd); err_line = "16";
dos.writeBytes("Command sent, see console log for more details."); err_line = "17";
dos.close(); err_line = "18";
}
else if(req.contains("%file%")){
String path = req.replace("/%file%/", app_root_dir); err_line = "19";
path = path.substring(path.indexOf(app_root_dir)+5); err_line = "20";
Url_encoder url_converter = Url_encoder.new_http_url_(); err_line = "21";
path = url_converter.Decode_str(path); err_line = "22";
if(path.contains("?")){
path = path.substring(0, path.indexOf("?")); err_line = "23";
}
FileInputStream fis = new FileInputStream(path); err_line = "24";
dos.writeBytes("HTTP/1.1 200 OK: "); err_line = "25";
dos.writeBytes("Content-Type: " + contentType(path) + CRLF); err_line = "26";
dos.writeBytes(CRLF); err_line = "27";
sendBytes(fis, dos); err_line = "28";
fis.close(); err_line = "28";
dos.close(); err_line = "29";
br.close(); err_line = "30";
socket.close(); err_line = "31";
}else{
String[] req_split = req.split("/"); err_line = "32";
System.out.println("Request: " +request); err_line = "33";
if(req_split.length >= 1){
wiki_domain = req_split[1]; err_line = "34";
}
if(req_split.length >= 4){
page_name = req_split[3]; err_line = "35";
for(int i = 4; i <= req_split.length-1; i++){
page_name += "/"+req_split[i]; err_line = "36";
}
Url_encoder url_converter = Url_encoder.new_http_url_(); err_line = "37";
page_name = url_converter.Decode_str(page_name); err_line = "38";
//page_name = app.Url_converter_url().Decode_str(page_name);
}
try{
// String page_html = app.Http_server().Parse_page_to_html(app, wiki_domain, page_name); err_line = "39";
// Write_page(dos, page_html, app_root_dir, wiki_domain); err_line = "40";
}catch(Exception err) {
dos.writeBytes("Site not found. Check address please, or see console log.\n"+err.getMessage()); err_line = "41";
dos.close(); err_line = "42";
}
}
} catch (IOException e) {
e.printStackTrace();
}
catch (Exception e) {
String err_msg = String_.Format("error retrieving page. Please make sure your url is of the form: http://localhost:8080/home/wiki/Main_Page; err_msg={0} err_line={1}", e.toString(), err_line);
System.out.println(err_msg);
e.printStackTrace();
}
}
private static void Write_page(DataOutputStream strm, String page_html, String app_file_dir, String wiki_domain) {
page_html = Convert_page(page_html, app_file_dir, wiki_domain);
Write_to_stream(strm, page_html);
}
private static String Convert_page(String page_html, String app_file_dir, String wiki_domain) {
page_html = page_html.replaceAll(app_file_dir , "%file%/");
page_html = page_html.replaceAll("xowa-cmd" , "%xowa-cmd%/xowa-cmd");
page_html = page_html.replaceAll("<a href=\"/wiki/" , "<a href=\"/"+wiki_domain+"/wiki/");
page_html = page_html.replaceAll("<a href='/wiki/" , "<a href='/"+wiki_domain+"/wiki/");
page_html = page_html.replaceAll("action=\"/wiki/" , "action=\"/"+wiki_domain+"/wiki/");
page_html = page_html.replaceAll("/site" , "");
return page_html;
}
private static void Write_to_stream(DataOutputStream strm, String page_html) {
try{
strm.writeBytes("HTTP/1.1 200 OK: ");
strm.writeBytes("Content-Type: text/html; charset=utf-8" + CRLF);
// strm.writeBytes("Access-Control-Allow-Origin: *" + CRLF); // No 'Access-Control-Allow-Origin' header is present on the requested resource.
strm.writeBytes(CRLF);
strm.write(page_html.getBytes(Charset.forName("UTF-8")));
strm.close();
} catch (Exception err) {
try {
strm.writeBytes("Site not found. Check address please, or see console log.\n"+err.getMessage());
strm.close();
}
catch (Exception io_err) {}
}
}
private void sendBytes(FileInputStream fis, DataOutputStream dos) {
byte[] buffer = new byte[1024];
int bytes = 0;
try {
while((bytes= fis.read(buffer)) != -1){
dos.write(buffer, 0, bytes);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String contentType(String fileName) {
if(fileName.endsWith(".htm") || fileName.endsWith(".html"))
return "text/html";
if(fileName.endsWith(".jpg"))
return "text/jpg";
if(fileName.endsWith(".gif"))
return "text/gif";
return "application/octet-stream";
}
}

View File

@@ -0,0 +1,208 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*;
import gplx.ios.*;
import gplx.core.primitives.*; import gplx.core.net.*; import gplx.langs.htmls.encoders.*;
import gplx.xowa.apps.*;
import gplx.xowa.htmls.js.*;
class Http_server_wkr_v2 implements GfoInvkAble {
private final int uid;
private final Http_server_mgr server_mgr;
private final Http_server_wtr server_wtr;
private final Http_client_wtr client_wtr = Http_client_wtr_.new_stream();
private final Http_client_rdr client_rdr = Http_client_rdr_.new_stream();
private final Http_request_parser request_parser;
private final Url_encoder url_encoder;
private final Xoae_app app;
private final String root_dir_http;
private final byte[] root_dir_fsys;
private final Bry_bfr tmp_bfr = Bry_bfr.new_(64);
private Socket_adp socket;
private Http_data__client data__client;
public Http_server_wkr_v2(Http_server_mgr server_mgr, int uid){
this.server_mgr = server_mgr; this.uid = uid;
this.app = server_mgr.App(); this.server_wtr = server_mgr.Server_wtr(); this.url_encoder = server_mgr.Encoder();
this.root_dir_http = app.Fsys_mgr().Root_dir().To_http_file_str();
this.root_dir_fsys = Bry_.new_u8(app.Fsys_mgr().Root_dir().Raw());
this.request_parser = server_mgr.Request_parser();
}
public void Init_by_thread(Socket_adp socket) {
this.socket = socket;
}
public void Run(){
Http_request_itm request = null;
try {
client_rdr.Stream_(socket.Get_input_stream());
client_wtr.Stream_(socket.Get_output_stream());
request = request_parser.Parse(client_rdr);
this.data__client = new Http_data__client(request.Host(), socket.Ip_address());
byte[] url_bry = request.Url();
if (Bry_.Eq(url_bry, Url__home)) url_bry = server_mgr.Home(); // "localhost:8080" comes thru as url of "/"; transform to custom home page; DATE:2015-10-11
switch (request.Type()) {
case Http_request_itm.Type_get: Process_get(request, url_bry); break;
case Http_request_itm.Type_post: Process_post(request); break;
}
client_wtr.Rls(); // client_rdr.Rls(); socket.Rls();
}
catch (Exception e) {
String request_str = request == null ? "<<NULL>>" : request.To_str(tmp_bfr, Bool_.N);
server_wtr.Write_str_w_nl(String_.Format("failed to process request;\nrequest={0}\nerr_msg={1}", request_str, Err_.Message_gplx_full(e)));
}
finally {
if (uid != -1) { // only release if uid was acquired; DATE:2015-10-11
server_mgr.Wkr_pool().Del(uid);
server_mgr.Uid_pool().Del(uid);
}
}
}
private void Process_get(Http_request_itm request, byte[] url) {
server_wtr.Write_str_w_nl(String_.new_u8(request.Host()) + "|GET|" + String_.new_u8(request.Url())); // use request url
if (Bry_.Has_at_bgn(url, Url__fsys)) Serve_file(url);
else if (Bry_.Has_at_bgn(url, Url__exec)) Exec_exec(url, Url__exec);
else if (Bry_.Has_at_bgn(url, Url__exec_2)) Exec_exec(url, Url__exec_2);
else Write_wiki(url);
}
private void Serve_file(byte[] url) {
tmp_bfr.Clear().Add(root_dir_fsys); // add "C:\xowa\"
int question_pos = Bry_find_.Find_fwd(url, Byte_ascii.Question);
int url_bgn = Bry_.Has_at_bgn(url, Url__fsys) ? Url__fsys_len : 0; // most files will have "/fsys/" at start, but Mathjax will not
int url_end = question_pos == Bry_find_.Not_found ? url.length : question_pos; // ignore files with query params; EX: /file/A.png?key=val
url_encoder.Decode(url, url_bgn, url_end, tmp_bfr, false); // decode url to actual chars; note that XOWA stores on fsys in UTF-8 chars; "<22>" not "%C3"
byte[] path = tmp_bfr.To_bry_and_clear();
client_wtr.Write_bry(Xosrv_http_wkr_.Rsp__http_ok);
// client_wtr.Write_str("Expires: Sun, 17-Jan-2038 19:14:07 GMT\n");
String mime_type = String_.new_u8(Http_file_utl.To_mime_type_by_path_as_bry(path));
client_wtr.Write_str("Content-Type: " + mime_type + "\n\n");
Io_stream_rdr file_stream = Io_stream_rdr_.new_by_url_(Io_url_.new_fil_(String_.new_u8(path))).Open();
client_wtr.Write_stream(file_stream);
file_stream.Rls(); client_rdr.Rls(); socket.Rls();
}
private void Exec_exec(byte[] url, byte[] tkn_bgn) {
byte[] cmd = Bry_.Mid(url, tkn_bgn.length);
app.Http_server().Run_xowa_cmd(app, String_.new_u8(cmd));
}
private void Write_wiki(byte[] req) {
String wiki_domain = ""; String page_name = "";
String[] req_split = String_.Split(String_.new_u8(req), "/");
if(req_split.length >= 1){
wiki_domain = req_split[1];
}
if(req_split.length >= 4){
page_name = req_split[3];
for(int i = 4; i <= req_split.length-1; i++){
page_name += "/" + req_split[i];
}
page_name = url_encoder.Decode_str(page_name);
}
String page_html = app.Http_server().Parse_page_to_html(data__client, Bry_.new_u8(wiki_domain), Bry_.new_u8(page_name));
page_html = Convert_page(page_html, root_dir_http, wiki_domain);
Xosrv_http_wkr_.Write_response_as_html(client_wtr, Bool_.N, page_html);
}
private void Process_post(Http_request_itm request) {
byte[] msg = request.Post_data_hash().Get_by(Key__msg).Val();
byte[] app_mode = request.Post_data_hash().Get_by(Key__app_mode).Val();
Xoa_app_mode app_mode_itm = Xoa_app_mode.parse(String_.new_u8(app_mode));
server_wtr.Write_str_w_nl(String_.new_u8(request.Host()) + "|POST|" + String_.new_u8(msg));
Object url_tid_obj = post_url_hash.Get_by_bry(request.Url()); if (url_tid_obj == null) throw Err_.new_wo_type("unknown url", "url", request.Url(), "request", request.To_str(tmp_bfr, Bool_.N));
String rv = null;
switch (((Int_obj_val)url_tid_obj).Val()) {
case Tid_post_url_json:
rv = app.Html__bridge_mgr().Cmd_mgr().Exec(msg);
break;
case Tid_post_url_gfs:
rv = Object_.Xto_str_strict_or_null_mark(app.Gfs_mgr().Run_str(String_.new_u8(msg)));
break;
}
if (app_mode_itm.Tid_is_http())
rv = Convert_page(rv, root_dir_http , "<<MISSING_WIKI>>");
Xosrv_http_wkr_.Write_response_as_html(client_wtr, app_mode_itm.Tid() == Xoa_app_mode.Itm_file.Tid(), rv);
}
private static final byte[] Key__msg = Bry_.new_a7("msg"), Key__app_mode = Bry_.new_a7("app_mode");
private static final int Tid_post_url_json = 1, Tid_post_url_gfs = 2;
private static final Hash_adp_bry post_url_hash = Hash_adp_bry.ci_a7()
.Add_str_int("/exec/json" , Tid_post_url_json)
.Add_str_int("/exec/gfs" , Tid_post_url_gfs)
;
private static String Convert_page(String page_html, String root_dir_http, String wiki_domain) {
page_html = String_.Replace(page_html, root_dir_http , "/fsys/");
page_html = String_.Replace(page_html, "xowa-cmd:" , "/exec/");
page_html = String_.Replace(page_html, "<a href=\"/wiki/" , "<a href=\"/" + wiki_domain + "/wiki/");
page_html = String_.Replace(page_html, "<a href='/wiki/" , "<a href='/" + wiki_domain + "/wiki/");
page_html = String_.Replace(page_html, "action=\"/wiki/" , "action=\"/" + wiki_domain + "/wiki/");
page_html = String_.Replace(page_html, "/site" , "");
return page_html;
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_run)) {this.Run();}
else return GfoInvkAble_.Rv_unhandled;
return this;
} public static final String Invk_run = "run";
private static final byte[]
Url__home = Bry_.new_a7("/"), Url__fsys = Bry_.new_a7("/fsys/")
, Url__exec = Bry_.new_a7("/exec/"), Url__exec_2 = Bry_.new_a7("/xowa-cmd:")
;
private static final int Url__fsys_len = Url__fsys.length;
}
class Xosrv_http_wkr_ {
public static void Write_response_as_html(Http_client_wtr client_wtr, boolean cross_domain, String html) {Write_response_as_html(client_wtr, cross_domain, Bry_.new_u8(html));}
public static void Write_response_as_html(Http_client_wtr client_wtr, boolean cross_domain, byte[] html) {
try{
client_wtr.Write_bry(Rsp__http_ok);
if (cross_domain)
client_wtr.Write_str("Access-Control-Allow-Origin: *\n"); // No 'Access-Control-Allow-Origin' header is present on the requested resource.
client_wtr.Write_bry(Rsp__content_type_html);
client_wtr.Write_bry(Byte_ascii.Nl_bry);
client_wtr.Write_bry(html);
} catch (Exception err) {
client_wtr.Write_str("Site not found. Check address please, or see console log.\n" + Err_.Message_lang(err));
client_wtr.Rls();
}
}
public static final byte[]
Rsp__http_ok = Bry_.new_a7("HTTP/1.1 200 OK:\n")
, Rsp__content_type_html = Bry_.new_a7("Content-Type: text/html; charset=utf-8\n")
;
}
class Http_file_utl {
public static byte[] To_mime_type_by_path_as_bry(byte[] path_bry) {
int dot_pos = Bry_find_.Find_bwd(path_bry, Byte_ascii.Dot);
return dot_pos == Bry_find_.Not_found ? Mime_octet_stream : To_mime_type_by_ext_as_bry(path_bry, dot_pos, path_bry.length);
}
public static byte[] To_mime_type_by_ext_as_bry(byte[] ext_bry, int bgn, int end) {
Object o = mime_hash.Get_by_mid(ext_bry, bgn, end);
return o == null ? Mime_octet_stream : (byte[])o;
}
private static final byte[]
Mime_html = Bry_.new_a7("text/html")
, Mime_jpg = Bry_.new_a7("image/jpeg")
, Mime_png = Bry_.new_a7("image/png")
, Mime_gif = Bry_.new_a7("image/gif")
, Mime_css = Bry_.new_a7("text/css")
, Mime_js = Bry_.new_a7("application/javascript")
, Mime_octet_stream = Bry_.new_a7("application/octet-stream")
;
private static final Hash_adp_bry mime_hash = Hash_adp_bry.ci_a7()
.Add_str_obj(".htm" , Mime_html)
.Add_str_obj(".html" , Mime_html)
.Add_str_obj(".jpg" , Mime_jpg)
.Add_str_obj(".png" , Mime_png)
.Add_str_obj(".gif" , Mime_gif)
.Add_str_obj(".css" , Mime_css)
.Add_str_obj(".js" , Mime_js)
;
}