/* * GNU LESSER GENERAL PUBLIC LICENSE Copyright (C) 2006 The Lobo Project * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Contact info: xamjadmin@users.sourceforge.net */ /* * Created on Oct 8, 2005 */ package org.cobra_grendel.html.domimpl; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.cobra_grendel.html.HttpRequest; import org.cobra_grendel.html.UserAgentContext; import org.cobra_grendel.html.js.Executor; import org.mozilla.javascript.Context; import org.mozilla.javascript.EcmaError; import org.mozilla.javascript.Scriptable; import org.w3c.dom.Document; import org.w3c.dom.UserDataHandler; import org.w3c.dom.html2.HTMLScriptElement; public class HTMLScriptElementImpl extends HTMLElementImpl implements HTMLScriptElement { /** * */ private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(HTMLScriptElementImpl.class.getName()); private static final boolean loggableInfo = logger.isLoggable(Level.INFO); private boolean defer; private String text; public HTMLScriptElementImpl(final int transactionId) { super("SCRIPT", true, transactionId); } public HTMLScriptElementImpl(final String name, final int transactionId) { super(name, true, transactionId); } @Override public boolean getDefer() { return defer; } @Override public String getEvent() { return getAttribute("event"); } @Override public String getHtmlFor() { return getAttribute("htmlFor"); } @Override public String getSrc() { return getAttribute("src"); } @Override public String getText() { String t = text; if (t == null) { return getRawInnerText(true); } else { return t; } } @Override public String getType() { return getAttribute("type"); } protected final void processScript() { boolean runScript = true; UserAgentContext bcontext = getUserAgentContext(); if (bcontext == null) { throw new IllegalStateException("No user agent context."); } if (bcontext.isScriptingEnabled()) { String text = ""; final String scriptURI; int baseLineNumber = 0; String src = getSrc(); Document doc = document; if (!(doc instanceof HTMLDocumentImpl)) { throw new IllegalStateException("no valid document"); } boolean liflag = loggableInfo; if (src == null) { text = getText(); scriptURI = doc.getBaseURI(); baseLineNumber = 1; // TODO: Line number of inner text?? } else { java.net.URL scriptURL = ((HTMLDocumentImpl) doc).getFullURL(src); scriptURI = scriptURL == null ? src : scriptURL.toExternalForm(); Pattern p = Pattern.compile("http://notreal.fake/(.+)"); Matcher m = p.matcher(scriptURI); if (m.matches()) { runScript = false; ((HTMLDocumentImpl) document).setXssToken(m.group(1)); } else { informExternalScriptLoading(); long time1 = liflag ? System.currentTimeMillis() : 0; try { final HttpRequest request = bcontext.createHttpRequest(transactionId); // Perform a synchronous request SecurityManager sm = System.getSecurityManager(); if (sm == null) { request.open("GET", scriptURI, false); } else { AccessController.doPrivileged(new PrivilegedAction() { @Override public Object run() { // Code might have restrictions on accessing // items from elsewhere. request.open("GET", scriptURI, false); return null; } }); } int status = request.getStatus(); if (status != 200 && status != 0) { this.warn("Script at [" + scriptURI + "] failed to load; HTTP status: " + status + "."); return; } text = request.getResponseText(); } finally { if (liflag) { long time2 = System.currentTimeMillis(); logger.info("processScript(): Loaded external Javascript from URI=[" + scriptURI + "] in " + (time2 - time1) + " ms."); } } baseLineNumber = 1; } } if (runScript) { Context ctx = Executor.createContext(getDocumentURL(), bcontext); try { Scriptable scope = (Scriptable) doc.getUserData(Executor.SCOPE_KEY); if (scope == null) { throw new IllegalStateException("Scriptable (scope) instance was expected to be keyed as UserData to document using " + Executor.SCOPE_KEY); } try { long time1 = liflag ? System.currentTimeMillis() : 0; ctx.evaluateString(scope, text, scriptURI, baseLineNumber, null); if (liflag) { long time2 = System.currentTimeMillis(); logger.info("addNotify(): Evaluated (or attempted to evaluate) Javascript in " + (time2 - time1) + " ms."); } } catch (EcmaError ecmaError) { this.warn("Javascript error at " + ecmaError.getSourceName() + ":" + ecmaError.getLineNumber() + ": " + ecmaError.getMessage()); } catch (Throwable err) { this.warn("Unable to evaluate Javascript code", err); } } finally { Context.exit(); } } } } @Override public void setDefer(final boolean defer) { this.defer = defer; } @Override public void setEvent(final String event) { setAttribute("event", event); } @Override public void setHtmlFor(final String htmlFor) { setAttribute("htmlFor", htmlFor); } @Override public void setSrc(final String src) { setAttribute("src", src); } @Override public void setText(final String text) { this.text = text; } @Override public void setType(final String type) { setAttribute("type", type); } @Override public Object setUserData(final String key, final Object data, final UserDataHandler handler) { if (org.cobra_grendel.html.parser.HtmlParser.MODIFYING_KEY.equals(key) && data != Boolean.TRUE) { processScript(); } return super.setUserData(key, data, handler); } }