001    package railo.commons.io.res.type.s3;
002    
003    import java.io.IOException;
004    import java.io.InputStream;
005    import java.io.UnsupportedEncodingException;
006    import java.net.HttpURLConnection;
007    import java.net.MalformedURLException;
008    import java.net.URL;
009    import java.security.InvalidKeyException;
010    import java.security.NoSuchAlgorithmException;
011    import java.util.ArrayList;
012    import java.util.HashMap;
013    import java.util.Iterator;
014    import java.util.List;
015    import java.util.Map;
016    import java.util.TimeZone;
017    
018    import javax.crypto.Mac;
019    import javax.crypto.spec.SecretKeySpec;
020    
021    import org.apache.commons.collections.map.ReferenceMap;
022    import org.xml.sax.SAXException;
023    
024    import railo.commons.lang.Md5;
025    import railo.commons.lang.StringUtil;
026    import railo.commons.net.URLEncoder;
027    import railo.commons.net.http.Entity;
028    import railo.commons.net.http.HTTPResponse;
029    import railo.commons.net.http.Header;
030    import railo.commons.net.http.httpclient3.HTTPEngine3Impl;
031    import railo.loader.util.Util;
032    import railo.runtime.config.Constants;
033    import railo.runtime.engine.ThreadLocalPageContext;
034    import railo.runtime.exp.PageException;
035    import railo.runtime.op.Caster;
036    import railo.runtime.type.dt.DateTime;
037    
038    public final class S3 implements S3Constants {
039    
040            private static final String DEFAULT_URL="s3.amazonaws.com";
041            
042            private String secretAccessKey;
043            private String accessKeyId;
044            private TimeZone timezone;
045            private String host;
046    
047    
048            private static final Map<String,S3Info> infos=new ReferenceMap();
049            private static final Map<String,AccessControlPolicy> acps=new ReferenceMap();
050    
051            public static final int MAX_REDIRECT = 15;
052    
053            public String toString(){
054                    return "secretAccessKey:"+secretAccessKey+";accessKeyId:"+accessKeyId+";host:"+host+";timezone:"+
055                    (timezone==null?"":timezone.getID());
056            }
057            
058            public String hash() {
059                    try {
060                            return Md5.getDigestAsString(toString());
061                    } catch (IOException e) {
062                            return null;
063                    }
064            }
065    
066            public S3(String secretAccessKey, String accessKeyId,TimeZone tz) {
067                    host=DEFAULT_URL;
068                    this.secretAccessKey = secretAccessKey;
069                    this.accessKeyId = accessKeyId;
070                    this.timezone = tz;
071                    //testFinal();
072            }
073            
074            
075    
076            public S3() {
077                    
078                    //testFinal();
079            }
080            
081            /**
082             * @return the secretAccessKey
083             * @throws S3Exception 
084             */
085            String getSecretAccessKeyValidate() throws S3Exception {
086                    if(StringUtil.isEmpty(secretAccessKey))
087                            throw new S3Exception("secretAccessKey is not defined, define in "+Constants.APP_CFC+" (s3.awsSecretKey) or as part of the path.");
088                    return secretAccessKey;
089            }
090            
091            /**
092             * @return the accessKeyId
093             * @throws S3Exception 
094             */
095            String getAccessKeyIdValidate() throws S3Exception {
096                    if(StringUtil.isEmpty(accessKeyId))
097                            throw new S3Exception("accessKeyId is not defined, define in "+Constants.APP_CFC+" (this.s3.accessKeyId) or as part of the path.");
098                    return accessKeyId;
099            }
100            
101            String getSecretAccessKey() {
102                    return secretAccessKey;
103            }
104            
105            /**
106             * @return the accessKeyId
107             * @throws S3Exception 
108             */
109            String getAccessKeyId() {
110                    return accessKeyId;
111            }
112    
113            /**
114             * @return the tz
115             */
116            TimeZone getTimeZone() {
117                    if(timezone==null)timezone=ThreadLocalPageContext.getTimeZone();
118                    return timezone;
119            }
120            
121            private static byte[] HMAC_SHA1(String key, String message,String charset) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
122                    
123                            SecretKeySpec sks = new SecretKeySpec(key.getBytes(charset),"HmacSHA1");
124                            Mac mac = Mac.getInstance(sks.getAlgorithm());
125                            mac.init(sks);
126                            mac.update(message.getBytes(charset));
127                            return mac.doFinal();
128                    
129            }
130    
131            private static String createSignature(String str, String secretAccessKey,String charset) throws InvalidKeyException, NoSuchAlgorithmException, IOException {
132                    //str=StringUtil.replace(str, "\\n", String.valueOf((char)10), false);
133                    byte[] digest = HMAC_SHA1(secretAccessKey,str,charset);
134                    try {
135                            return Caster.toB64(digest);
136                    } catch (Throwable t) {
137                            throw new IOException(t.getMessage());
138                    }
139            }
140            
141            public InputStream listBucketsRaw() throws MalformedURLException, IOException, InvalidKeyException, NoSuchAlgorithmException {
142                    String dateTimeString = Util.toHTTPTimeString();
143                    String signature = createSignature("GET\n\n\n"+dateTimeString+"\n/", getSecretAccessKeyValidate(), "iso-8859-1");
144                    
145                    HTTPResponse rsp = HTTPEngine3Impl.get(new URL("http://"+host), null, null, -1,MAX_REDIRECT, null, "Railo", null,
146                                    new Header[]{
147                                            header("Date",dateTimeString),
148                                            header("Authorization","AWS "+getAccessKeyIdValidate()+":"+signature)
149                                    }
150                    );
151                    return rsp.getContentAsStream();
152                    
153            }
154            
155    
156            public HTTPResponse head(String bucketName, String objectName) throws MalformedURLException, IOException, InvalidKeyException, NoSuchAlgorithmException {
157                    bucketName=checkBucket(bucketName);
158                    boolean hasObj=!StringUtil.isEmpty(objectName);
159                    if(hasObj)objectName=checkObjectName(objectName);
160                    
161                    String dateTimeString = Util.toHTTPTimeString();
162                    String signature = createSignature("HEAD\n\n\n"+dateTimeString+"\n/"+bucketName+"/"+(hasObj?objectName:""), getSecretAccessKeyValidate(), "iso-8859-1");
163                    
164                    
165                    List<Header> headers=new ArrayList<Header>();
166                    headers.add(header("Date",dateTimeString));
167                    headers.add(header("Authorization","AWS "+getAccessKeyIdValidate()+":"+signature));
168                    headers.add(header("Host",bucketName+"."+host));
169                    
170                    String strUrl="http://"+bucketName+"."+host+"/";
171                    //if(Util.hasUpperCase(bucketName))strUrl="http://"+host+"/"+bucketName+"/";
172                    if(hasObj) {
173                            strUrl+=objectName;
174                    }
175                    HTTPResponse method = HTTPEngine3Impl.head(new URL(strUrl), null, null, -1,MAX_REDIRECT, null, "Railo", null,headers.toArray(new Header[headers.size()]));
176                    return method;
177                    
178            }
179            
180            
181            
182            
183            public InputStream aclRaw(String bucketName, String objectName) throws MalformedURLException, IOException, InvalidKeyException, NoSuchAlgorithmException {
184                    bucketName=checkBucket(bucketName);
185                    boolean hasObj=!StringUtil.isEmpty(objectName);
186                    if(hasObj)objectName=checkObjectName(objectName);
187                    
188                    String dateTimeString = Util.toHTTPTimeString();
189                    String signature = createSignature("GET\n\n\n"+dateTimeString+"\n/"+bucketName+"/"+(hasObj?objectName:"")+"?acl", getSecretAccessKeyValidate(), "iso-8859-1");
190                    
191                    
192                    List<Header> headers=new ArrayList<Header>();
193                    headers.add(header("Date",dateTimeString));
194                    headers.add(header("Authorization","AWS "+getAccessKeyIdValidate()+":"+signature));
195                    headers.add(header("Host",bucketName+"."+host));
196                    
197                    String strUrl="http://"+bucketName+"."+host+"/";
198                    //if(Util.hasUpperCase(bucketName))strUrl="http://"+host+"/"+bucketName+"/";
199                    if(hasObj) {
200                            strUrl+=objectName;
201                    }
202                    strUrl+="?acl";
203                    
204                    HTTPResponse method = HTTPEngine3Impl.get(new URL(strUrl), null, null, -1,MAX_REDIRECT, null, "Railo", null,headers.toArray(new Header[headers.size()]));
205                    return method.getContentAsStream();
206                    
207            }
208            
209            public AccessControlPolicy getAccessControlPolicy(String bucketName, String objectName) throws InvalidKeyException, MalformedURLException, NoSuchAlgorithmException, IOException, SAXException {
210                    InputStream raw = aclRaw(bucketName,objectName);
211                    //print.o(IOUtil.toString(raw, null));
212                    ACLFactory factory=new ACLFactory(raw, this);
213                    return factory.getAccessControlPolicy();
214            }
215            
216            
217    
218    
219            public void setAccessControlPolicy(String bucketName, String objectName,AccessControlPolicy acp) throws IOException, InvalidKeyException, NoSuchAlgorithmException, SAXException {
220                    bucketName=checkBucket(bucketName);
221                    boolean hasObj=!StringUtil.isEmpty(objectName);
222                    if(hasObj)objectName=checkObjectName(objectName);
223                    
224    
225                    Entity re = HTTPEngine3Impl.getByteArrayEntity(acp.toXMLString().getBytes("iso-8859-1"),"text/html");
226                    
227                    
228                    String dateTimeString = Util.toHTTPTimeString();
229                    
230                    
231                    String cs = "PUT\n\n"+re.contentType()+"\n"+dateTimeString+"\n/"+bucketName+"/"+(hasObj?objectName:"")+"?acl";
232                    String signature = createSignature(cs, getSecretAccessKeyValidate(), "iso-8859-1");
233                    Header[] headers = new Header[]{
234                                    header("Content-Type",re.contentType()),
235                                    header("Content-Length",Long.toString(re.contentLength())),
236                                    header("Date",dateTimeString),
237                                    header("Authorization","AWS "+getAccessKeyIdValidate()+":"+signature),
238                    };
239                    
240                    String strUrl="http://"+bucketName+"."+host+"/";
241                    if(hasObj) {
242                            strUrl+=objectName;
243                    }
244                    strUrl+="?acl";
245                    
246                    
247                    
248                    HTTPResponse method = HTTPEngine3Impl.put(new URL(strUrl), null, null, -1,MAX_REDIRECT, null, 
249                                    "Railo", null,headers,re);
250                    if(method.getStatusCode()!=200){
251                            new ErrorFactory(method.getContentAsStream());
252                    }
253                    
254                    
255            }
256            
257            public InputStream listContentsRaw(String bucketName,String prefix,String marker,int maxKeys) throws MalformedURLException, IOException, InvalidKeyException, NoSuchAlgorithmException {
258                    bucketName=checkBucket(bucketName);
259                    String dateTimeString = Util.toHTTPTimeString();
260                    String signature = createSignature("GET\n\n\n"+dateTimeString+"\n/"+bucketName+"/", getSecretAccessKeyValidate(), "iso-8859-1");
261                    
262                    
263                    List<Header> headers=new ArrayList<Header>();
264                    headers.add(header("Date",dateTimeString));
265                    headers.add(header("Authorization","AWS "+getAccessKeyIdValidate()+":"+signature));
266                    headers.add(header("Host",bucketName+"."+host));
267                    
268                    String strUrl="http://"+bucketName+"."+host+"/";
269                    if(Util.hasUpperCase(bucketName))strUrl="http://"+host+"/"+bucketName+"/";
270                    
271                    
272                    char amp='?';
273                    if(!Util.isEmpty(prefix)){
274                            strUrl+=amp+"prefix="+encodeEL(prefix);
275                            amp='&';
276                    }
277                    if(!Util.isEmpty(marker)) {
278                            strUrl+=amp+"marker="+encodeEL(marker);
279                            amp='&';
280                    }
281                    if(maxKeys!=-1) {
282                            strUrl+=amp+"max-keys="+maxKeys;
283                            amp='&';
284                    }
285                    
286                    HTTPResponse method = HTTPEngine3Impl.get(new URL(strUrl), null, null, -1,MAX_REDIRECT, null, "Railo", null,headers.toArray(new Header[headers.size()]));
287                    return method.getContentAsStream();
288            }
289            
290    
291            public Content[] listContents(String bucketName,String prefix) throws InvalidKeyException, MalformedURLException, NoSuchAlgorithmException, IOException, SAXException {
292                    String marker=null,last=null;
293                    ContentFactory factory;
294                    Content[] contents;
295                    List<Content[]> list = new ArrayList<Content[]>();
296                    int size=0;
297                    while(true) {
298                            factory = new ContentFactory(listContentsRaw(bucketName, prefix, marker, -1),this);
299                            contents = factory.getContents();
300                            list.add(contents);
301                            size+=contents.length;
302                            if(factory.isTruncated() && contents.length>0) {
303                                    last=marker;
304                                    marker=contents[contents.length-1].getKey();
305                                    if(marker.equals(last))break;
306                            }
307                            else break;
308                    }
309                    
310                    if(list.size()==1) return list.get(0);
311                    if(list.size()==0) return new Content[0];
312                    
313                    Content[] rtn=new Content[size];
314                    Iterator<Content[]> it = list.iterator();
315                    int index=0;
316                    while(it.hasNext()) {
317                            contents=it.next();
318                            for(int i=0;i<contents.length;i++) {
319                                    rtn[index++]=contents[i];
320                            }
321                    }
322                    
323                    return rtn;
324            }
325    
326            public Content[] listContents(String bucketName,String prefix,String marker,int maxKeys) throws InvalidKeyException, MalformedURLException, NoSuchAlgorithmException, IOException, SAXException {
327                    InputStream raw = listContentsRaw(bucketName, prefix, marker, maxKeys);
328                    //print.o(IOUtil.toString(raw, null));
329                    ContentFactory factory = new ContentFactory(raw,this);
330                    return factory.getContents();
331            }
332            
333            public Bucket[] listBuckets() throws InvalidKeyException, MalformedURLException, NoSuchAlgorithmException, IOException, SAXException {
334                    InputStream raw = listBucketsRaw();
335                    //print.o(IOUtil.toString(raw, null));
336                    BucketFactory factory = new BucketFactory(raw,this);
337                    return factory.getBuckets();
338            }
339            
340            public void putBuckets(String bucketName,int acl, int storage) throws IOException, InvalidKeyException, NoSuchAlgorithmException, SAXException {
341                    String strXML = "";
342                    if(storage==STORAGE_EU) {
343                            strXML="<CreateBucketConfiguration><LocationConstraint>EU</LocationConstraint></CreateBucketConfiguration>";
344                    }
345                    
346                    byte[] barr = strXML.getBytes("iso-8859-1");
347                    put(bucketName, null, acl,HTTPEngine3Impl.getByteArrayEntity(barr,"text/html"));        
348            }
349            
350            /*public void putObject(String bucketName,String objectName,int acl,Resource res) throws IOException, InvalidKeyException, NoSuchAlgorithmException, PageException, SAXException, EncoderException {
351                    String contentType = IOUtil.getMimeType(res, "application");
352                    InputStream is = null;
353                    try {
354                            is = res.getInputStream();
355                            put(bucketName, objectName, acl, is, contentType);
356                    }
357                    finally {
358                            IOUtil.closeEL(is);
359                    }
360            }*/
361            /*
362            public void put(String bucketName,String objectName,int acl, InputStream is,long length, String contentType) throws IOException, InvalidKeyException, NoSuchAlgorithmException, PageException, SAXException, EncoderException {
363                    put(bucketName, objectName, acl, HTTPUtil.toRequestEntity(is),length, contentType);
364            }*/
365                    
366            public void put(String bucketName,String objectName,int acl, Entity re) throws IOException, InvalidKeyException, NoSuchAlgorithmException, SAXException {
367                    bucketName=checkBucket(bucketName);
368                    objectName=checkObjectName(objectName);
369                    
370                    String dateTimeString = Util.toHTTPTimeString();
371                    // Create a canonical string to send based on operation requested 
372                    String cs = "PUT\n\n"+re.contentType()+"\n"+dateTimeString+"\nx-amz-acl:"+toStringACL(acl)+"\n/"+bucketName+"/"+objectName;
373                    String signature = createSignature(cs, getSecretAccessKeyValidate(), "iso-8859-1");
374                    Header[] headers = new Header[]{
375                                    header("Content-Type",re.contentType()),
376                                    header("Content-Length",Long.toString(re.contentLength())),
377                                    header("Date",dateTimeString),
378                                    header("x-amz-acl",toStringACL(acl)),
379                                    header("Authorization","AWS "+getAccessKeyIdValidate()+":"+signature),
380                    };
381                    
382                    String strUrl="http://"+bucketName+"."+host+"/"+objectName;
383                    if(Util.hasUpperCase(bucketName))strUrl="http://"+host+"/"+bucketName+"/"+objectName;
384                    
385                    
386                    
387                    HTTPResponse method = HTTPEngine3Impl.put(new URL(strUrl), null, null, -1,MAX_REDIRECT, null, 
388                                    "Railo", null,headers,re);
389                    if(method.getStatusCode()!=200){
390                            new ErrorFactory(method.getContentAsStream());
391                    }
392                    
393                    
394            }
395                    
396            public HttpURLConnection preput(String bucketName,String objectName,int acl, String contentType) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
397                    bucketName=checkBucket(bucketName);
398                    objectName=checkObjectName(objectName);
399                    
400                    String dateTimeString = Util.toHTTPTimeString();
401                    // Create a canonical string to send based on operation requested 
402                    String cs = "PUT\n\n"+contentType+"\n"+dateTimeString+"\nx-amz-acl:"+toStringACL(acl)+"\n/"+bucketName+"/"+objectName;
403                    String signature = createSignature(cs, getSecretAccessKeyValidate(), "iso-8859-1");
404                    
405                    String strUrl="http://"+bucketName+"."+host+"/"+objectName;
406                    if(Util.hasUpperCase(bucketName))strUrl="http://"+host+"/"+bucketName+"/"+objectName;
407                    
408                    URL url = new URL(strUrl);
409                    
410                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
411                    conn.setRequestMethod("PUT");
412                    
413                    conn.setFixedLengthStreamingMode(227422142);
414                    conn.setDoOutput(true);
415                    conn.setUseCaches(false);
416                    conn.setRequestProperty("CONTENT-TYPE", contentType);
417                    conn.setRequestProperty("USER-AGENT", "S3 Resource");        
418                    //conn.setRequestProperty("Transfer-Encoding", "chunked" );
419                    conn.setRequestProperty("Date", dateTimeString);
420                    conn.setRequestProperty("x-amz-acl", toStringACL(acl));
421                    conn.setRequestProperty("Authorization", "AWS "+getAccessKeyIdValidate()+":"+signature);
422                    return conn;
423            }
424    
425            public String getObjectLink(String bucketName,String objectName,int secondsValid) throws InvalidKeyException, NoSuchAlgorithmException, IOException {
426                    bucketName=checkBucket(bucketName);
427                    objectName=checkObjectName(objectName);
428                    
429                    //String dateTimeString = GetHttpTimeString.invoke();
430                    long epoch = (System.currentTimeMillis()/1000)+(secondsValid);
431                    String cs = "GET\n\n\n"+epoch+"\n/"+bucketName+"/"+objectName;
432                    String signature = createSignature(cs, getSecretAccessKeyValidate(), "iso-8859-1");
433                    
434                    String strUrl="http://"+bucketName+"."+host+"/"+objectName;
435                    if(Util.hasUpperCase(bucketName))strUrl="http://"+host+"/"+bucketName+"/"+objectName;
436                    
437                    
438                    return strUrl+"?AWSAccessKeyId="+getAccessKeyIdValidate()+"&Expires="+epoch+"&Signature="+signature;
439            }
440    
441            public InputStream getInputStream(String bucketName,String objectName) throws InvalidKeyException, NoSuchAlgorithmException, IOException, SAXException  {
442                    return getData(bucketName, objectName).getContentAsStream();
443            }
444            
445            public Map<String, String> getMetadata(String bucketName,String objectName) throws InvalidKeyException, NoSuchAlgorithmException, IOException, SAXException  {
446                    HTTPResponse method = getData(bucketName, objectName);
447                    Header[] headers = method.getAllHeaders();
448                    Map<String,String> rtn=new HashMap<String, String>();
449                    String name;
450                    if(headers!=null)for(int i=0;i<headers.length;i++){
451                            name=headers[i].getName();
452                            if(name.startsWith("x-amz-meta-"))
453                                    rtn.put(name.substring(11), headers[i].getValue());
454                    }
455                    return rtn;
456            }
457            
458            private HTTPResponse getData(String bucketName,String objectName) throws InvalidKeyException, NoSuchAlgorithmException, IOException, SAXException  {
459                    bucketName=checkBucket(bucketName);
460                    objectName=checkObjectName(objectName);
461                    
462                    String dateTimeString = Util.toHTTPTimeString();
463                    //long epoch = (System.currentTimeMillis()/1000)+6000;
464                    String cs = "GET\n\n\n"+dateTimeString+"\n/"+bucketName+"/"+objectName;
465                        
466                    
467                    String signature = createSignature(cs, getSecretAccessKeyValidate(), "iso-8859-1");
468                    
469                    String strUrl="http://"+bucketName+"."+host+"/"+objectName;
470                    if(Util.hasUpperCase(bucketName))strUrl="http://"+host+"/"+bucketName+"/"+objectName;
471                    URL url = new URL(strUrl);
472                    
473                    
474                    HTTPResponse method = HTTPEngine3Impl.get(url, null, null, -1,MAX_REDIRECT, null, "Railo", null,
475                                    new Header[]{
476                                    header("Date",dateTimeString),
477                                    header("Host",bucketName+"."+host),
478                                    header("Authorization","AWS "+getAccessKeyIdValidate()+":"+signature)
479                                    }
480                    );
481                    if(method.getStatusCode()!=200)
482                            new ErrorFactory(method.getContentAsStream());
483                    return method;
484            }
485    
486            public void delete(String bucketName, String objectName) throws IOException, InvalidKeyException, NoSuchAlgorithmException, SAXException {
487                    bucketName=checkBucket(bucketName);
488                    objectName = checkObjectName(objectName);
489    
490                    String dateTimeString = Util.toHTTPTimeString();
491                    // Create a canonical string to send based on operation requested 
492                    String cs ="DELETE\n\n\n"+dateTimeString+"\n/"+bucketName+"/"+objectName;
493                    //print.out(cs);
494                    String signature = createSignature(cs, getSecretAccessKeyValidate(), "iso-8859-1");
495                    
496                    Header[] headers =new Header[]{
497                                    header("Date",dateTimeString),
498                                    header("Authorization","AWS "+getAccessKeyIdValidate()+":"+signature),
499                    };
500                    
501                    String strUrl="http://"+bucketName+"."+host+"/"+objectName;
502                    if(Util.hasUpperCase(bucketName))strUrl="http://"+host+"/"+bucketName+"/"+objectName;
503                    
504                    
505                    
506                    HTTPResponse rsp = HTTPEngine3Impl.delete(new URL(strUrl), null, null, -1,MAX_REDIRECT, null, "Railo",  null,headers);
507                    
508                    if(rsp.getStatusCode()!=200)
509                            new ErrorFactory(rsp.getContentAsStream());
510            }
511    
512            
513            
514            
515            
516            
517            // --------------------------------
518            public static String toStringACL(int acl) throws S3Exception {
519                    switch(acl) {
520                            case ACL_AUTH_READ:return "authenticated-read";
521                            case ACL_PUBLIC_READ:return "public-read";
522                            case ACL_PRIVATE:return "private";
523                            case ACL_PUBLIC_READ_WRITE:return "public-read-write";
524                    }
525                    throw new S3Exception("invalid acl definition");
526            }
527    
528            public static String toStringStorage(int storage) throws S3Exception {
529                    String s = toStringStorage(storage, null);
530                    if(s==null)
531                            throw new S3Exception("invalid storage definition");
532                    return s;
533            }
534            public static String toStringStorage(int storage, String defaultValue) {
535                    switch(storage) {
536                            case STORAGE_EU:return "eu";
537                            case STORAGE_US:return "us";
538                            case STORAGE_US_WEST:return "us-west";
539                    }
540                    return defaultValue;
541            }
542            
543            public static int toIntACL(String acl) throws S3Exception {
544                    acl=acl.toLowerCase().trim();
545                    if("public-read".equals(acl)) return ACL_PUBLIC_READ;
546                    if("private".equals(acl)) return ACL_PRIVATE;
547                    if("public-read-write".equals(acl)) return ACL_PUBLIC_READ_WRITE;
548                    if("authenticated-read".equals(acl)) return ACL_AUTH_READ;
549                    
550                    if("public_read".equals(acl)) return ACL_PUBLIC_READ;
551                    if("public_read_write".equals(acl)) return ACL_PUBLIC_READ_WRITE;
552                    if("authenticated_read".equals(acl)) return ACL_AUTH_READ;
553                    
554                    if("publicread".equals(acl)) return ACL_PUBLIC_READ;
555                    if("publicreadwrite".equals(acl)) return ACL_PUBLIC_READ_WRITE;
556                    if("authenticatedread".equals(acl)) return ACL_AUTH_READ;
557                    
558                    throw new S3Exception("invalid acl value, valid values are [public-read, private, public-read-write, authenticated-read]");
559            }
560    
561            public static int toIntStorage(String storage) throws S3Exception {
562                    int s=toIntStorage(storage,-1);
563                    if(s==-1)
564                            throw new S3Exception("invalid storage value, valid values are [eu,us,us-west]");
565                    return s;
566            }
567            public static int toIntStorage(String storage, int defaultValue) {
568                    storage=storage.toLowerCase().trim();
569                    if("us".equals(storage)) return STORAGE_US;
570                    if("usa".equals(storage)) return STORAGE_US;
571                    if("eu".equals(storage)) return STORAGE_EU;
572                    
573                    if("u.s.".equals(storage)) return STORAGE_US;
574                    if("u.s.a.".equals(storage)) return STORAGE_US;
575                    if("europe.".equals(storage)) return STORAGE_EU;
576                    if("euro.".equals(storage)) return STORAGE_EU;
577                    if("e.u.".equals(storage)) return STORAGE_EU;
578                    if("united states of america".equals(storage)) return STORAGE_US;
579                    
580                    if("us-west".equals(storage)) return STORAGE_US_WEST;
581                    if("usa-west".equals(storage)) return STORAGE_US_WEST;
582                    
583                    
584                    return defaultValue;
585            }
586            
587    
588            private String checkObjectName(String objectName) throws UnsupportedEncodingException {
589                    if(Util.isEmpty(objectName)) return "";
590                    if(objectName.startsWith("/"))objectName=objectName.substring(1);
591                    return encode(objectName);
592            }
593    
594            private String checkBucket(String name) {
595                    /*if(!Decision.isVariableName(name)) 
596                            throw new S3Exception("invalid bucket name definition ["+name+"], name should only contain letters, digits, dashes and underscores");
597                    
598                    if(name.length()<3 || name.length()>255) 
599                            throw new S3Exception("invalid bucket name definition ["+name+"], the length of a bucket name must be between 3 and 255");
600                    */
601                    
602                    return encodeEL(name);
603            }
604    
605            private String encodeEL(String name) {
606                    try {
607                            return encode(name);
608                    
609                    } catch (UnsupportedEncodingException e) {
610                            return name;
611                    }
612            }
613            private String encode(String name) throws UnsupportedEncodingException {
614                    return URLEncoder.encode(name,"UTF-8");
615            }
616    
617            /**
618             * @param secretAccessKey the secretAccessKey to set
619             */
620            public void setSecretAccessKey(String secretAccessKey) {
621                    this.secretAccessKey = secretAccessKey;
622            }
623    
624            /**
625             * @param accessKeyId the accessKeyId to set
626             */
627            public void setAccessKeyId(String accessKeyId) {
628                    this.accessKeyId = accessKeyId;
629            }
630    
631            /**
632             * @param url the url to set
633             */
634            public void setHost(String host) {
635                    this.host=host;
636            }
637    
638            public String getHost() {
639                    return host;
640            }
641    
642            public S3Info getInfo(String path) {
643                    return infos.get(toKey(path));
644            }
645    
646            public void setInfo(String path,S3Info info) {
647                    infos.put(toKey(path),info);
648            }
649    
650            public AccessControlPolicy getACP(String path) {
651                    return acps.get(toKey(path));
652            }
653    
654            public void setACP(String path,AccessControlPolicy acp) {
655                    acps.put(toKey(path),acp);
656            }
657    
658            public void releaseCache(String path) {
659                    Object k = toKey(path);
660                    infos.remove(k);
661                    acps.remove(k);
662            }
663    
664            private String toKey(String path) {
665                    return toString()+":"+path.toLowerCase();
666            }
667            
668            private Header header(String name, String value) {
669                    return HTTPEngine3Impl.header(name,value);
670            }
671    
672            public static DateTime toDate(String strDate, TimeZone tz) throws PageException {
673                    if(strDate.endsWith("Z"))
674                            strDate=strDate.substring(0,strDate.length()-1);
675                    return Caster.toDate(strDate, tz);
676            }
677    }
678    
679    
680    
681    
682