diff --git a/400_xowa/src/gplx/xowa/apps/servers/http/Http_server_wkr.java b/400_xowa/src/gplx/xowa/apps/servers/http/Http_server_wkr.java index 156b4e504..8bab6f667 100644 --- a/400_xowa/src/gplx/xowa/apps/servers/http/Http_server_wkr.java +++ b/400_xowa/src/gplx/xowa/apps/servers/http/Http_server_wkr.java @@ -136,7 +136,7 @@ public class Http_server_wkr implements Gfo_invk { .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, "file:////home/lnxusr/xowa/file/", "/fsys/file/"); + page_html = Replace_fsys_hack(page_html); 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, " href=\"/wiki/" , " href=\"/" + wiki_domain + "/wiki/"); @@ -145,6 +145,91 @@ public class Http_server_wkr implements Gfo_invk { page_html = String_.Replace(page_html, "/site" , ""); return page_html; } + + private static final byte[] + Bry__file_lhs = Bry_.new_a7("file:") + , Bry__file_mid = Bry_.new_a7("/file/") + , Bry__file_fsys = Bry_.new_a7("/fsys") + ; + + public static String Replace_fsys_hack(String html_str) { + // init + Bry_bfr bfr = Bry_bfr_.New(); + byte[] html_bry = Bry_.new_u8(html_str); + int len = html_bry.length; + int pos = 0; + + // loop while finding "file:.*/file/" + while (true) { + // find "file:" + int lhs_bgn = Bry_find_.Find_fwd(html_bry, Bry__file_lhs, pos); + + // exit if nothing found + if (lhs_bgn == Bry_find_.Not_found) + break; + + // set lhs_end (after "file:") + int lhs_end = lhs_bgn + Bry__file_lhs.length; + + // skip if page literally starts with "file:" + if (lhs_bgn == 0) { + bfr.Add_mid(html_bry, pos, lhs_end); + pos = lhs_end; + continue; + } + + // get quote char before "file:" + int quote_bgn = lhs_bgn - 1; + byte quote = html_bry[quote_bgn]; + + // skip if no quote found + if (quote != Byte_ascii.Apos && quote != Byte_ascii.Quote) { + bfr.Add_mid(html_bry, pos, lhs_end); + pos = lhs_end; + continue; + } + + // find end quote + int quote_end = Bry_find_.Find_fwd(html_bry, quote, lhs_end); + + // exit if no end quote + if (quote_end == Bry_find_.Not_found) + break; + + // skip if "'file: ... '" is too long. should be no more than 300 + if (quote_end - lhs_end > 300) { + bfr.Add_mid(html_bry, pos, quote_end); + pos = quote_end; + continue; + } + + // find "/file/" + int mid_bgn = Bry_find_.Find_fwd(html_bry, Bry__file_mid, lhs_bgn, quote_end); + + // skip if no "/file/" + if (mid_bgn == Bry_find_.Not_found) { + bfr.Add_mid(html_bry, pos, quote_end); + pos = quote_end; + continue; + } + + // add everything up to "file:" + bfr.Add_mid(html_bry, pos, lhs_bgn); + + // add "/fsys/" + bfr.Add(Bry__file_fsys); + + // add everything up to quote + bfr.Add_mid(html_bry, mid_bgn, quote_end); + + // move pos forward + pos = quote_end; + } + + // add rest + bfr.Add_mid(html_bry, pos, len); + return bfr.To_str_and_clear(); + } public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { if (ctx.Match(k, Invk_run)) {this.Run();} else return Gfo_invk_.Rv_unhandled; diff --git a/400_xowa/src/gplx/xowa/apps/servers/http/Http_server_wkr_tst.java b/400_xowa/src/gplx/xowa/apps/servers/http/Http_server_wkr_tst.java new file mode 100644 index 000000000..c63221baf --- /dev/null +++ b/400_xowa/src/gplx/xowa/apps/servers/http/Http_server_wkr_tst.java @@ -0,0 +1,51 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012-2017 gnosygnu@gmail.com + +XOWA is licensed under the terms of the General Public License (GPL) Version 3, +or alternatively under the terms of the Apache License Version 2.0. + +You may use XOWA according to either of these licenses as is most appropriate +for your project on a case-by-case basis. + +The terms of each license can be found in the source code repository: + +GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt +Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt +*/ +package gplx.xowa.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*; +import org.junit.*; import gplx.core.tests.*; +public class Http_server_wkr_tst { + private final Http_server_wkr_fxt fxt = new Http_server_wkr_fxt(); + @Test public void File_bgn_missing() { // "file:" missing + fxt.Test__Replace_fsys_hack("src='file////home/lnxusr/xowa/file/'"); + } + @Test public void File_bgn_at_bos() { // "file:" at start of page + fxt.Test__Replace_fsys_hack("file:////home/lnxusr/xowa/file/"); + } + @Test public void Quote_bgn_missing() { + fxt.Test__Replace_fsys_hack("(file:////home/lnxusr/xowa/file/)"); + } + @Test public void Quote_end_missing() { + fxt.Test__Replace_fsys_hack("a'file:////home/lnxusr/xowa/file/"); + } + @Test public void Too_long() { // skip if too long + fxt.Test__Replace_fsys_hack("'file:" + String_.Repeat("a", 301) + "'"); + } + @Test public void File_mid_missing() { // skip if no /file/ + fxt.Test__Replace_fsys_hack("'file:////home/lnxusr/xowa/file_missing/'"); + } + @Test public void One() { + fxt.Test__Replace_fsys_hack("'file:////home/lnxusr/xowa/file/A.png'", "'/fsys/file/A.png'"); + } + @Test public void Many() { + fxt.Test__Replace_fsys_hack("a 'file:////home/lnxusr/xowa/file/A.png' b \"file:////home/lnxusr/xowa/file/B.png\" c", "a '/fsys/file/A.png' b \"/fsys/file/B.png\" c"); + } +} +class Http_server_wkr_fxt { + public void Test__Replace_fsys_hack(String html) {Test__Replace_fsys_hack(html, html);} + public void Test__Replace_fsys_hack(String html, String expd) { + String actl = Http_server_wkr.Replace_fsys_hack(html); + Gftest.Eq__ary__lines(expd, actl); + } +}