/* GNU GENERAL LICENSE Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2017 Lobo Evolution This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either verion 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 General License for more details. You should have received a copy of the GNU General Public along with this program. If not, see <http://www.gnu.org/licenses/>. Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it */ package org.lobobrowser.primary.ext; import java.awt.Component; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.InvocationTargetException; import java.net.ConnectException; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.URL; import java.net.UnknownHostException; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lobobrowser.clientlet.ClientletException; import org.lobobrowser.clientlet.ClientletResponse; import org.lobobrowser.clientlet.ComponentContent; import org.lobobrowser.clientlet.JavaVersionException; import org.lobobrowser.clientlet.NavigatorVersionException; import org.lobobrowser.html.HtmlRendererContext; import org.lobobrowser.html.gui.HtmlPanel; import org.lobobrowser.primary.clientlets.PrimaryClientletSelector; import org.lobobrowser.primary.clientlets.html.HtmlContent; import org.lobobrowser.primary.clientlets.html.HtmlRendererContextImpl; import org.lobobrowser.request.UserAgentImpl; import org.lobobrowser.ua.NavigationEntry; import org.lobobrowser.ua.NavigatorErrorListener; import org.lobobrowser.ua.NavigatorExceptionEvent; import org.lobobrowser.ua.NavigatorExtension; import org.lobobrowser.ua.NavigatorExtensionContext; import org.lobobrowser.ua.NavigatorFrame; import org.lobobrowser.ua.NavigatorWindow; import org.lobobrowser.util.Html; import org.lobobrowser.util.Strings; import org.lobobrowser.w3c.html.HTMLDocument; /** * The Class ExtensionImpl. */ public class ExtensionImpl implements NavigatorExtension { /** The Constant logger. */ private static final Logger logger = LogManager.getLogger(ExtensionImpl.class); /* * (non-Javadoc) * * @see org.lobobrowser.ua.NavigatorExtension#destroy() */ @Override public void destroy() { } /* * (non-Javadoc) * * @see org.lobobrowser.ua.NavigatorExtension#init(org.lobobrowser.ua. * NavigatorExtensionContext) */ @Override public void init(NavigatorExtensionContext pcontext) { pcontext.addURLStreamHandlerFactory(new PrimaryStreamHandlerFactory()); pcontext.addClientletSelector(new PrimaryClientletSelector()); pcontext.addNavigatorErrorListener(new NavigatorErrorListener() { @Override public void errorOcurred(NavigatorExceptionEvent event) { showError(event.getNavigatorFrame(), event.getResponse(), event.getException()); } }); } /* * (non-Javadoc) * * @see * org.lobobrowser.ua.NavigatorExtension#windowClosing(org.lobobrowser.ua. * NavigatorWindow) */ @Override public void windowClosing(NavigatorWindow wcontext) { NavigationHistory.getInstance().save(); } /* * (non-Javadoc) * * @see * org.lobobrowser.ua.NavigatorExtension#windowOpening(org.lobobrowser.ua. * NavigatorWindow) */ @Override public void windowOpening(NavigatorWindow wcontext) { ComponentSource cs = new ComponentSource(wcontext); Component[] abc = cs.getAddressBarComponents(); for (Component c : abc) { wcontext.addAddressBarComponent(c); } Component[] sbc = cs.getStatusBarComponents(); for (Component c : sbc) { wcontext.addStatusBarComponent(c); } wcontext.addMenu("lobo.file", cs.getFileMenu()); wcontext.addMenu("lobo.edit", cs.getEditMenu()); wcontext.addMenu("lobo.view", cs.getViewMenu()); wcontext.addMenu("lobo.navigation", cs.getNavigationMenu()); wcontext.addMenu("lobo.chronology", cs.getChronologyMenu()); wcontext.addMenu("lobo.bookmarks", cs.getBookmarksMenu()); wcontext.addMenu("lobo.tools", cs.getToolsMenu()); wcontext.addMenu("lobo.help", cs.getHelpMenu()); wcontext.addNavigatorWindowListener(cs); NavigationEntry firstEntry = wcontext.getCurrentNavigationEntry(); cs.setNavigationEntry(firstEntry); } /** * Show error. * * @param frame * the frame * @param response * the response * @param exception * the exception */ public static void showError(NavigatorFrame frame, ClientletResponse response, Throwable exception) { if (logger.isWarnEnabled()) { logger.error("showError(): An error occurred trying to process document " + (response == null ? "[null]" : response.getResponseURL()), exception.getCause()); } ComponentContent errorComponent = getErrorComponent(frame, response, exception); frame.replaceContent(response, errorComponent); // TODO: Get window or something, and ensure current URL is shown. } /** * Gets the error component. * * @param frame * the frame * @param response * the response * @param exception * the exception * @return the error component */ private static ComponentContent getErrorComponent(NavigatorFrame frame, ClientletResponse response, Throwable exception) { HtmlPanel panel = new HtmlPanel(); HtmlRendererContext rcontext = HtmlRendererContextImpl.getHtmlRendererContext(frame); panel.setHtml(getErrorHtml(response, exception), "about:error", rcontext); String sourceCode = "[NOT AVAILABLE]"; if (exception instanceof ClientletException) { ClientletException ce = (ClientletException) exception; String sc = ce.getSourceCode(); if (sc != null) { sourceCode = sc; } } return new HtmlContent((HTMLDocument) panel.getRootNode(), panel, sourceCode); } /** * Gets the root cause. * * @param t * the t * @return the root cause */ private static Throwable getRootCause(Throwable t) { while (t.getCause() != null) { t = t.getCause(); } return t; } /** * Gets the error html. * * @param response * the response * @param exception * the exception * @return the error html */ static String getErrorHtml(ClientletResponse response, Throwable exception) { URL url = response == null ? null : response.getResponseURL(); String method = response == null ? null : response.getLastRequestMethod(); Writer swriter = new StringWriter(); PrintWriter writer = new PrintWriter(swriter); writer.println("<html><body>"); writer.println("<dl style='background-color: #FFB0B0; border: solid red 2px; padding: 2px;'>"); writer.println(" <big>An <strong>error</strong> occurred trying to process a request.</big>"); writer.println(" <br>"); if (url != null) { writer.println(" <dt><strong>URL</strong>:</dt>"); writer.println(" <dd>" + getErrorUrlText(url, method) + "</dd>"); } writer.println(" <dt><strong>Exception</strong>:</dt>"); writer.println(" <dd>" + exception.getClass().getName() + "</dd>"); writer.println(" <dt><strong>Meaning</strong>:</dt>"); writer.println(" <dd>" + getExceptionMeaning(url, exception) + "</dd>"); writer.println(" <dt><strong>Message</strong>:</dt>"); writer.println(" <dd>" + Html.textToHTML(exception.getMessage()) + "</dd>"); writer.println("</dl>"); writer.println("<p></p>"); writer.println("<table border='1' width='100%' style='background-color: #B0B0FF; bolder: solid red 2px;'>"); writer.println(" <tr><th>"); writer.println(" Details"); writer.println(" </th></tr>"); writer.println(" <tr><td>"); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); exception.printStackTrace(pw); pw.flush(); writer.println(Html.textToHTML(sw.toString())); if (exception.getCause() != null) { Throwable rootCause = getRootCause(exception); StringWriter sw2 = new StringWriter(); PrintWriter pw2 = new PrintWriter(sw2); rootCause.printStackTrace(pw2); pw2.flush(); writer.println("<p><strong>Root Cause</strong></p>"); writer.println(Html.textToHTML(sw2.toString())); } writer.println(" </td></tr>"); writer.println("</table>"); writer.println("</body><html>"); writer.flush(); return swriter.toString(); } /** * Gets the error url text. * * @param url * the url * @param method * the method * @return the error url text */ private static String getErrorUrlText(URL url, String method) { StringBuffer buf = new StringBuffer(); boolean isGet = "GET".equals(method); if (isGet) { buf.append("<a href=\"" + url.toExternalForm() + "\">"); } buf.append(Strings.truncate(url.toExternalForm(), 80)); if (isGet) { buf.append("</a>"); } return buf.toString(); } /** * Gets the exception meaning. * * @param url * the url * @param exception * the exception * @return the exception meaning */ private static String getExceptionMeaning(URL url, Throwable exception) { if (exception instanceof org.lobobrowser.clientlet.JavaVersionException) { JavaVersionException jve = (JavaVersionException) exception; return "This exception is thrown when the content expects the user's Java Virtual Machine " + "to be more up to date than it currently is. In this case the content is " + "expecting version " + jve.getExpectingVersion() + " whereas the version running " + "the browser is " + System.getProperty("java.version") + "."; } else if (exception instanceof NavigatorVersionException) { NavigatorVersionException nve = (NavigatorVersionException) exception; return "This exception is thrown when the content expects the browser version " + "to be more up to date than it currently is. In this case the content is " + "expecting version " + nve.getExpectingVersion() + " whereas the user agent " + "version is " + UserAgentImpl.getInstance().getVersion() + "."; } else { Throwable cause = exception; if (exception instanceof ClientletException) { cause = ((ClientletException) exception).getCause(); if (cause == null) { // oops cause = exception; } } else if (exception instanceof InvocationTargetException) { cause = ((InvocationTargetException) exception).getCause(); } if (cause instanceof MalformedURLException) { return "A URL or URI was not formatted correctly."; } else if (cause instanceof UnknownHostException) { return "The host named '" + ((UnknownHostException) cause).getMessage() + "' could not be found by the Domain Name Service (DNS)."; } else if (cause instanceof SecurityException) { return "An attempted security violation has been detected and stopped."; } else if (cause instanceof ProtocolException) { return "Indicates there is an error in the underlying communications protocol."; } else if (cause instanceof SocketTimeoutException) { return "It means the server accepted the connection, but failed to respond after a long period of time. This is usually indicative of a server problem."; } else if (cause instanceof ConnectException) { return "It means a connection to the server could not be obtained. Typically, the server has refused the connection, i.e. it's not accepting connections on a given port."; } else if (cause instanceof SocketException) { return "Indicates there was an error in the underlying protocol, e.g. TCP/IP."; } else if (cause instanceof java.io.IOException) { return "Indicates an Input/Output error has occurred. This is typically due " + "to a network connection that cannot be establised or one that has failed, " + "but it can also mean that a file could not be accessed or found."; } else if ((cause instanceof NullPointerException) || (cause instanceof ClassCastException)) { return "This is a common Java exception that generally occurs due to a programming error. " + "The stack trace will show if the error is in browser code, an extension or the document itself."; } else if (cause instanceof ClientletException) { return "A " + ClientletException.class.getSimpleName() + " is thrown by extensions or documents typically to indicate an unexpected state has been encountered."; } else { return "Unknown."; } } } }