/* * 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: lobochief@users.sourceforge.net */ /* * Created on Oct 8, 2005 */ package com.nvarghese.beowulf.common.cobra.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.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; import com.nvarghese.beowulf.common.cobra.html.HttpRequest; import com.nvarghese.beowulf.common.cobra.html.UserAgentContext; import com.nvarghese.beowulf.common.cobra.html.js.Executor; public class HTMLScriptElementImpl extends HTMLElementImpl implements HTMLScriptElement { private static final Logger logger = Logger.getLogger(HTMLScriptElementImpl.class.getName()); private static final boolean loggableInfo = logger.isLoggable(Level.INFO); public HTMLScriptElementImpl() { super("SCRIPT", true); } public HTMLScriptElementImpl(String name) { super(name, true); } private String text; public String getText() { String t = this.text; if (t == null) { return this.getRawInnerText(true); } else { return t; } } public void setText(String text) { this.text = text; } public String getHtmlFor() { return this.getAttribute("htmlFor"); } public void setHtmlFor(String htmlFor) { this.setAttribute("htmlFor", htmlFor); } public String getEvent() { return this.getAttribute("event"); } public void setEvent(String event) { this.setAttribute("event", event); } private boolean defer; public boolean getDefer() { return this.defer; } public void setDefer(boolean defer) { this.defer = defer; } public String getSrc() { return this.getAttribute("src"); } public void setSrc(String src) { this.setAttribute("src", src); } public String getType() { return this.getAttribute("type"); } public void setType(String type) { this.setAttribute("type", type); } public Object setUserData(String key, Object data, UserDataHandler handler) { if (com.nvarghese.beowulf.common.cobra.html.parser.HtmlParser.MODIFYING_KEY.equals(key) && data != Boolean.TRUE) { this.processScript(); } return super.setUserData(key, data, handler); } protected final void processScript() { boolean runScript = true; UserAgentContext bcontext = this.getUserAgentContext(); if (bcontext == null) { throw new IllegalStateException("No user agent context."); } if (bcontext.isScriptingEnabled()) { String text = null; final String scriptURI; int baseLineNumber = 0; String src = this.getSrc(); Document doc = this.document; if (!(doc instanceof HTMLDocumentImpl)) { throw new IllegalStateException("no valid document"); } boolean liflag = loggableInfo; if (src == null) { text = this.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 { this.informExternalScriptLoading(); long time1 = liflag ? System.currentTimeMillis() : 0; try { final HttpRequest request = bcontext.createHttpRequest(); // Perform a synchronous request SecurityManager sm = System.getSecurityManager(); if (sm == null) { try { request.open("GET", scriptURI, false); request.send(null); } catch (java.io.IOException thrown) { logger.log(Level.WARNING, "processScript()", thrown); } } else { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { // Code might have restrictions on accessing // items from elsewhere. try { request.open("GET", scriptURI, false); request.send(null); } catch (java.io.IOException thrown) { logger.log(Level.WARNING, "processScript()", thrown); } 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(this.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; if (text == null) { throw new java.lang.IllegalStateException("Script source is null: " + this + "."); } 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) { logger.log(Level.WARNING, "Javascript error at " + ecmaError.getSourceName() + ":" + ecmaError.getLineNumber() + ": " + ecmaError.getMessage(), ecmaError); } catch (Throwable err) { logger.log(Level.WARNING, "Unable to evaluate Javascript code", err); } } finally { Context.exit(); } } } } protected void appendInnerTextImpl(StringBuffer buffer) { // nop } }