/** * * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. * * 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, see <http://www.gnu.org/licenses/>. * **/ package lucee.runtime.type.scope; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import lucee.commons.lang.ExceptionUtil; import lucee.commons.lang.StringUtil; import lucee.runtime.PageContext; import lucee.runtime.config.NullSupportHelper; import lucee.runtime.dump.DumpData; import lucee.runtime.dump.DumpProperties; import lucee.runtime.engine.ThreadLocalPageContext; import lucee.runtime.exp.PageException; import lucee.runtime.listener.ApplicationContext; import lucee.runtime.net.http.ReqRspUtil; import lucee.runtime.op.Caster; import lucee.runtime.security.ScriptProtect; import lucee.runtime.type.Collection; import lucee.runtime.type.KeyImpl; import lucee.runtime.type.Struct; import lucee.runtime.type.StructImpl; import lucee.runtime.type.it.EntryIterator; import lucee.runtime.type.it.KeyIterator; import lucee.runtime.type.util.KeyConstants; import lucee.runtime.type.util.StructSupport; import lucee.runtime.type.util.StructUtil; /** * * * To change the template for this generated type comment go to * Window - Preferences - Java - Code Generation - Code and Comments */ public final class CGIImpl extends StructSupport implements CGI,ScriptProtected { private static final long serialVersionUID = 5219795840777155232L; private static final Collection.Key[] STATIC_KEYS={ KeyConstants._auth_password, KeyConstants._auth_type, KeyConstants._auth_user, KeyConstants._cert_cookie, KeyConstants._cert_flags, KeyConstants._cert_issuer, KeyConstants._cert_keysize, KeyConstants._cert_secretkeysize, KeyConstants._cert_serialnumber, KeyConstants._cert_server_issuer, KeyConstants._cert_server_subject, KeyConstants._cert_subject,KeyConstants._cf_template_path, KeyConstants._content_length, KeyConstants._content_type, KeyConstants._gateway_interface, KeyConstants._http_accept, KeyConstants._http_accept_encoding, KeyConstants._http_accept_language, KeyConstants._http_connection, KeyConstants._http_cookie, KeyConstants._http_host, KeyConstants._http_user_agent, KeyConstants._http_referer, KeyConstants._https, KeyConstants._https_keysize, KeyConstants._https_secretkeysize, KeyConstants._https_server_issuer, KeyConstants._https_server_subject, KeyConstants._path_info, KeyConstants._path_translated, KeyConstants._query_string, KeyConstants._remote_addr, KeyConstants._remote_host, KeyConstants._remote_user, KeyConstants._request_method, KeyConstants._request_url, KeyConstants._script_name, KeyConstants._server_name, KeyConstants._server_port, KeyConstants._server_port_secure, KeyConstants._server_protocol, KeyConstants._server_software, KeyConstants._web_server_api, KeyConstants._context_path, KeyConstants._local_addr, KeyConstants._local_host }; private static Struct staticKeys=new StructImpl(); static{ for(int i=0;i<STATIC_KEYS.length;i++){ staticKeys.setEL(STATIC_KEYS[i],""); } } private static String localAddress=""; private static String localHost=""; static { try { InetAddress addr = InetAddress.getLocalHost(); localAddress=addr.getHostAddress(); localHost=addr.getHostName(); } catch(UnknownHostException uhe) {} } private HttpServletRequest req; private boolean isInit; private Struct internal; private Map<Collection.Key,Collection.Key> aliases; private int scriptProtected; public CGIImpl(){ //this.setReadOnly(true); } @Override public boolean isInitalized() { return isInit; } @Override public void initialize(PageContext pc) { isInit=true; req=pc.getHttpServletRequest(); if(scriptProtected==ScriptProtected.UNDEFINED) { scriptProtected=((pc.getApplicationContext().getScriptProtect()&ApplicationContext.SCRIPT_PROTECT_CGI)>0)? ScriptProtected.YES:ScriptProtected.NO; } //if(internal==null) { internal=new StructImpl(); aliases=new HashMap<Collection.Key,Collection.Key>(); String k,v; Collection.Key key,alias,httpKey; try { Enumeration<String> e = req.getHeaderNames(); while(e.hasMoreElements()) { // keys k =e.nextElement(); key=KeyImpl.init(k); if(k.contains("-")) alias=KeyImpl.init(k.replace('-','_')); else alias=null; httpKey=KeyImpl.init("http_"+(alias==null?key:alias).getString()); // value v = doScriptProtect(req.getHeader(k)); // set value internal.setEL(httpKey,v); // set alias keys aliases.put(key, httpKey); if(alias!=null)aliases.put(alias, httpKey); } } catch(Throwable t){ExceptionUtil.rethrowIfNecessary(t);} //} } @Override public void release(PageContext pc) { isInit=false; scriptProtected=ScriptProtected.UNDEFINED; req=null; internal=null; aliases=null; } @Override public boolean containsKey(Key key) { return internal.containsKey(key) || staticKeys.containsKey(key) || aliases.containsKey(key); } @Override public boolean containsValue(Object value) { Iterator<Object> it = internal.valueIterator(); while(it.hasNext()){ if(it.next().equals(value)) return true; } return false; } @Override public Collection duplicate(boolean deepCopy) { Struct sct=new StructImpl(); StructImpl.copy(this,sct,deepCopy); return sct; } @Override public int size() { return keys().length; } @Override public Collection.Key[] keys() { Set<Collection.Key> set=new HashSet<Collection.Key>(); Iterator<Key> it = internal.keyIterator(); while(it.hasNext())set.add(it.next()); it = staticKeys.keyIterator(); while(it.hasNext())set.add(it.next()); return set.toArray(new Collection.Key[set.size()]); } @Override public Object get(Collection.Key key, Object defaultValue) { // do we have internal? Object res = internal.get(key, NullSupportHelper.NULL()); if(res!=NullSupportHelper.NULL()) return res; // do we have an alias { Key k = aliases.get(key); if(k!=null) { res = internal.get(k, NullSupportHelper.NULL()); if(res!=NullSupportHelper.NULL()) return res; } } if(key.length()>7) { char first=key.lowerCharAt(0); try{ if(first=='a') { if(key.equals(KeyConstants._auth_type)) return store(key,toString(req.getAuthType())); } else if(first=='c') { if(key.equals(KeyConstants._context_path)) return store(key,toString(req.getContextPath())); if(key.equals(KeyConstants._cf_template_path)) return store(key,getPathTranslated()); } else if(first=='h') { if(StringUtil.startsWithIgnoreCase(key.getString(), "http_")) { // _http_if_modified_since if(key.equals(KeyConstants._http_if_modified_since)) { Object o = internal.get(KeyConstants._last_modified,NullSupportHelper.NULL()); if(o!=NullSupportHelper.NULL()) return store(key,(String)o); } } } else if(first=='r') { if(key.equals(KeyConstants._remote_user)) return store(key,toString(req.getRemoteUser())); if(key.equals(KeyConstants._remote_addr)) return store(key,toString(req.getRemoteAddr())); if(key.equals(KeyConstants._remote_host)) return store(key,toString(req.getRemoteHost())); if(key.equals(KeyConstants._request_method)) return store(key,req.getMethod()); if(key.equals(KeyConstants._request_url)) return store(key,ReqRspUtil.getRequestURL( req, true )); if(key.equals(KeyConstants._request_uri)) return store(key,toString(req.getAttribute("javax.servlet.include.request_uri"))); // we do not store this, to be as backward compatible as possible. if(key.getUpperString().startsWith("REDIRECT_")){ // from attributes (key sensitive) Object value = req.getAttribute(key.getString()); if(!StringUtil.isEmpty(value)) return toString(value); // from attributes (key insensitive) Enumeration<String> names = req.getAttributeNames(); String k; while(names.hasMoreElements()){ k=names.nextElement(); if(k.equalsIgnoreCase(key.getString())) { return toString(req.getAttribute(k)); } } } } else if(first=='l') { if(key.equals(KeyConstants._local_addr)) return store(key,toString(localAddress)); if(key.equals(KeyConstants._local_host)) return store(key,toString(localHost)); } else if(first=='s') { if(key.equals(KeyConstants._script_name)) return store(key,ReqRspUtil.getScriptName(null,req)); if(key.equals(KeyConstants._server_name)) return store(key,toString(req.getServerName())); if(key.equals(KeyConstants._server_protocol)) return store(key,toString(req.getProtocol())); if(key.equals(KeyConstants._server_port)) return store(key,Caster.toString(req.getServerPort())); if(key.equals(KeyConstants._server_port_secure)) return store(key,req.isSecure()?"1":"0"); } else if(first=='p') { if(key.equals(KeyConstants._path_info)) { String pathInfo = Caster.toString(req.getAttribute("javax.servlet.include.path_info"),null); if(StringUtil.isEmpty(pathInfo)) pathInfo = Caster.toString(req.getHeader("xajp-path-info"),null); if(StringUtil.isEmpty(pathInfo)) pathInfo = req.getPathInfo(); if(StringUtil.isEmpty(pathInfo)) { pathInfo = Caster.toString(req.getAttribute("requestedPath"),null); if(!StringUtil.isEmpty(pathInfo,true)) { String scriptName = ReqRspUtil.getScriptName(null,req); if ( pathInfo.startsWith(scriptName) ) pathInfo = pathInfo.substring(scriptName.length()); } } if(!StringUtil.isEmpty(pathInfo,true)) return store(key,pathInfo); return ""; } if(key.equals(KeyConstants._path_translated)) return store(key,getPathTranslated()); } else if(first=='q') { if(key.equals(KeyConstants._query_string)) return store(key,doScriptProtect(toString(ReqRspUtil.getQueryString(req)))); } } catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);} } return other(key,defaultValue); } private Object store(Key key, String value) { internal.setEL(key, value); return value; } private Object other(Collection.Key key, Object defaultValue) { if(staticKeys.containsKey(key)) return ""; return defaultValue; } private String getPathTranslated() { try{ PageContext pc = ThreadLocalPageContext.get(); return pc.getBasePageSource().getResourceTranslated(pc).toString(); } catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);} return ""; } private String doScriptProtect(String value) { if(isScriptProtected()) return ScriptProtect.translate(value); return value; } private String toString(Object str) { return StringUtil.toStringEmptyIfNull(str); } @Override public Object get(Collection.Key key) { Object value=get(key,""); if(value==null)value= ""; return value; } @Override public Iterator<Collection.Key> keyIterator() { return new KeyIterator(keys()); } @Override public Iterator<Entry<Key, Object>> entryIterator() { return new EntryIterator(this, keys()); } @Override public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { return StructUtil.toDumpTable(this, "CGI Scope (writable)", pageContext, maxlevel, dp); } @Override public int getType() { return SCOPE_CGI; } @Override public String getTypeAsString() { return "cgi"; } @Override public boolean isScriptProtected() { return scriptProtected==ScriptProtected.YES; } @Override public void setScriptProtecting(ApplicationContext ac,boolean scriptProtecting) { scriptProtected=scriptProtecting?ScriptProtected.YES:ScriptProtected.NO; } @Override public Object remove(Key key) throws PageException { Key k = aliases.remove(key); if(k!=null) key=k; Object rtn=internal.remove(key); if(staticKeys.containsKey(key))internal.set(key, ""); // we do this to avoid to this get reinit again return rtn; } @Override public Object removeEL(Key key) { Key k = aliases.remove(key); if(k!=null) key=k; Object rtn=internal.removeEL(key); if(staticKeys.containsKey(key))internal.setEL(key, ""); // we do this to avoid to this get reinit again return rtn; } @Override public void clear() { Key[] keys = keys(); for(int i=0;i<keys.length;i++){ removeEL(keys[i]); } } @Override public Object set(Key key, Object value) throws PageException { Key k = aliases.get(key); if(k!=null) key=k; return internal.set(key, value); } @Override public Object setEL(Key key, Object value) { Key k = aliases.get(key); if(k!=null) key=k; return internal.setEL(key, value); } @Override public Iterator<Object> valueIterator() { return internal.valueIterator(); } }