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
}
}