<xsharper switchPrefixes="-">
<usage options="default ifNoArguments autoSuffix" />
<versionInfo version="1.0.0.0">Program to download files from Amazon S3.</versionInfo>
<param name="directory" required="1">Output directory</param>
<param name="files" required="1" count="multiple" description="file [file]">Files to download, formatted as bucket/directory/filename</param>
<param />
<param switch="range">Range header, in bytes. For example, 10-20</param>
<param switch="head" default="0" count="none" unspecified="1">Issue HEAD instead of GET, and do not save to file</param>
<param switch="httpHeaders" default="0" count="none" unspecified="1">Dump HTTP headers</param>
<param />
<param switch="baseUrl" default="http://s3.amazonaws.com">Service URL</param>
<param switch="accesskey" required="1">Access key</param>
<param switch="secretkey">Secret key</param>
<param switch="secretkeyfile">Text file, first line of which contains the key</param>
<param />
<param>Note: Either -secretkey or -secretkeyfile must be specified.</param>
<if isNotSet="secretKey">
<if isNotSet="secretkeyfile">
<throw>Either -secretkey or -secretkeyfile must be specified.</throw>
</if>
<set secretKey="${=.ReadLines($secretKeyFile)[0].Trim()}" />
</if>
<foreach file="${files}">
<set fname="${=Path.Combine($directory,Path.GetFileName($file)) }" />
<print outTo="^info" nl="false">s3://${file} => ${fname} ...</print>
<code />
<set url="${=X.SignUrl($baseUrl,$accesskey,$secretkey,$file, $head)}" />
<print outTo="^debug">${url}</print>
<?_ try
{
HttpWebRequest wr=(HttpWebRequest)WebRequest.Create(c.GetStr("url"));
{
if (c.IsSet("range"))
{
MethodInfo httpWebRequestAddRangeHelper = typeof(WebHeaderCollection).GetMethod("AddWithoutValidate", BindingFlags.Instance | BindingFlags.NonPublic);
httpWebRequestAddRangeHelper.Invoke(wr.Headers, new object[] { "Range", string.Format("bytes={0}", c.GetStr("range"))});
}
wr.ReadWriteTimeout = 100000;
wr.Timeout = 100000;
wr.AllowWriteStreamBuffering=false;
wr.SendChunked=true;
if (c.GetBool("head"))
wr.Method="HEAD";
HttpWebResponse resp=(HttpWebResponse)wr.GetResponse();
if (!c.GetBool("head"))
{
Stream rs= resp.GetResponseStream();
using (Stream fs=c.CreateStream(c.GetStr("fname")))
{
byte[] buf=new byte[4096];
int n;
while ((n=rs.Read(buf,0,buf.Length))!=0)
fs.Write(buf,0,n);
}
}
c.WriteLine(XS.OutputType.Info, "Done");
if (c.GetBool("httpHeaders"))
{
c.WriteLine("-- HTTP headers for {0} ---", Path.GetFileName(c.GetStr("fname")));
for (int n=0;n<resp.Headers.Count;++n)
c.WriteLine("{0}: {1}",resp.Headers.GetKey(n),resp.Headers[n]);
}
}
}
catch (WebException e)
{
if (e.Response!=null)
try {
XS.XmlDoc xs=new XS.XmlDoc(((HttpWebResponse)e.Response).GetResponseStream());
c.Error.WriteLine("Error message: {0}",xs.V("/Error/Message/text()"));
}
catch
{
}
throw;
}
?>
</foreach>
<?h using System.Security.Cryptography;
using System.Net;
using System.Reflection;
public static class X
{
public static string SignUrl(string baseUrl, string accesskey, string secretkey, string filename, bool head)
{
string path=filename.TrimStart('/');
string expiration=((long)((DateTime.UtcNow.AddDays(1)-new DateTime(1970, 1, 1)).TotalSeconds)).ToString();
using (HMACSHA1 sign = new HMACSHA1(Encoding.UTF8.GetBytes(secretkey)))
{
string escaped=Uri.EscapeUriString(path);
string stringToSign = string.Format("{0}\n\n\n{1}\n/{2}",head?"HEAD":"GET",expiration,escaped);
string authorization = Uri.EscapeDataString(Convert.ToBase64String(sign.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)),Base64FormattingOptions.None).Trim());
// Console.WriteLine(stringToSign);
return string.Format( "{0}/{1}?AWSAccessKeyId={2}&Expires={3}&Signature={4}",baseUrl, escaped,accesskey,expiration,authorization);
}
}
}
?>
</xsharper>