001: /*
002: * Copyright (c) 2002-2008 Gargoyle Software Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * 1. Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: * 2. Redistributions in binary form must reproduce the above copyright notice,
010: * this list of conditions and the following disclaimer in the documentation
011: * and/or other materials provided with the distribution.
012: * 3. The end-user documentation included with the redistribution, if any, must
013: * include the following acknowledgment:
014: *
015: * "This product includes software developed by Gargoyle Software Inc.
016: * (http://www.GargoyleSoftware.com/)."
017: *
018: * Alternately, this acknowledgment may appear in the software itself, if
019: * and wherever such third-party acknowledgments normally appear.
020: * 4. The name "Gargoyle Software" must not be used to endorse or promote
021: * products derived from this software without prior written permission.
022: * For written permission, please contact info@GargoyleSoftware.com.
023: * 5. Products derived from this software may not be called "HtmlUnit", nor may
024: * "HtmlUnit" appear in their name, without prior written permission of
025: * Gargoyle Software Inc.
026: *
027: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
028: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
029: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
030: * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
031: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
032: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
033: * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
034: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
035: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
036: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037: */
038: package com.gargoylesoftware.htmlunit.html;
039:
040: import java.io.IOException;
041: import java.net.MalformedURLException;
042: import java.net.URL;
043: import java.util.Map;
044:
045: import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
046: import com.gargoylesoftware.htmlunit.Page;
047: import com.gargoylesoftware.htmlunit.WebClient;
048: import com.gargoylesoftware.htmlunit.WebRequestSettings;
049: import com.gargoylesoftware.htmlunit.WebWindow;
050:
051: /**
052: * Base class for frame and iframe.
053: *
054: * @version $Revision: 2132 $
055: * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
056: * @author David K. Taylor
057: * @author <a href="mailto:cse@dynabean.de">Christian Sell</a>
058: * @author Marc Guillemot
059: * @author David D. Kilzer
060: * @author Stefan Anzinger
061: * @author Ahmed Ashour
062: */
063: public abstract class BaseFrame extends StyledElement {
064:
065: private final WebWindow enclosedWindow_ = new FrameWindow(this );
066:
067: /**
068: * Create an instance of BaseFrame
069: *
070: * @param namespaceURI the URI that identifies an XML namespace.
071: * @param qualifiedName The qualified name of the element type to instantiate
072: * @param page The HtmlPage that contains this element.
073: * @param attributes the initial attributes
074: */
075: protected BaseFrame(final String namespaceURI,
076: final String qualifiedName, final HtmlPage page,
077: final Map attributes) {
078: super (namespaceURI, qualifiedName, page, attributes);
079:
080: try {
081: // put about:blank in the window to allow JS to run on this frame before the
082: // real content is loaded
083: getPage().getWebClient().pushClearFirstWindow();
084: getPage().getWebClient().getPage(enclosedWindow_,
085: new WebRequestSettings(WebClient.URL_ABOUT_BLANK));
086: getPage().getWebClient().popFirstWindow();
087: } catch (final FailingHttpStatusCodeException e) {
088: // should never occur
089: } catch (final IOException e) {
090: // should never occur
091: }
092: }
093:
094: /**
095: * Called after the node for <frame...> or <iframe> has been added to the containing page.
096: * The node needs to be added first to allow js in the frame to see the frame in the parent
097: * @throws FailingHttpStatusCodeException If the server returns a
098: * failing status code AND the property
099: * {@link WebClient#setThrowExceptionOnFailingStatusCode(boolean)} is set to true.
100: */
101: void loadInnerPage() throws FailingHttpStatusCodeException {
102: String source = getSrcAttribute();
103: if (source.length() == 0) {
104: // Nothing to load
105: source = "about:blank";
106: } else {
107: getPage().getWebClient().pushClearFirstWindow();
108: loadInnerPageIfPossible(source);
109: getPage().getWebClient().popFirstWindow();
110: }
111: }
112:
113: /**
114: * @throws FailingHttpStatusCodeException If the server returns a
115: * failing status code AND the property
116: * {@link WebClient#setThrowExceptionOnFailingStatusCode(boolean)} is set to true.
117: */
118: private void loadInnerPageIfPossible(final String src)
119: throws FailingHttpStatusCodeException {
120: if (src.length() != 0) {
121: final URL url;
122: try {
123: url = getPage().getFullyQualifiedUrl(src);
124: } catch (final MalformedURLException e) {
125: notifyIncorrectness("Invalid src attribute of "
126: + getTagName() + ": url=[" + src
127: + "]. Ignored.");
128: return;
129: }
130: if (isAlreadyLoadedByAncestor(url)) {
131: notifyIncorrectness("Recursive src attribute of "
132: + getTagName() + ": url=[" + src
133: + "]. Ignored.");
134: return;
135: }
136: try {
137: final WebRequestSettings settings = new WebRequestSettings(
138: url);
139: settings.addAdditionalHeader("Referer", getPage()
140: .getWebResponse().getUrl().toExternalForm());
141: getPage().getWebClient().getPage(enclosedWindow_,
142: settings);
143: } catch (final IOException e) {
144: getLog().error(
145: "IOException when getting content for "
146: + getTagName() + ": url=["
147: + url.toExternalForm() + "]", e);
148: }
149: }
150: }
151:
152: /**
153: * Test if the provided url is the one of one of the parents which would cause an infinite loop.
154: * @param url the url to test
155: * @return <code>false</code> if no parent has already this url
156: */
157: private boolean isAlreadyLoadedByAncestor(final URL url) {
158: WebWindow window = getPage().getEnclosingWindow();
159: while (window != null) {
160: if (url.sameFile(window.getEnclosedPage().getWebResponse()
161: .getUrl())) {
162: return true;
163: }
164: if (window == window.getParentWindow()) { // should getParentWindow() return null on top windows?
165: window = null;
166: } else {
167: window = window.getParentWindow();
168: }
169: }
170: return false;
171: }
172:
173: /**
174: * Return the value of the attribute "longdesc". Refer to the
175: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
176: * documentation for details on the use of this attribute.
177: *
178: * @return The value of the attribute "longdesc"
179: * or an empty string if that attribute isn't defined.
180: */
181: public final String getLongDescAttribute() {
182: return getAttributeValue("longdesc");
183: }
184:
185: /**
186: * Return the value of the attribute "name". Refer to the
187: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
188: * documentation for details on the use of this attribute.
189: *
190: * @return The value of the attribute "name"
191: * or an empty string if that attribute isn't defined.
192: */
193: public final String getNameAttribute() {
194: return getAttributeValue("name");
195: }
196:
197: /**
198: * Set the value of the "name" attribute.
199: *
200: * @param name The new window name.
201: */
202: public final void setNameAttribute(final String name) {
203: setAttributeValue("name", name);
204: }
205:
206: /**
207: * Return the value of the attribute "src". Refer to the
208: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
209: * documentation for details on the use of this attribute.
210: *
211: * @return The value of the attribute "src"
212: * or an empty string if that attribute isn't defined.
213: */
214: public final String getSrcAttribute() {
215: return getAttributeValue("src");
216: }
217:
218: /**
219: * Return the value of the attribute "frameborder". Refer to the
220: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
221: * documentation for details on the use of this attribute.
222: *
223: * @return The value of the attribute "frameborder"
224: * or an empty string if that attribute isn't defined.
225: */
226: public final String getFrameBorderAttribute() {
227: return getAttributeValue("frameborder");
228: }
229:
230: /**
231: * Return the value of the attribute "marginwidth". Refer to the
232: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
233: * documentation for details on the use of this attribute.
234: *
235: * @return The value of the attribute "marginwidth"
236: * or an empty string if that attribute isn't defined.
237: */
238: public final String getMarginWidthAttribute() {
239: return getAttributeValue("marginwidth");
240: }
241:
242: /**
243: * Return the value of the attribute "marginheight". Refer to the
244: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
245: * documentation for details on the use of this attribute.
246: *
247: * @return The value of the attribute "marginheight"
248: * or an empty string if that attribute isn't defined.
249: */
250: public final String getMarginHeightAttribute() {
251: return getAttributeValue("marginheight");
252: }
253:
254: /**
255: * Return the value of the attribute "noresize". Refer to the
256: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
257: * documentation for details on the use of this attribute.
258: *
259: * @return The value of the attribute "noresize"
260: * or an empty string if that attribute isn't defined.
261: */
262: public final String getNoResizeAttribute() {
263: return getAttributeValue("noresize");
264: }
265:
266: /**
267: * Return the value of the attribute "scrolling". Refer to the
268: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
269: * documentation for details on the use of this attribute.
270: *
271: * @return The value of the attribute "scrolling"
272: * or an empty string if that attribute isn't defined.
273: */
274: public final String getScrollingAttribute() {
275: return getAttributeValue("scrolling");
276: }
277:
278: /**
279: * Return the value of the attribute "onload". This attribute is not
280: * actually supported by the HTML specification however it is supported
281: * by the popular browsers.
282: *
283: * @return The value of the attribute "onload"
284: * or an empty string if that attribute isn't defined.
285: */
286: public final String getOnLoadAttribute() {
287: return getAttributeValue("onload");
288: }
289:
290: /**
291: * Return the currently loaded page in the enclosed window.
292: * This is a facility method for <code>getEnclosedWindow().getEnclosedPage()</code>.
293: * @see WebWindow#getEnclosedPage()
294: * @return The currently loaded page in the enclosed window or null if no page has been loaded.
295: */
296: public Page getEnclosedPage() {
297: return getEnclosedWindow().getEnclosedPage();
298: }
299:
300: /**
301: * Gets the window enclosed in this frame.
302: * @return the window
303: */
304: public WebWindow getEnclosedWindow() {
305: return enclosedWindow_;
306: }
307:
308: /**
309: * Set the value of the "src" attribute. Also load the frame with the specified url if possible.
310: * @param attribute The new value
311: */
312: public final void setSrcAttribute(final String attribute) {
313: setAttributeValue("src", attribute);
314: }
315:
316: /**
317: * {@inheritDoc}
318: */
319: public final void setAttributeValue(final String namespaceURI,
320: final String qualifiedName, String attributeValue) {
321: if (qualifiedName.equals("src")) {
322: attributeValue = attributeValue.trim();
323: }
324: super .setAttributeValue(namespaceURI, qualifiedName,
325: attributeValue);
326: if (qualifiedName.equals("src")) {
327: loadInnerPageIfPossible(attributeValue);
328: }
329: }
330: }
|