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.commons.io.res.type.s3;
020
021import java.io.IOException;
022import java.util.Map;
023
024import lucee.commons.io.res.Resource;
025import lucee.commons.io.res.ResourceLock;
026import lucee.commons.io.res.ResourceProvider;
027import lucee.commons.io.res.ResourceProviderPro;
028import lucee.commons.io.res.Resources;
029import lucee.commons.lang.ExceptionUtil;
030import lucee.commons.lang.StringUtil;
031import lucee.commons.lang.types.RefInteger;
032import lucee.commons.lang.types.RefIntegerImpl;
033import lucee.runtime.PageContext;
034import lucee.runtime.engine.ThreadLocalPageContext;
035import lucee.runtime.net.s3.Properties;
036import lucee.runtime.net.s3.PropertiesImpl;
037
038public final class S3ResourceProvider implements ResourceProviderPro {
039        
040        
041        private int socketTimeout=-1;
042        private int lockTimeout=20000;
043        private int cache=20000;
044        private ResourceLock lock;
045        private String scheme="s3";
046        private Map arguments;
047
048        
049
050        
051        /**
052         * initalize ram resource
053         * @param scheme
054         * @param arguments
055         * @return RamResource
056         */
057        public ResourceProvider init(String scheme,Map arguments) {
058                if(!StringUtil.isEmpty(scheme))this.scheme=scheme;
059                
060                if(arguments!=null) {
061                        this.arguments=arguments;
062                        // socket-timeout
063                        String strTimeout = (String) arguments.get("socket-timeout");
064                        if(strTimeout!=null) {
065                                socketTimeout=toIntValue(strTimeout,socketTimeout);
066                        }
067                        // lock-timeout
068                        strTimeout=(String) arguments.get("lock-timeout");
069                        if(strTimeout!=null) {
070                                lockTimeout=toIntValue(strTimeout,lockTimeout);
071                        }
072                        // cache
073                        String strCache=(String) arguments.get("cache");
074                        if(strCache!=null) {
075                                cache=toIntValue(strCache,cache);
076                        }
077                }
078                
079                return this;
080        }
081
082        private int toIntValue(String str, int defaultValue) {
083                try{
084                        return Integer.parseInt(str);
085                }
086                catch(Throwable t){
087                ExceptionUtil.rethrowIfNecessary(t);
088                        return defaultValue;
089                }
090        }
091
092
093        @Override
094        public String getScheme() {
095                return scheme;
096        }
097        
098        public Resource getResource(String path) {
099                path=lucee.commons.io.res.util.ResourceUtil.removeScheme(scheme, path);
100                S3 s3 = new S3();
101                RefInteger storage=new RefIntegerImpl(S3.STORAGE_UNKNOW);
102                
103                
104                //path=loadWithOldPattern(s3,storage,path);
105                path=loadWithNewPattern(s3,storage,path);
106                
107                return new S3Resource(s3,storage.toInt(),this,path,true);
108        }
109
110        
111        public static String loadWithNewPattern(S3 s3,RefInteger storage, String path) {
112                PageContext pc = ThreadLocalPageContext.get();
113                Properties prop=null; 
114                if(pc!=null){
115                        prop=pc.getApplicationContext().getS3();
116                }
117                if(prop==null) prop=new PropertiesImpl();
118                
119                int defaultLocation = prop.getDefaultLocation();
120                storage.setValue(defaultLocation);
121                String accessKeyId = prop.getAccessKeyId();
122                String secretAccessKey = prop.getSecretAccessKey();
123                
124                int atIndex=path.indexOf('@');
125                int slashIndex=path.indexOf('/');
126                if(slashIndex==-1){
127                        slashIndex=path.length();
128                        path+="/";
129                }
130                int index;
131                
132                // key/id
133                if(atIndex!=-1) {
134                        index=path.indexOf(':');
135                        if(index!=-1 && index<atIndex) {
136                                accessKeyId=path.substring(0,index);
137                                secretAccessKey=path.substring(index+1,atIndex);
138                                index=secretAccessKey.indexOf(':');
139                                if(index!=-1) {
140                                        String strStorage=secretAccessKey.substring(index+1).trim().toLowerCase();
141                                        secretAccessKey=secretAccessKey.substring(0,index);
142                                        //print.out("storage:"+strStorage);
143                                        storage.setValue(S3.toIntStorage(strStorage, defaultLocation));
144                                }
145                        }
146                        else accessKeyId=path.substring(0,atIndex);
147                }
148                path=prettifyPath(path.substring(atIndex+1));
149                index=path.indexOf('/');
150                s3.setHost(prop.getHost());
151                if(index==-1){
152                        if(path.equalsIgnoreCase(S3Constants.HOST) || path.equalsIgnoreCase(prop.getHost())){
153                                s3.setHost(path);
154                                path="/";
155                        }
156                }
157                else {
158                        String host=path.substring(0,index);
159                        if(host.equalsIgnoreCase(S3Constants.HOST) || host.equalsIgnoreCase(prop.getHost())){
160                                s3.setHost(host);
161                                path=path.substring(index);
162                        }
163                }
164                
165                
166                s3.setSecretAccessKey(secretAccessKey);
167                s3.setAccessKeyId(accessKeyId);
168                
169                return path;
170        }
171
172        /*public static void main(String[] args) {
173                // s3://bucket/x/y/sample.txt
174                // s3://accessKeyId:awsSecretKey@bucket/x/y/sample.txt
175                String secretAccessKey="R/sOy3hgimrI8D9c0lFHchoivecnOZ8LyVmJpRFQ";
176                String accessKeyId="1DHC5C5FVD7YEPR4DBG2";
177                
178                Properties prop=new Properties();
179                prop.setAccessKeyId(accessKeyId);
180                prop.setSecretAccessKey(secretAccessKey);
181                
182                
183                test("s3://"+accessKeyId+":"+secretAccessKey+"@s3.amazonaws.com/dudi/peter.txt");
184                test("s3://"+accessKeyId+":"+secretAccessKey+"@dudi/peter.txt");
185                test("s3:///dudi/peter.txt");
186                test("s3://dudi/peter.txt");
187                
188                
189        }
190        
191        
192        
193        private static void test(String path) {
194
195                Properties prop=new Properties();
196                prop.setAccessKeyId("123456");
197                prop.setSecretAccessKey("abcdefghji");
198                
199                
200                
201                String scheme="s3";
202                path=lucee.commons.io.res.util.ResourceUtil.removeScheme(scheme, path);
203                S3 s3 = new S3();
204                RefInteger storage=new RefIntegerImpl(S3.STORAGE_UNKNOW);
205                path=loadWithNewPattern(s3,prop,storage,path);
206                
207
208                print.o(s3);
209                print.o(path);
210        }*/
211
212        private static String prettifyPath(String path) {
213                path=path.replace('\\','/');
214                return StringUtil.replace(path, "//", "/", false);
215                // TODO /aaa/../bbb/
216        }
217        
218        
219        
220
221        public static String loadWithOldPattern(S3 s3,RefInteger storage, String path) {
222                
223                
224                String accessKeyId = null;
225                String secretAccessKey = null;
226                String host = null;
227                //int port = 21;
228                
229                //print.out("raw:"+path);
230                
231                int atIndex=path.indexOf('@');
232                int slashIndex=path.indexOf('/');
233                if(slashIndex==-1){
234                        slashIndex=path.length();
235                        path+="/";
236                }
237                int index;
238                
239                // key/id
240                if(atIndex!=-1) {
241                        index=path.indexOf(':');
242                        if(index!=-1 && index<atIndex) {
243                                accessKeyId=path.substring(0,index);
244                                secretAccessKey=path.substring(index+1,atIndex);
245                                index=secretAccessKey.indexOf(':');
246                                if(index!=-1) {
247                                        String strStorage=secretAccessKey.substring(index+1).trim().toLowerCase();
248                                        secretAccessKey=secretAccessKey.substring(0,index);
249                                        //print.out("storage:"+strStorage);
250                                        storage.setValue(S3.toIntStorage(strStorage, S3.STORAGE_UNKNOW));
251                                }
252                        }
253                        else accessKeyId=path.substring(0,atIndex);
254                }
255                path=prettifyPath(path.substring(atIndex+1));
256                index=path.indexOf('/');
257                if(index==-1){
258                        host=path;
259                        path="/";
260                }
261                else {
262                        host=path.substring(0,index);
263                        path=path.substring(index);
264                }
265                
266                s3.setHost(host);
267                s3.setSecretAccessKey(secretAccessKey);
268                s3.setAccessKeyId(accessKeyId);
269                
270                return path;
271        }
272        @Override
273        public boolean isAttributesSupported() {
274                return false;
275        }
276
277        @Override
278        public boolean isCaseSensitive() {
279                return true;
280        }
281
282        @Override
283        public boolean isModeSupported() {
284                return false;
285        }
286
287        @Override
288        public void lock(Resource res) throws IOException {
289                lock.lock(res);
290        }
291
292        @Override
293        public void read(Resource res) throws IOException {
294                lock.read(res);
295        }
296
297        public void setResources(Resources res) {
298                lock=res.createResourceLock(lockTimeout,true);
299        }
300
301        @Override
302        public void unlock(Resource res) {
303                lock.unlock(res);
304        }
305
306        /**
307         * @return the socketTimeout
308         */
309        public int getSocketTimeout() {
310                return socketTimeout;
311        }
312
313        /**
314         * @return the lockTimeout
315         */
316        public int getLockTimeout() {
317                return lockTimeout;
318        }
319
320        /**
321         * @return the cache
322         */
323        public int getCache() {
324                return cache;
325        }
326
327        @Override
328        public Map getArguments() {
329                return arguments;
330        }
331
332        @Override
333        public char getSeparator() {
334                return '/';
335        }
336        
337
338}