Cross-domain IFrame Resizing

IFrames are a great way to do a low-tech mashup. The first thing you will want to do after getting an IFrame on your page is to resize it to get rid of the scroll bars that are probably present. A little googling turns up solutions like this,

function resizeFrame(f) {
    f.style.height = f.contentWindow.document.body.scrollHeight+'px';
} 
 ...
<iframe onload="resizeFrame(this)" src="..." ... 

This works great as long as the IFrame source is in the same domain as your client page. If it's not, your page is prevented from getting or setting any attributes of the IFrame. To get around this, you can make a  local proxy to fool your page into thinking that the IFrame is in your domain. For example,

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">
<%
    public static String scrape(String url) {
        try {
            URL u = new URL(url);
            BufferedReader in = new BufferedReader(
                    new InputStreamReader(
                    u.openStream()));

            String inputLine;
            StringBuffer b = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                b.append(inputLine);
            }

            in.close();
            return b.toString();
        } catch (IOException ioe) {
            return "Could not scrape URL: " + ioe;
        } 
    }
%>
<%= scrape(request.getParameter("url"))%> 

Now your IFrame looks like,

<iframe 
  onload="resizeFrame(this)" 
  src="proxy.jsp?url=..."></iframe>

where ... is the page outside your domain. As soon as this page loads into your IFrame you will notice the next problem. Since our proxy is dumb and doesn't rewrite URLs, any relative URLs in the scraped page are broken, including images. To fix this, use the BASE tag in the head of the scraped page,

<html>
  <head>
    <base href="http://opensso.dev.java.net/console"> 
...

This obviously relies on you being able to modify the IFrame source, which is not possible in most situations.

A thought I had was to dynamically modify the base URI of the IFrame. Since the IFrame source is now local I expected that would be possible. Apparently, the base URI (an attribute of the document) is set when the IFrame loads and is read only from then on out. That left me with mucking with the markup before it was processed by the  browser. A bit of code to insert the BASE tag is all that was needed,

public class Scraper {

    private String url;

    public Scraper(String url) {
        this.url = url;
    }

    public String scrape() throws IOException {
        URL u = new URL(url);
        BufferedReader in = new BufferedReader(
                new InputStreamReader(
                u.openStream()));

        String inputLine;
        StringBuffer b = new StringBuffer();
        while ((inputLine = in.readLine()) != null) {
            b.append(inputLine);
        }

        in.close();

        String base = getBase(url);
        String result;

        if (base != null) {
            result = setBase(b.toString(), base);
        } else {
            result = b.toString();
        }

        return result;
    }

    private static String getBase(String url) {
        try {
            URL u = new URL(url);
            StringBuffer b = new StringBuffer();
            b.append(u.getProtocol());
            b.append("://");
            b.append(u.getHost());
            if (u.getPort() != -1) {
                b.append(":");
                b.append(u.getPort());
            }

            return b.toString();
        } catch (MalformedURLException mfue) {
            return null;
        }
    }

    private static String setBase(String content, String base) {
        // remove base tag if it exists
        Pattern basePattern = Pattern.compile("<base.\*?>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
        Matcher baseMatcher = basePattern.matcher(content);
        if (baseMatcher.find()) {
            // base is already set
            return content;
        }

        // add new base tag
        Pattern headPattern = Pattern.compile("<head>(.\*?)</head>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
        Matcher headMatcher = headPattern.matcher(content);

        if (headMatcher.find()) {
            StringBuffer newHead = new StringBuffer();
            newHead.append("<head>\\n");
            newHead.append("<base href=\\"");
            newHead.append(base);
            newHead.append("\\" target=\\"_blank\\"/>\\n");
            newHead.append(headMatcher.group(1));
            newHead.append("\\n");
            newHead.append("</head>\\n");

            content = headMatcher.replaceFirst(newHead.toString());
        }

        return content;
    }
}

This solution is obviously limited in that it relied on you being able to put code on your server. Another solution I found relies only on modifying the source of the IFrame, but I found the hackiness offensive.

Comments:

jean style jean style jeans stylejeans style mens jean style mens jean style skinny jean style skinny jean style blue jeans style blue jeans style seven jeans style seven jeans style new jean style new jean style latest jean style latest jean style jeans styles jeans styles boy style jeans boy style jeans men jean style men jean style jean style 

Posted by jean style on December 17, 2009 at 02:18 PM PST #

The select items have object values. http://www.watchgy.com/ All is good. When I submit the form, I see "Validation Error: Value is not valid". My first reaction was that I didn't have any validation on the page, so how could a value be not valid? http://www.watchgy.com/tag-heuer-c-24.html
http://www.watchgy.com/rolex-submariner-c-8.html

Posted by replica rolex on December 28, 2009 at 11:55 PM PST #

Thanks for the iframes info. I am still working on a project that I need to use iframes calling a remote host. What a pain! Thanks!

Posted by RAP Addons on July 04, 2010 at 12:28 PM PDT #

Thanks for this. I have a similar problem with a widget we are delivery to a client via iframe that needs to resize its height as it changes.

Posted by broadband deals on October 12, 2010 at 12:50 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

jtb

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today