C# HttpWebRequest Date Header Formatting

后端 未结 4 941
無奈伤痛
無奈伤痛 2020-12-30 13:13

I\'m making a HttpWebRequest to S3, and I\'m trying to set the Date header to something like this:

\"Mon, 16 Jul 2012 01:16:18 -0000\"

相关标签:
4条回答
  • 2020-12-30 13:27

    There are some things to clarify:

    • Your date pattern is incorrect.

    • The HttpWebRequest request.Date header can be only get modified in .NET Framework 4 and according to the documentation, the System.Net namespace will always write this header as standard form using GMT (UTC) format. So, whatever you can do to format your date as you want, won't work!

    • In other .NET framework versions you won't be able to modify the HttpWebRequest request.Date header because it will use the actual date in correct GMT (UTC) format unless you use a kind of hack to set your own date and format (see below).


    Solution for your problem (tested and working):

    Your imports:

    using System.Net;
    using System.Reflection;
    

    Get today's date in format: Mon, 16 Jul 2012 01:16:18 -0000

    string today = String.Format("{0:ffffd,' 'dd' 'MMM' 'yyyy' 'HH':'mm':'ss' 'K}", DateTime.Now);
    

    Here comes the tricky thing, you can hack the HttpWebRequest date header by doing this:

    (Don't do request.Date = something; anymore, replace it with the following)

    MethodInfo priMethod = request.Headers.GetType().GetMethod("AddWithoutValidate", BindingFlags.Instance | BindingFlags.NonPublic);
    priMethod.Invoke(request.Headers, new[] { "Date", today });
    

    Get the date from your request (just to test):

    // "myDate" will output the same date as the first moment: 
    // Mon, 16 Jul 2012 01:16:18 -0000
    // As you can see, you will never get this again:
    // Mon, 16 Jul 2012 07:16:18 GMT
    string myDate = request.Headers.Get("Date");
    

    At this point you had successfully set your own format and date value to the HttpWebRequest date header!

    Hope this helps :-)

    0 讨论(0)
  • 2020-12-30 13:36

    Assuming you want to set the Date header for Authorization header to work.

    Amazon provides another custom header which will used instead of Date (if provided). If you are unable to set Date header, you can use the custom header, x-amz-date instead.

    Here's the link to amazon's docs here

    0 讨论(0)
  • 2020-12-30 13:45

    You should use "X-Amz-Date" header.

    public void GetObject(string AccessKeyID, string SecretKey){           
            /*objectKey = folder/folder/filename.zzz*/
            var url = "http://somehost/bucket/objectkey"
    
            HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
            /*Fiddler proxy*/
            /*request.Proxy = new WebProxy("http://127.0.0.1:8888");*/
    
            request.Headers.Add("X-Amz-Date",String.Format("{0:ffffd,' 'dd' 'MMM' 'yyyy' 'HH':'mm':'ss' 'K}", DateTime.Now));
            request.Headers.Add("Authorization", $"AWS {AccessKeyID}:{SignAuthorizationString(request, SecretKey)}");
    
            WebResponse response = request.GetResponse();
            }
    private string SignAuthorizationString(HttpWebRequest request, string SecretKey){
            //TODO: DOCS - http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
    
            string canonicalizedResource = request.RequestUri.PathAndQuery;
            string canonicalizedAmzHeaders  = ComposeSignatureAmzHeadersForSigning(request);
            string stringToSign = request.Method + "\n"
                                  + request.Headers.Get("Content-MD5") + "\n"
                                  + request.ContentType + "\n"
                                  + request.Headers.Get("Date") + "\n" /*Here the date will be blank*/
                                  + canonicalizedAmzHeaders + canonicalizedResource;
    
            return GetSignedMessage(SecretKey, stringToSign);
            }
     private string ComposeSignatureAmzHeadersForSigning(HttpWebRequest request){
            SortedDictionary<string, string> headersDictionary = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            foreach (string _key in request.Headers.Keys)
            {
                key = _key.ToLower(); 
                if (key.StartsWith("x-amz"))
                {
                    if ("x-amz-meta-reviewedby".Equals(key))
                    {
                        if (headersDictionary.ContainsKey(key))
                            headersDictionary[key] = headersDictionary[key] + "," + request.Headers[key];
                        else
                            headersDictionary[key] = request.Headers[key];
                    }
                    else
                        headersDictionary[key] = request.Headers.Get(key);
                }
            }
            StringBuilder stringBuilder = new StringBuilder();
            foreach (var pair in headersDictionary)
            {
                stringBuilder.Append(pair.Key)
                    .Append(":")
                    .Append(pair.Value)
                    .Append("\n");
    
            }
            return stringBuilder.ToString();
            }
    private static string GetSignedMessage(string key, string message){
            var crypt = HMACSHA1.Create();
            crypt.Key = Encoding.ASCII.GetBytes(key);
            crypt.ComputeHash(Encoding.UTF8.GetBytes(message));
    
            return Convert.ToBase64String(crypt.Hash);
            }
    
    0 讨论(0)
  • 2020-12-30 13:46

    The HttpWebRequest will properly format the Date by itself. Your problem is that you must submit a valid current date. You have to check that the clock of the computer is accurate, and then that you are sending the proper date regarding Time Zones and UTC and GMT issues...

    try both:

    request.Date = DateTime.Now;
    request.Date = DateTime.UtcNow;
    

    one of that needs to work (and both should work if HttpWebRequest is properly implemented).

    In case that doesn't work, use fiddler to see what's going on, and fix the request by hand until you get it working

    0 讨论(0)
提交回复
热议问题