package com.idega.presentation.ui; import java.io.IOException; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.idega.core.builder.business.BuilderService; import com.idega.core.builder.business.ICBuilderConstants; import com.idega.core.builder.data.ICPage; import com.idega.presentation.IWContext; import com.idega.presentation.Page; import com.idega.presentation.PresentationObject; import com.idega.util.FileUtil; import com.idega.util.Index; import com.idega.util.IndexComparator; import com.idega.util.URLUtil; import com.idega.util.text.TextSoap; /** * A presentationObject that uses FileUtil.getStringFromURL to serverside * include a given URL * * @author <a href="mailto:eiki@idega.is">Eirikur Hrafnsson</a> * @version 1.0 */ public class PageIncluder extends PresentationObject implements Index { private static final String IB_PAGE_PARAMETER = ICBuilderConstants.IB_PAGE_PARAMETER; private String URL = null; private String BASEURL = null; private String BASEURLHTTPS = null; private String RELATIVEURL = null; private String pageIncluderPrefix = null; private String _label = null; private String _sendToLabel = null; private ICPage _sendToPage = null; private String _sendToPageIfSet = null; private String sessionId = null; private String sessionURL = null; private String token = null; private String tokenReplacer = null; private String serverName = null; private String httpPrefix = null; private String httpsPrefix = null; private Map findReplaceStrings = null; private String out; private int index = 1000; private static final String PAGE_INCLUDER_PARAMETER_NAME = "iw_uri_"; private static final String PAGE_INCLUDER_SESSION_NAME = "iw_session_token"; private int instanceId; private boolean forceFrame = false; private boolean useSecureLinks = false; private boolean changeURL = false; private final String symbol = "$"; private Map allowedDomainsAndIPNumberMap; private String pageEncoding = "UTF-8"; public String getPageEncoding() { return pageEncoding; } public void setPageEncoding(String pageEncoding) { this.pageEncoding = pageEncoding; } public PageIncluder() { super(); } public PageIncluder(String URL) { this(); this.URL = URL; } private void sortAndProcess(IWContext iwc) { // sort Page parent = this.getParentPage(); /** @todo get in main **/ List objects = parent.getChildrenRecursive(); ArrayList includers = new ArrayList(); Iterator iter = objects.iterator(); while (iter.hasNext()) { Object item = iter.next(); if (item instanceof PageIncluder) { includers.add(item); } } IndexComparator indexer = new IndexComparator( IndexComparator.ORDER_BY_INDEX); includers = indexer.sortedArrayList(includers); // process Iterator iter2 = includers.iterator(); while (iter2.hasNext()) { PageIncluder item = (PageIncluder) iter2.next(); try { item.process(iwc); } catch (Exception ex) { ex.printStackTrace(System.err); } } } public void setIndex(int index) { this.index = index; } public int getIndex() { return this.index; } public void main(IWContext iwc) throws Exception { Page fromPage = this.getParentPage(); this.instanceId = getICObjectInstanceID(); this.changeURL = (iwc.isParameterSet(PAGE_INCLUDER_PARAMETER_NAME + this._label)) || (iwc.isParameterSet(PAGE_INCLUDER_PARAMETER_NAME + this.instanceId)); if (this.changeURL) { this.changeURL = canChangeURLFromRequest(iwc); } if (this.changeURL && (this._sendToPage != null) && iwc.isParameterSet(this._sendToPageIfSet)) {// forwarding forwardToIBPage(fromPage, this._sendToPage, iwc); } else if (this.out == null) { sortAndProcess(iwc);// ususal } } /** * Security check to stop hackers from using the pageincluder from a domain * that is not allowed * * @param iwc */ private boolean canChangeURLFromRequest(IWContext iwc) { if (this.allowedDomainsAndIPNumberMap != null) { boolean changingTheURLFromRequest = (iwc .isParameterSet(PAGE_INCLUDER_PARAMETER_NAME + this._label)) || (iwc.isParameterSet(PAGE_INCLUDER_PARAMETER_NAME + this.instanceId)); if (changingTheURLFromRequest) { String url = iwc.getParameter(PAGE_INCLUDER_PARAMETER_NAME + this._label); if (url == null || "".equals(url)) { url = iwc.getParameter(PAGE_INCLUDER_PARAMETER_NAME + this.instanceId); } URLUtil util = new URLUtil(url); String domainOrIpPart = util.getHost(); if (!this.allowedDomainsAndIPNumberMap .containsKey(domainOrIpPart)) { return false;// if the domain is not allowed to ask for // pageincluding then return false } } } return true; } public void print(IWContext iwc) throws IOException { if (this.URL != null) { if (this.out != null) { println(this.out); } this.out = null; } } protected void process(IWContext iwc) throws Exception { this.serverName = iwc.getServerName(); this.instanceId = getICObjectInstanceID(); // pageincluderprefix httpprefix etc... setPrefixes(iwc); // get parameters and change the pageincluders url if needed String loc = getLocation(iwc); // System.out.println("Loc before = "+loc); // get a session id from a session creating page if ((this.sessionURL != null) && (this.token != null)) { if (this.sessionId == null) { this.sessionId = (String) iwc .getSessionAttribute(PAGE_INCLUDER_SESSION_NAME); if (this.sessionId == null) { this.sessionId = FileUtil.getStringFromURL(this.sessionURL); // debug("Sessions id is : "+sessionId); } } iwc.setSessionAttribute(PAGE_INCLUDER_SESSION_NAME, this.sessionId); loc = TextSoap.findAndReplace(loc, this.token, this.sessionId); loc = TextSoap.findAndCut(loc, "\r\n"); loc = TextSoap.findAndCut(loc, "\n"); } else if ((this.sessionId != null) && (this.token != null)) { loc = TextSoap.findAndReplace(loc, this.token, this.sessionId); } // System.out.println("Location url is: "+loc+" and index is: "+index); if (loc != null && !loc.equals("")) { this.out = FileUtil.getStringFromURL(loc, getPageEncoding()); URL url = new URL(loc); this.BASEURL = url.getProtocol() + "://" + url.getHost() + "/"; this.BASEURLHTTPS = "https://" + url.getHost() + "/"; if (loc.lastIndexOf("/") == 6) { loc += "/"; } this.RELATIVEURL = loc.substring(0, loc.lastIndexOf("/") + 1); /** * @todo use expressions to make none case sensitive or implement * using HTMLDocumentLoader (Advanced Swing); * **/ /* * Finish if needed but make sure it is a configurable option just * an idea to get all javascripts and styles from the real page List * headerTag = TextSoap.FindAllBetween(out, "<head>","</head>"); * if(headerTag!=null && headerTag.isEmpty()) { String headerContent * = (String)headerTag.iterator().next(); List styles = * TextSoap.FindAllBetween(out, * "<style type=\"text/css\">\n","</style>\n"); if(styles!=null && * styles.isEmpty()) { this.getParentPage().setStyleDefinition()... * } } */ this.out = TextSoap.stripHTMLTagAndChangeBodyTagToTable(this.out); this.out = preProcess(this.out, iwc); if (this.forceFrame) { this.out = encodeQueryStrings(this.out); } this.out = changeAHrefAttributes(this.out); this.out = changeFormActionAttributes(this.out); this.out = changeSrcAttributes(this.out); this.out = changeJSOpenWindowURL(this.out); this.out = postProcess(this.out, iwc); } } protected String preProcess(String html, IWContext iwc) { html = TextSoap.findAndReplace(html, "href=\"javascript", "httpIW_PREPROCESSED"); return html; } protected String postProcess(String html, IWContext iwc) { html = TextSoap.findAndReplace(html, "httpIW_PREPROCESSED", "href=\"javascript"); html = findAndReplaceStrings(html); // Make images from this server (idegaweb) always follow the protocol // being used http/https // @todo this is case sensitive and could break! move to IWContext. Also // done in Link, SubmitButton, Image and PageIncluder if (iwc.getRequest().isSecure()) { html = TextSoap.findAndReplace(html, "src=\"http://" + this.serverName, "src=\"https://" + this.serverName); } return html; } /** * @todo temporary Strengs fix. We should change the find replace method with * the simpler:<br> * 1. find all between symbol=".." strings 2. Change them 3. Find * replace the original found strings with the new ones */ private String findAndReplaceStrings(String html) { if (this.findReplaceStrings != null) { Set keys = this.findReplaceStrings.keySet(); Iterator iter = keys.iterator(); String key; while (iter.hasNext()) { key = (String) iter.next(); html = TextSoap.findAndReplace(html, key, (String) this.findReplaceStrings.get(key)); } } return html; } public void setFindAndReplaceString(String stringToFind, String stringToReplace) { if (this.findReplaceStrings == null) { this.findReplaceStrings = new HashMap(); } this.findReplaceStrings.put(stringToFind, stringToReplace); } protected String changeAHrefAttributes(String html) { /* * Possibilities tags: ahref and action src /xxx/xx * prefix+baseurl+/xxx/xx baseurl+/xxx/xx xxx/xx * prefix+relativeurl+/+xxx/xx relative+/+xxx/xx http:// prefix ekkert * //slashdot.org/ prefix+http: http: */ html = insertPageIncludeInTagIgnoreCase("href", html); return html; } protected String changeFormActionAttributes(String html) { html = insertPageIncludeInTagIgnoreCase("action", html); return html; } protected String changeSrcAttributes(String html) { html = changeURLToAbsoluteValueIgnoreCase("src", html); html = changeURLToAbsoluteValueIgnoreCase("background", html); return html; } protected String insertPageIncludeInTagIgnoreCase(String tag, String html) { html = insertPageIncludeInTag(tag.toLowerCase(), html); html = insertPageIncludeInTag(tag.toUpperCase(), html); return html; } protected String insertPageIncludeInTag(String tag, String html) { // do NOT change the order of replacements! // "logic" is as follows /* * prefix of url to replace -> what changes to * * 1. nothing -> http+relativeurl = baseurl // -> baseurl / -> baseurl * http -> donothing = baseurl https -> donothing = httpsbaseurl http to * another server -> do nothing * * 2. force in frame addon baseurl -> httpprefix+baseurl * * * 2b. httpprefix+baseurl -> nothing httpsbaseurl -> * httpsprefix+httpsbaseurl */ tag = tag + "=\""; String prefixHttp = tag + this.httpPrefix; String prefixHttps = tag + this.httpsPrefix; html = TextSoap.findAndReplace(html, tag + "//", tag + this.BASEURL);// the // // // case html = TextSoap.findAndReplace(html, tag + "/", tag + this.BASEURL); String[] unchangedUrlsPrefixes = new String[] { "http:", "ftp:", "mailto:", "https:" }; // prefixes of urls not to modify, add as // needed html = TextSoap.findAndReplace(html, tag, unchangedUrlsPrefixes, tag + this.RELATIVEURL); // System.out.println("tag+BASEURL"+tag+BASEURL); // System.out.println("tag+RELATIVEURL"+tag+RELATIVEURL); if (this.forceFrame) { html = TextSoap.findAndReplace(html, tag + this.BASEURL, prefixHttp + this.BASEURL);// the http://baseurl case skipped the // tailing / html = TextSoap.findAndReplace(html, tag + this.BASEURLHTTPS, prefixHttps + this.BASEURL);// the https:// case } return html; } protected String getCurrentIBPageIDToURLString(IWContext iwc) throws Exception { BuilderService bservice = getBuilderService(iwc); return IB_PAGE_PARAMETER + "=" + bservice.getCurrentPageId(iwc); } protected String getSendToPageURLString() { return IB_PAGE_PARAMETER + "=" + this._sendToPage.getID(); } protected String changeURLToAbsoluteValueIgnoreCase(String tag, String html) { html = changeURLToAbsoluteValue(tag.toLowerCase(), html); html = changeURLToAbsoluteValue(tag.toUpperCase(), html); return html; } protected String changeURLToAbsoluteValue(String tag, String html) { html = TextSoap.findAndReplace(html, tag + "=\"//", tag + "=\"" + "http://");// the // case html = TextSoap.findAndReplace(html, tag + "=\"/", tag + "=\"" + this.BASEURL);// the / case html = TextSoap.findAndReplace(html, tag + "=\"", "http://", tag + "=\"" + this.RELATIVEURL); return html; } private String symbolReplace(String html, String tag) { return TextSoap.findAndReplace(html, this.symbol + tag, "&" + tag); } protected String encodeQueryStrings(String html) { // laddi changed links in idegaweb to use amp; instead of a & // so we need to fix that here! html = TextSoap.findAndReplace(html, "&", "&"); // laddi again, only replacing single &, a javascript issue html = TextSoap.findAndReplace(html, "&", "&", this.symbol); // fixing this should be done with a HTMLEditor object OR // make a single general expression fix // by getting all between (textSoap) changing them and then use a find // replace on the originals html = symbolReplace(html, "eth;"); html = symbolReplace(html, "ETH;"); html = symbolReplace(html, "thorn;"); html = symbolReplace(html, "THORN;"); html = symbolReplace(html, "aelig;"); html = symbolReplace(html, "AElig;"); html = symbolReplace(html, "ouml;"); html = symbolReplace(html, "Ouml;"); html = symbolReplace(html, "auml;"); html = symbolReplace(html, "Auml;"); html = symbolReplace(html, "euml;"); html = symbolReplace(html, "Euml;"); html = symbolReplace(html, "uuml;"); html = symbolReplace(html, "Uuml;"); html = symbolReplace(html, "nbsp;"); // html = symbolReplace(html,"amp;");// a muuu point see top of method html = symbolReplace(html, "quot;"); html = symbolReplace(html, "middot"); html = symbolReplace(html, "raquo;"); html = symbolReplace(html, "#149;"); html = symbolReplace(html, "#039;"); html = symbolReplace(html, "#169;"); html = symbolReplace(html, "#8211;"); html = symbolReplace(html, "gt;"); html = symbolReplace(html, "pound;"); html = symbolReplace(html, "yen;"); html = symbolReplace(html, "copy;"); html = symbolReplace(html, "reg;"); html = symbolReplace(html, "szlig;"); html = symbolReplace(html, "#cedil;"); html = symbolReplace(html, "ccedil;"); html = symbolReplace(html, "Ccedil;"); html = symbolReplace(html, "cedil;"); html = symbolReplace(html, "oslash;"); html = symbolReplace(html, "Oslash;"); html = TextSoap.findAndReplace(html, " " + this.symbol + " ", " & "); html = TextSoap.findAndReplace(html, this.symbol + " ", "& "); // islenskir broddstafir html = symbolReplace(html, "aacute;"); html = symbolReplace(html, "Aacute;"); html = symbolReplace(html, "eacute;"); html = symbolReplace(html, "Eacute;"); html = symbolReplace(html, "iacute;"); html = symbolReplace(html, "Iacute;"); html = symbolReplace(html, "uacute;"); html = symbolReplace(html, "Uacute;"); html = symbolReplace(html, "oacute;"); html = symbolReplace(html, "Oacute;"); html = symbolReplace(html, "yacute;"); html = symbolReplace(html, "Yacute;"); return html; } protected String decodeQueryString(String query) { return TextSoap.findAndReplace(query, this.symbol, "&"); } protected String copyJavaScript(String html, IWContext iwc) { return html; } protected String copyIncludes(String html, IWContext iwc) { return html; } public synchronized Object clone() { PageIncluder obj = null; try { obj = (PageIncluder) super.clone(); obj.URL = this.URL; obj.BASEURL = this.BASEURL; obj.RELATIVEURL = this.RELATIVEURL; obj.pageIncluderPrefix = this.pageIncluderPrefix; obj.instanceId = this.instanceId; obj.sessionId = this.sessionId; obj.sessionURL = this.sessionURL; obj.token = this.token; obj.tokenReplacer = this.tokenReplacer; obj.out = this.out; obj.index = this.index; } catch (Exception ex) { ex.printStackTrace(System.err); } return obj; } public void setURL(String URL) { this.URL = URL; } public void setSessionId(String sessionId) { this.sessionId = sessionId; } public void setURLToGetSessionIDFrom(String sessionURL) { this.sessionURL = sessionURL; } public void setTokenToReplaceWithSessionId(String token) { this.token = token; } public void setForceInFrame(boolean forceFrame) { this.forceFrame = forceFrame; } public void setKeepSecure(boolean useSecureLinks) { this.useSecureLinks = useSecureLinks; } public void setLabel(String label) { this._label = label; } /** * Redirects the URL from this PageIncluder to another PageIncluder with the * corresponding label. * * @param label * The label of the PageIncluder which we want to redirect to. */ public void setRedirectTo(String label) { this._sendToLabel = label; } public String getLabel() { return this._label; } public String getRedirectTo() { return this._sendToLabel; } public void setSendToPage(ICPage page) { this._sendToPage = page; } public ICPage getSendToPage() { return this._sendToPage; } public void setSendToPageIfSet(String condition) { this._sendToPageIfSet = condition; } public String getSendToPageIfSet() { return this._sendToPageIfSet; } public void forwardToIBPage(Page fromPage, ICPage page, IWContext iwc) throws Exception { StringBuffer URL = new StringBuffer(); BuilderService bservice = getBuilderService(iwc); URL.append(bservice.getPageURI(((Integer) page.getPrimaryKeyValue()) .intValue())); URL.append('&'); String query = getRequest().getQueryString(); if (this._sendToLabel != null) { query = TextSoap.findAndReplace(query, PAGE_INCLUDER_PARAMETER_NAME + this.instanceId, PAGE_INCLUDER_PARAMETER_NAME + this._sendToLabel); } URL.append(query); fromPage.setToRedirect(URL.toString()); fromPage.empty(); } /** * changes the pageincluders url if needed and adds all parameters from the * request. */ private String getLocation(IWContext iwc) { StringBuffer location = new StringBuffer(); String query = null; StringBuffer queryBuf = new StringBuffer(); String instanceParam = PAGE_INCLUDER_PARAMETER_NAME + this.instanceId; String labelParam = PAGE_INCLUDER_PARAMETER_NAME + this._label; // get all parameters even from post actions Enumeration enumer = iwc.getParameterNames(); while (enumer.hasMoreElements()) { String param = (String) enumer.nextElement(); // debug(param+" : "+iwc.getParameter(param)); if (param.equals(instanceParam) || param.equals(labelParam)) { boolean canChangeURL = canChangeURLFromRequest(iwc); if (canChangeURL) { this.URL = decodeQueryString(iwc.getParameter(param)); } // System.out.println("Changing location to:"+location.toString()); } else { if (param.indexOf(PAGE_INCLUDER_PARAMETER_NAME) == -1) { String[] values = iwc.getParameterValues(param); for (int i = 0; i < values.length; i++) { queryBuf.append(param); queryBuf.append("="); queryBuf.append(URLEncoder.encode(values[i])); queryBuf.append("&"); } } } }// while ends query = queryBuf.toString(); location.append(this.URL); if (!query.equals("")) { if (this.URL.endsWith("/")) {// check if the url ends with a slash location.append("?"); } else {// no slash at end if (this.URL.indexOf("?") == -1) {// check if the url contains a // ? if (this.URL.indexOf("/", 8) != -1) {// check if the url // contains a slash location.append("?"); } else { location.append("/?"); } } else {// just add to the parameters location.append("&"); } } // add the extra parameters location.append(query); } String finalLocationString = finalizeLocationString( location.toString(), iwc); return finalLocationString; } /** * A method for extending classes to influence the location string (the url) * that is sent to the real page. For example to add extra parameters. * * @param location * The finished url to the real page the pageincluder is * including * @return */ protected String finalizeLocationString(String location, IWContext iwc) { return location; } private void setPrefixes(IWContext iwc) throws Exception { if (this.forceFrame) { StringBuffer buf = new StringBuffer(); String uri = iwc.getRequestURI(); buf.append(uri); buf.append('?'); if (this._sendToPage != null) { if ((this._sendToLabel != null) && (this._sendToPageIfSet == null)) { buf.append(getSendToPageURLString()); buf.append('&'); buf.append(PAGE_INCLUDER_PARAMETER_NAME); buf.append(this._sendToLabel); buf.append('='); } else { buf.append(getCurrentIBPageIDToURLString(iwc)); buf.append('&'); buf.append(PAGE_INCLUDER_PARAMETER_NAME); buf.append(this.instanceId); buf.append('='); } } else { buf.append(getCurrentIBPageIDToURLString(iwc)); buf.append('&'); if ((this._sendToLabel != null) && (this._sendToPageIfSet == null)) { buf.append(PAGE_INCLUDER_PARAMETER_NAME); buf.append(this._sendToLabel); buf.append('='); } else { buf.append(PAGE_INCLUDER_PARAMETER_NAME); buf.append(this.instanceId); buf.append('='); } } this.pageIncluderPrefix = buf.toString(); if (this.useSecureLinks) { buf.append("https://"); buf.append(iwc.getServerName()); } StringBuffer buf2 = new StringBuffer(); buf2.append("http://").append(this.serverName) .append(this.pageIncluderPrefix); // .append("http://"); this.httpPrefix = buf2.toString(); // System.out.println("httpPrefix"+httpPrefix); this.httpsPrefix = "https://" + this.httpPrefix.substring(7, this.httpPrefix.length()); // System.out.println("httpSPrefix"+httpsPrefix); // System.out.println("PAGEINCLUDER PREFIX = "+pageIncluderPrefix); } else { this.pageIncluderPrefix = ""; } } private String changeJSOpenWindowURL(String html) { String regex = ":openwindow\\(\\\'\\/servlet\\/WindowOpener\\??[\\w+\\=\\-?.+\\" + this.symbol + "?]*\\\',"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(html); StringBuffer sb = new StringBuffer(); while (matcher.find()) { StringBuffer sbURL = new StringBuffer(); StringBuffer sbSymbol = new StringBuffer(); String rURL = "\\(\\\'\\/servlet"; Pattern pURL = Pattern.compile(rURL); Matcher mURL = pURL.matcher(matcher.group()); while (mURL.find()) { mURL.appendReplacement(sbURL, "('" + this.BASEURL + "servlet"); } mURL.appendTail(sbURL); String rSymbol = "\\" + this.symbol; Pattern pSymbol = Pattern.compile(rSymbol); Matcher mSymbol = pSymbol.matcher(sbURL.toString()); while (mSymbol.find()) { mSymbol.appendReplacement(sbSymbol, "&"); } mSymbol.appendTail(sbSymbol); matcher.appendReplacement(sb, sbSymbol.toString()); } matcher.appendTail(sb); return sb.toString(); } public void setToAddRequiredIPOrDomain(String allowedIpOrDomain) { if (this.allowedDomainsAndIPNumberMap == null) { this.allowedDomainsAndIPNumberMap = new HashMap(); } this.allowedDomainsAndIPNumberMap.put(allowedIpOrDomain, allowedIpOrDomain);// map to avoid adding endlessly into a list // in the builder } }