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}