Package com.amazon.s3

Source Code of com.amazon.s3.Utils

//  This software code is made available "AS IS" without warranties of any
//  kind.  You may copy, display, modify and redistribute the software
//  code either by itself or as incorporated into your code; provided that
//  you do not remove any proprietary notices.  Your use of this software
//  code is at your own risk and you waive any claim against Amazon
//  Digital Services, Inc. or its affiliates with respect to your use of
//  this software code. (c) 2006 Amazon Digital Services, Inc. or its
//  affiliates.

package com.amazon.s3;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.CharEncoding;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

public class Utils {
    static final String METADATA_PREFIX = "x-amz-meta-";
    static final String AMAZON_HEADER_PREFIX = "x-amz-";
    static final String ALTERNATIVE_DATE_HEADER = "x-amz-date";
    static final String DEFAULT_HOST = "s3.amazonaws.com";
    static final int SECURE_PORT = 443;
    static final int INSECURE_PORT = 80;


    /**
     * HMAC/SHA1 Algorithm per RFC 2104.
     */
    private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";

    static String makeCanonicalString(String method, String resource, Map headers) {
        return makeCanonicalString(method, resource, headers, null);
    }

    /**
     * Calculate the canonical string.  When expires is non-null, it will be
     * used instead of the Date header.
     * @param method
     * @param resource
     * @param headers
     * @param expires
     * @return canoncical string
     */
    static String makeCanonicalString(String method, String resource,
                                             Map headers, String expires)
    {
      StringBuilder buf = new StringBuilder();
        buf.append(method + "\n");

        // Add all interesting headers to a list, then sort them.  "Interesting"
        // is defined as Content-MD5, Content-Type, Date, and x-amz-
        SortedMap interestingHeaders = new TreeMap();
        if (headers != null) {
            for (Iterator i = headers.keySet().iterator(); i.hasNext(); ) {
                String key = (String)i.next();
                if (key == null) continue;
                String lk = key.toLowerCase();

                // Ignore any headers that are not particularly interesting.
                if (lk.equals("content-type") || lk.equals("content-md5") || lk.equals("date") ||
                    lk.startsWith(AMAZON_HEADER_PREFIX))
                {
                    List s = (List)headers.get(key);
                    interestingHeaders.put(lk, concatenateList(s));
                }
            }
        }

        if (interestingHeaders.containsKey(ALTERNATIVE_DATE_HEADER)) {
            interestingHeaders.put("date", "");
        }

        // if the expires is non-null, use that for the date field.  this
        // trumps the x-amz-date behavior.
        if (expires != null) {
            interestingHeaders.put("date", expires);
        }

        // these headers require that we still put a new line in after them,
        // even if they don't exist.
        if (! interestingHeaders.containsKey("content-type")) {
            interestingHeaders.put("content-type", "");
        }
        if (! interestingHeaders.containsKey("content-md5")) {
            interestingHeaders.put("content-md5", "");
        }

        // Finally, add all the interesting headers (i.e.: all that startwith x-amz- ;-))
        for (Iterator i = interestingHeaders.keySet().iterator(); i.hasNext(); ) {
            String key = (String)i.next();
            if (key.startsWith(AMAZON_HEADER_PREFIX)) {
                buf.append(key).append(':').append(interestingHeaders.get(key));
            } else {
                buf.append(interestingHeaders.get(key));
            }
            buf.append('\n');
        }

        // don't include the query parameters...
        int queryIndex = resource.indexOf('?');
        if (queryIndex == -1) {
            buf.append("/" + resource);
        } else {
            buf.append("/" + resource.substring(0, queryIndex));
        }

        // ...unless there is an acl or torrent parameter
        if (resource.matches(".*[&?]acl($|=|&).*")) {
            buf.append("?acl");
        } else if (resource.matches(".*[&?]torrent($|=|&).*")) {
            buf.append("?torrent");
        }

        return buf.toString();
    }

    /**
     * Calculate the HMAC/SHA1 on a string.
     * @param awsSecretAccessKey passcode to sign with
     * @param canonicalString string to sign
     * @param urlencode <code>true</code> to urlencode the result
     * @return Signature
     */
    static String encode(String awsSecretAccessKey, String canonicalString,
                                boolean urlencode)
    {
        // The following HMAC/SHA1 code for the signature is taken from the
        // AWS Platform's implementation of RFC2104 (amazon.webservices.common.Signature)
        //
        // Acquire an HMAC/SHA1 from the raw key bytes.
        SecretKeySpec signingKey =
            new SecretKeySpec(awsSecretAccessKey.getBytes(), HMAC_SHA1_ALGORITHM);

        // Acquire the MAC instance and initialize with the signing key.
        Mac mac = null;
        try {
            mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            // should not happen
            throw new RuntimeException("Could not find sha1 algorithm", e);
        }
        try {
            mac.init(signingKey);
        } catch (InvalidKeyException e) {
            // also should not happen
            throw new RuntimeException("Could not initialize the MAC algorithm", e);
        }

        // Compute the HMAC on the digest, and set it.
        String b64 = Base64.encodeBase64String(mac.doFinal(canonicalString.getBytes()));

        if (urlencode) {
            return urlencode(b64);
        } else {
            return b64;
        }
    }

    static String pathForListOptions(String bucket, String prefix, String marker, Integer maxKeys) {
      StringBuilder path = new StringBuilder(bucket);
        path.append('?');

        // these two params must be url encoded
        if (prefix != null) path.append("prefix=" + urlencode(prefix) + "&");
        if (marker != null) path.append("marker=" + urlencode(marker) + "&");

        if (maxKeys != null) path.append("max-keys=" + maxKeys + "&");
        path.deleteCharAt(path.length()-1);     // we've always added exactly one too many chars

        return path.toString();
    }

    static String urlencode(String unencoded) {
        try {
            return URLEncoder.encode(unencoded, CharEncoding.UTF_8);
        } catch (UnsupportedEncodingException e) {
            // should never happen
            throw new RuntimeException("Could not url encode to UTF-8", e);
        }
    }

    static XMLReader createXMLReader() {
        try {
            return XMLReaderFactory.createXMLReader();
        } catch (SAXException e) {
            // oops, lets try doing this (needed in 1.4)
            System.setProperty("org.xml.sax.driver", "org.apache.crimson.parser.XMLReaderImpl");
        }
        try {
            // try once more
            return XMLReaderFactory.createXMLReader();
        } catch (SAXException e) {
            throw new RuntimeException("Couldn't initialize a sax driver for the XMLReader");
        }
    }

    /**
     * Concatenates a bunch of header values, seperating them with a comma.
     * @param values List of header values.
     * @return String of all headers, with commas.
     */
    private static String concatenateList(List values) {
      StringBuilder buf = new StringBuilder();
        for (int i = 0, size = values.size(); i < size; ++ i) {
            buf.append(((String)values.get(i)).replaceAll("\n", "").trim());
            if (i != (size - 1)) {
                buf.append(',');
            }
        }
        return buf.toString();
    }
}
TOP

Related Classes of com.amazon.s3.Utils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.