001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.type.scope;
020
021import java.net.InetAddress;
022import java.net.UnknownHostException;
023import java.util.Enumeration;
024import java.util.HashMap;
025import java.util.Iterator;
026import java.util.Map;
027
028import javax.servlet.http.HttpServletRequest;
029
030import lucee.commons.lang.ExceptionUtil;
031import lucee.commons.lang.StringUtil;
032import lucee.runtime.PageContext;
033import lucee.runtime.config.NullSupportHelper;
034import lucee.runtime.dump.DumpData;
035import lucee.runtime.dump.DumpProperties;
036import lucee.runtime.engine.ThreadLocalPageContext;
037import lucee.runtime.listener.ApplicationContext;
038import lucee.runtime.net.http.ReqRspUtil;
039import lucee.runtime.op.Caster;
040import lucee.runtime.security.ScriptProtect;
041import lucee.runtime.type.Collection;
042import lucee.runtime.type.KeyImpl;
043import lucee.runtime.type.ReadOnlyStruct;
044import lucee.runtime.type.Struct;
045import lucee.runtime.type.StructImpl;
046import lucee.runtime.type.it.EntryIterator;
047import lucee.runtime.type.it.KeyIterator;
048import lucee.runtime.type.it.StringIterator;
049import lucee.runtime.type.util.KeyConstants;
050import lucee.runtime.type.util.StructUtil;
051
052/**
053 *
054 *
055 * To change the template for this generated type comment go to
056 * Window - Preferences - Java - Code Generation - Code and Comments
057 */
058public final class CGIImplReadOnly extends ReadOnlyStruct implements CGI,ScriptProtected {
059        
060        private static final long serialVersionUID = 5219795840777155232L;
061
062        private static final Collection.Key[] keys={
063                KeyConstants._auth_password, KeyConstants._auth_type, KeyConstants._auth_user, KeyConstants._cert_cookie, KeyConstants._cert_flags, 
064                KeyConstants._cert_issuer, KeyConstants._cert_keysize, KeyConstants._cert_secretkeysize, KeyConstants._cert_serialnumber, 
065                KeyConstants._cert_server_issuer, KeyConstants._cert_server_subject, KeyConstants._cert_subject,KeyConstants._cf_template_path, 
066                KeyConstants._content_length, KeyConstants._content_type, KeyConstants._gateway_interface, KeyConstants._http_accept, 
067                KeyConstants._http_accept_encoding, KeyConstants._http_accept_language, KeyConstants._http_connection, KeyConstants._http_cookie, 
068                KeyConstants._http_host, KeyConstants._http_user_agent, KeyConstants._http_referer, KeyConstants._https, KeyConstants._https_keysize, 
069                KeyConstants._https_secretkeysize, KeyConstants._https_server_issuer, KeyConstants._https_server_subject, KeyConstants._path_info,
070                KeyConstants._path_translated, KeyConstants._query_string, KeyConstants._remote_addr, KeyConstants._remote_host, KeyConstants._remote_user, 
071                KeyConstants._request_method, KeyConstants._request_url, KeyConstants._script_name, KeyConstants._server_name, KeyConstants._server_port, KeyConstants._server_port_secure,
072                KeyConstants._server_protocol, KeyConstants._server_software, KeyConstants._web_server_api, KeyConstants._context_path, KeyConstants._local_addr, 
073                KeyConstants._local_host
074        };
075        private static Struct staticKeys=new StructImpl();
076        static{
077                for(int i=0;i<keys.length;i++){
078                        staticKeys.setEL(keys[i],"");
079                }
080        }
081        
082        private static String localAddress="";
083        private static String localHost="";
084        
085        static {
086                try {
087                        InetAddress addr = InetAddress.getLocalHost();
088                        localAddress=addr.getHostAddress();
089                        localHost=addr.getHostName();
090                }
091                catch(UnknownHostException uhe) {}
092        }
093        
094        private HttpServletRequest req;
095        private boolean isInit;
096        //private PageContext pc;
097        private Struct https;
098        private Struct headers;
099        private int scriptProtected;
100
101        private boolean disconnected;
102        private Map<Key, Object> disconnectedData;
103        
104        public CGIImplReadOnly(){
105                this.setReadOnly(true);
106        }
107        
108
109        public void disconnect() {
110                if(disconnected) return;
111                
112                disconnectedData=new HashMap<Key, Object>();
113                for(int i=0;i<keys.length;i++){
114                        disconnectedData.put(keys[i], get(keys[i], "")); 
115                }
116                req=null;
117        }
118        
119
120        @Override
121        public boolean containsKey(Key key) {
122                return staticKeys.containsKey(key);
123        }
124        
125        @Override
126        public boolean containsValue(Object value) {
127                // TODO Auto-generated method stub
128                return super.containsValue(value);
129        }
130        @Override
131        public Collection duplicate(boolean deepCopy) {
132                Struct sct=new StructImpl();
133                copy(this,sct,deepCopy);
134                return sct;
135        }
136        
137        
138        @Override
139        public int size() {
140                return keys.length;
141        }
142
143        public Collection.Key[] keys() {
144                return keys;
145        }
146        
147        @Override
148        public Object get(Collection.Key key, Object defaultValue) {
149                
150                if(https==null) {
151                        https=new StructImpl();
152                        headers=new StructImpl();
153                        String k,v;
154                        try {
155                                Enumeration e = req.getHeaderNames();
156                        
157                                while(e.hasMoreElements()) {
158                                k = (String)e.nextElement();
159                                v = req.getHeader(k);
160                                //print.err(k.length()+":"+k);
161                                headers.setEL(KeyImpl.init(k),v);
162                                headers.setEL(KeyImpl.init(k=k.replace('-','_')),v);
163                                https.setEL(KeyImpl.init("http_"+k),v); 
164                        }
165                        }
166                        catch(Throwable t){
167                                ExceptionUtil.rethrowIfNecessary(t);
168                                t.printStackTrace();
169                        }
170                }
171                
172                String lkey=key.getLowerString();
173        
174            
175        if(lkey.length()>7) {
176            char first=lkey.charAt(0);
177            if(first=='a') {
178                if(key.equals(KeyConstants._auth_type)) return toString(req.getAuthType());
179            }
180            else if(first=='c') {
181                if(key.equals(KeyConstants._context_path))return toString(req.getContextPath());
182                if(key.equals(KeyConstants._cf_template_path)) return getPathTranslated();
183            }
184            else if(first=='h') {
185                if(lkey.startsWith("http_")){
186                        Object o = https.get(key,NullSupportHelper.NULL());
187                    if(o==NullSupportHelper.NULL() && key.equals(KeyConstants._http_if_modified_since))
188                        o = https.get(KeyConstants._last_modified,NullSupportHelper.NULL());
189                    if(o!=NullSupportHelper.NULL())return doScriptProtect((String)o);
190            }
191            }
192            else if(first=='r') {
193                if(key.equals(KeyConstants._remote_user))               return toString(req.getRemoteUser());
194                if(key.equals(KeyConstants._remote_addr))               {
195                        return toString(req.getRemoteAddr());
196                }
197                if(key.equals(KeyConstants._remote_host))               return toString(req.getRemoteHost());
198                if(key.equals(KeyConstants._request_method))            return req.getMethod();
199                if(key.equals(KeyConstants._request_url))               return ReqRspUtil.getRequestURL( req, true );
200                if(key.equals(KeyConstants._request_uri))               return toString(req.getAttribute("javax.servlet.include.request_uri"));
201                if(key.getUpperString().startsWith("REDIRECT_")){
202                        // from attributes (key sensitive)
203                        Object value = req.getAttribute(key.getString());
204                        if(!StringUtil.isEmpty(value)) return toString(value);
205                        
206                        // from attributes (key insensitive)
207                        Enumeration<String> names = req.getAttributeNames();
208                        String k;
209                        while(names.hasMoreElements()){
210                                k=names.nextElement();
211                                if(k.equalsIgnoreCase(key.getString())) {
212                                        return toString(req.getAttribute(k));
213                                }
214                        }
215                }
216            }
217            
218            
219            else if(first=='l') {
220                if(key.equals(KeyConstants._local_addr))                return toString(localAddress);
221                if(key.equals(KeyConstants._local_host))                return toString(localHost);
222            }
223            else if(first=='s') {
224                if(key.equals(KeyConstants._script_name)) 
225                        return ReqRspUtil.getScriptName(null,req);
226                                //return StringUtil.emptyIfNull(req.getContextPath())+StringUtil.emptyIfNull(req.getServletPath());
227                        if(key.equals(KeyConstants._server_name))               return toString(req.getServerName());
228                if(key.equals(KeyConstants._server_protocol))   return toString(req.getProtocol());
229                if(key.equals(KeyConstants._server_port))               return Caster.toString(req.getServerPort());
230                if(key.equals(KeyConstants._server_port_secure))return req.isSecure()?"1":"0";
231                
232            }
233            else if(first=='p') {
234                if(key.equals(KeyConstants._path_info)) {
235                        String pathInfo = Caster.toString(req.getAttribute("javax.servlet.include.path_info"),null);
236                        if(StringUtil.isEmpty(pathInfo)) pathInfo = Caster.toString(req.getHeader("xajp-path-info"),null);
237                        if(StringUtil.isEmpty(pathInfo)) pathInfo = req.getPathInfo();
238                        if(StringUtil.isEmpty(pathInfo)) {
239                                pathInfo = Caster.toString(req.getAttribute("requestedPath"),null);
240                                if(!StringUtil.isEmpty(pathInfo,true)) {
241                                        String scriptName = ReqRspUtil.getScriptName(null,req);
242                                        if ( pathInfo.startsWith(scriptName) )
243                                                pathInfo = pathInfo.substring(scriptName.length());
244                                }
245                        }
246                    
247                        if(!StringUtil.isEmpty(pathInfo,true)) return pathInfo;
248                    return "";
249                }
250                if(key.equals(KeyConstants._path_translated)) return getPathTranslated();
251            }
252            else if(first=='q') {
253                if(key.equals(KeyConstants._query_string))return doScriptProtect(toString(ReqRspUtil.getQueryString(req)));
254            }
255        }
256        
257        // check header
258        String headerValue = (String) headers.get(key,null);//req.getHeader(key.getString());
259            if(headerValue != null) return doScriptProtect(headerValue);
260            
261        return other(key,defaultValue);
262        }
263        
264        private Object getPathTranslated() {
265                try{
266                        PageContext pc = ThreadLocalPageContext.get();
267                        return pc.getBasePageSource().getResourceTranslated(pc).toString();
268                }
269                catch(Throwable t){
270                        ExceptionUtil.rethrowIfNecessary(t);
271                }
272                return "";
273        }
274
275
276        private Object other(Collection.Key key, Object defaultValue) {
277                if(staticKeys.containsKey(key)) return "";
278                return defaultValue;
279        }
280        
281        private String doScriptProtect(String value) {
282                if(isScriptProtected()) return ScriptProtect.translate(value);
283                return value;
284        }
285        
286        private String toString(Object str) {
287                return StringUtil.toStringEmptyIfNull(str);
288        }
289        
290        @Override
291        public Object get(Collection.Key key) {
292                Object value=get(key,"");
293                if(value==null)value= "";
294                return value;
295        }
296        
297        @Override
298        public Iterator<Collection.Key> keyIterator() {
299                return new KeyIterator(keys());
300        }
301    
302    @Override
303        public Iterator<String> keysAsStringIterator() {
304        return new StringIterator(keys());
305    }
306        
307        @Override
308        public Iterator<Entry<Key, Object>> entryIterator() {
309                return new EntryIterator(this, keys());
310        }
311        
312        @Override
313        public boolean isInitalized() {
314                return isInit;
315        }
316        
317        @Override
318        public void initialize(PageContext pc) {
319                isInit=true;
320                req=pc.getHttpServletRequest();
321                
322                
323        if(scriptProtected==ScriptProtected.UNDEFINED) {
324                        scriptProtected=((pc.getApplicationContext().getScriptProtect()&ApplicationContext.SCRIPT_PROTECT_CGI)>0)?
325                                        ScriptProtected.YES:ScriptProtected.NO;
326                }
327        }
328        
329        @Override
330        public void release() {
331                isInit=false;
332                scriptProtected=ScriptProtected.UNDEFINED; 
333                req=null;
334                https=null;
335                headers=null;
336                
337        }
338        
339        @Override
340        public void release(PageContext pc) {
341                release();
342        }
343        
344        @Override
345        public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
346                return StructUtil.toDumpTable(this, "CGI Scope", pageContext, maxlevel, dp);
347        }
348    
349    @Override
350    public int getType() {
351        return SCOPE_CGI;
352    }
353    
354    @Override
355    public String getTypeAsString() {
356        return "cgi";
357    }
358    
359        public boolean isScriptProtected() {
360                return scriptProtected==ScriptProtected.YES;
361        }
362        
363        @Override
364        public void setScriptProtecting(ApplicationContext ac,boolean scriptProtecting) {
365                scriptProtected=scriptProtecting?ScriptProtected.YES:ScriptProtected.NO;
366        }
367
368        
369        public static String getDomain(HttpServletRequest req) { // DIFF 23
370                StringBuffer sb=new StringBuffer();
371                sb.append(req.isSecure()?"https://":"http://");
372                sb.append(req.getServerName());
373                sb.append(':');
374                sb.append(req.getServerPort());
375                if(!StringUtil.isEmpty(req.getContextPath()))sb.append(req.getContextPath());
376                return sb.toString();
377        }
378
379}