<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>