I'am quiet new in Azure, and I'm trying to implement the Put Block List operation according to the documentation.
Here are the steps, which I do to upload my file
Read a file from a local folder
Upload it using Put block operation. it gets succes.
Then I use
Get Block List to see if my blocks are uploaded and in the response I can see
<BlockList><CommittedBlocks /><UncommittedBlocks><Block><Name>MDAwMDAwMDAwMA==</Name><Size>17</Size></Block></UncommittedBlocks></BlockList>
that I have one uncommited block with ID MDAwMDAwMDAwMA==.
And finally I use Put Block List to commit the blob.
Here I get an error code 403 "Forbidden".
My Signature is the following
"PUT\n
\n
\n
110\n
\n
\n
\n
\n
\n
\n
\n
\n
x-ms-date:Tue, 15 May 2018 10:54:08 GMT\nx-ms-version:2017-07-29\n
/storagekaren/dbstore/ddd.txt\ncomp:blocklist"
Here is the uri
https://storagekaren.blob.core.windows.net/dbstore/ddd.txt?comp=blocklist
request content
"<?xml version=\"1.0\" encoding=\"utf-8\"?
>\r\n<BlockList>\r\n<Uncommitted>MDAwMDAwMDAwMA==</Uncommitted>
</BlockList>\r\n"
authorizationHeader is computed using this method
public static String CreateAuthorizationHeader(String canonicalizedString)
{
string signature;
using (var hmacSha256 = new
HMACSHA256(Convert.FromBase64String(STORAGE_ACCOUNT_KEY)))
{
var dataToHmac = Encoding.UTF8.GetBytes(canonicalizedString);
signature =
Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
var authorizationHeader = String.Format(
CultureInfo.InvariantCulture,
"{0} {1}:{2}",
"SharedKey",
ACCOUNT_NAME,
signature
);
return authorizationHeader;
}
"SharedKey storagekaren:eIHacFz/PWypTWg6SN/4BOuqlCLVLctABhi6Ay7TYiA="
And this is my HttpClient object to make a request
{System.Net.Http.HttpClient}
BaseAddress: null
DefaultRequestHeaders: {x-ms-date: Tue, 15 May 2018 11:07:51 GMT
x-ms-version: 2017-07-29
Authorization: SharedKey storagekaren:eIHacFz/PWypTWg6SN/4BOuqlCLVLctABhi6Ay7TYiA=
}
MaxResponseContentBufferSize: 2147483647
Timeout: {01:00:00}
Here is the response with error
HTTP/1.1 403 Server failed to authenticate the request. Make sure the value
of Authorization header is formed correctly including the signature.
Content-Length: 686
Content-Type: application/xml
Server: Microsoft-HTTPAPI/2.0
x-ms-request-id: 7a96deee-201e-00fc-78de-ec0ffc000000
x-ms-error-code: AuthenticationFailed
Date: Wed, 16 May 2018 06:22:35 GMT
<?xml version="1.0" encoding="utf-8"?><Error>
<Code>AuthenticationFailed</Code><Message>Server failed to authenticate the
request. Make sure the value of Authorization header is formed correctly
including the signature.
RequestId:7a96deee-201e-00fc-78de-ec0ffc000000
Time:2018-05-16T06:22:36.0842958Z</Message><AuthenticationErrorDetail>The
MAC signature found in the HTTP request
'E9M4w8nHaBbAsgW3Qhf+u5nHipvmxMvLp09AFdaxYZg=' is not the same as any
computed signature. Server used following string to sign: 'PUT
110
text/plain
x-ms-date:Wed, 16 May 2018 06:22:34 GMT
x-ms-version:2017-07-29
/storagekaren/dbstore/ddd.txt
comp:blocklist'.</AuthenticationErrorDetail></Error>
Please help me understand what am I doing wrong?
Essentially the problem is coming because HttpClient is adding text/plain for Content-Type header whereas you're passing an empty string for that. If you change your signature string to include content-type header, I believe you should not get this error. Essentially, your signature string should look like the following:
"PUT\n
\n
\n
110\n
\n
text/plain\n
\n
\n
\n
\n
\n
\n
x-ms-date:Tue, 15 May 2018 10:54:08 GMT\nx-ms-version:2017-07-29\n
/storagekaren/dbstore/ddd.txt\ncomp:blocklist"
Related
TL;DR
If my Content-Type "application/x-ourformat" bound custom TextInputFormatter cannot parse the input, I want to return HTTP 400 (possibly 415) back to the client.
What is the correct way to return from the implementation of ReadRequestBodyAsync to get the framework to return a 4xx HTTP response?
We have a custom formatter for application/x-ourformat built upon the TextInputFormatter as explained in the link.
The example from the MS docs above does error handling as follows:
ReadRequestBodyAsync:
public override async Task<InputFormatterResult> ReadRequestBodyAsync(
InputFormatterContext context, Encoding effectiveEncoding)
{
...
return await InputFormatterResult.SuccessAsync(contact);
}
catch
{
logger.LogError("Read failed: nameLine = {nameLine}", nameLine);
return await InputFormatterResult.FailureAsync();
}
}
That is, if the processing of the input fails with an exception, it will return FailureAsync().
However, this will NOT result in a HTTP 400 response, instead the input object bound to the Api will simply be null.
What does result in a 400 response is:
Throwing an exception out of ReadRequestBodyAsync
Setting context.ModelState.AddModelError("My Key", "Couldn't really understand you."); prior to returning FailureAsync.
But I do neither understand which one is "correct" nor do I really understand what the ModelError is supposed to represent.
I have now dug into the call chain for ReadRequestBodyAsync:
Eventually the result will be processed in BindModelAsync, which:
On HasError, Logs, and returns nothing, stating // Formatter encountered an error. Do not use the model it returned.
On exception, does ModelState.AddModelError(modelBindingKey, exception
So, since the framework itself will set a ModelError on an exception, it sure seems at least that setting the ModelError oneself is more useful.
Like ckuri noted above :
A model error represents that the model ... doesn’t satisfy a
constraint or contains malformed data. Therefore, it kinda applies in
your case.
Below is a sample response. Notice the 200 OK is before the http headers. The HTTP headers have a key and a value separated by a colon. The body is after the headers. the content length is the number of bytes in the body.
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
ETag: "34aa387-d-1568eb00"
Accept-Ranges: bytes
Content-Length: 51
Vary: Accept-Encoding
Content-Type: text/plain
Hello World! My content includes a trailing CRLF.
I want to put a text file to a blob container using HttResquestMessage, and I get 403 error(Forbidden).
I know that this is a famous problem, and there are a lot of answers about it, but I've searched a lot and couldn't find the problem in my case.
Here is my Signature
PUT\n
\n
\n
11\n
\n
\n
\n
\n
\n
\n
\n
\n
x-ms-blob-type:BlockBlob\n
x-ms-date:Thu, 10 May 2018 16:00:21 GMT\n
x-ms-version:2017-07-29\n
/MyStorage/dbstore/myFolder/test2.txt"
And this is Authorization generated by SHA256 and Base64 encoding
SharedKey MyStorage:Oy8nB79/KVROzxYCYSF71djhIwYEYS36tgRqyxe6sXY=
This Authorization works for GET request I've tried to get all container names and it succeeded.
My HttpRequestMessage looks like
{Method: PUT, RequestUri:
'http://MyStorage.blob.core.windows.net/dbstore/
myFolder/test2.txt', Version: 1.1, Content:
System.Net.Http.ByteArrayContent, Headers:
{
x-ms-date: Fri, 11 May 2018 06:39:35 GMT
x-ms-version: 2017-07-29
Authorization: SharedKey
storagekaren:Oy8nB79/KVROzxYCYSF71djhIwYEYS36tgRqyxe6sXY=
Content-Length: 11
Content-MD5: CAQ66JnJH0H9GhrLTy+b1w==
}}
Content: {System.Net.Http.ByteArrayContent}
Headers: {x-ms-date: Fri, 11 May 2018 06:39:35 GMT
x-ms-version: 2017-07-29
Authorization: SharedKey
storagekaren:Oy8nB79/KVROzxYCYSF71djhIwYEYS36tgRqyxe6sXY=
}
Method: {PUT}
Properties: Count = 0
RequestUri: {http://MyStorage.blob.core.windows.net/dbstore/myFolder/test2.txt}
Version: {1.1}
What I missed in the request?
Two parameters need adding when putting blob
x-ms-blob-type is required to be included in HttpRequestMessage header.
Content-MD5 is optional, but if you add it in your request header, it should also be included in StringToSign, i.e. the Signature you mentioned.
Any further question, just ask.
In my OwinMiddleware I just write out to the body:
await context.Response.Body.WriteStringAsync("Hey There");
The raw response I get in Fiddler is:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Server: Microsoft-HTTPAPI/2.0
Date: Fri, 13 May 2016 16:00:07 GMT
A
/hey/there
5
there
9
Hey There
26
{ec86d5c7-4ea4-437f-be2a-4e294b655227}
0
And Fiddler is saying this encoded (with a message saying please click here decode)
The single letters and numbers are not mine. I wrote /hey/there and there and Hey There and the Guid with braces.
How do I just get the plain text response?
I'm trying to get the same type of results that Fiddler gets when I launch a webpage from my app.
Below is the code I'm using and the results I'm getting. I've used google.com only as an example.
What do I need to modify in my code to get the results I want or do I need an entirely different approach?
Thanks for your help.
My code:
// create the HttpWebRequest object
HttpWebRequest objRequest = (HttpWebRequest)WebRequest.Create("http://www.google.com");
// get the response object which has the header info, using the GetResponse method
var objResults = objRequest.GetResponse();
// get the header count
int intCount = objResults.Headers.Count;
// loop through the results object
for (int i = 0; i < intCount; i++)
{
string strKey = objResults.Headers.GetKey(i);
string strValue = objResults.Headers.Get(i);
lblResults.Text += strKey + "<br />" + strValue + "</br /><br />";
}
My results:
Cache-Control
private, max-age=0
Content-Type
text/html; charset=ISO-8859-1
Date
Tue, 05 Jun 2012 17:40:38 GMT
Expires
-1
Set-Cookie
PREF=ID=526197b0260fd361:FF=0:TM=1338918038:LM=1338918038:S=gefqgwkuzuPJlO3G; expires=Thu, 05-Jun-2014 17:40:38 GMT; path=/; domain=.google.com,NID=60=CJbpzMe6uTKf58ty7rysqUFTW6GnsQHZ-Uat_cFf1AuayffFtJoFQSIwT5oSQKqQp5PSIYoYtBf_8oSGh_Xsk1YtE7Z834Qwn0A4Sw3ruVCA9v3f_UDYH4b4fAloFJbW; expires=Wed, 05-Dec-2012 17:40:38 GMT; path=/; domain=.google.com; HttpOnly
P3P
CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
Server
gws
X-XSS-Protection
1; mode=block
X-Frame-Options
SAMEORIGIN
Transfer-Encoding
chunked
=========================
Fiddler results:
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
1 304 HTTP www.rolandgarros.com /images/misc/weather/P8.gif 0 max-age=700 Expires: Tue, 05 Jun 2012 17:53:40 GMT image/gif firefox:5456
2 200 HTTP www.google.com / 23,697 private, max-age=0 Expires: -1 text/html; charset=UTF-8 chrome:2324
3 304 HTTP www.rolandgarros.com /images/misc/weather/P9.gif 0 max-age=700 Expires: Tue, 05 Jun 2012 17:53:57 GMT image/gif firefox:5456
4 200 HTTP Tunnel to translate.googleapis.com:443 0 chrome:2324
5 200 HTTP www.google.com
The difference is Fiddler is actually recording an entire session, not just a single HTTP request.
If a user loads Google.com, the response is typically an HTML document which contains images, script files, CSS files, etc. Your browser will then initiate a new HTTP request for each one of those resources. With Fiddler running, it tracks each of those HTTP requests and spits out the result code and other information about the session.
With your C# code above, you're only initiating a single HTTP request, thus you only have information about a single result.
You'd probably be better off writing a browser plugin. Otherwise, you'd have to parse the HTML response and load other resources from that document as well.
If you do need to do this with C# code, you could probably parse the document with the HTML Agility Pack and then look for other resources within the HTML to simulate a browser. There's also embedded browsers, such as Awesomium, that might be helpful.
You are not asking for the same information that Fiddler is displaying. Fiddler shows the HTTP Status code, the host and URI and (it appears, from your example) the Content Length, Content Type and Cache status.
For many of these you will have to peek in to the response headers.
I'm running the following code;
using (WebClient wc = new WebClient())
{
string page = wc.DownloadString(URL);
...
}
To access the URL of a share price website, http://www.shareprice.co.uk
If you append a company's symbol name onto the end of the URL, then a page is returned which I parse to get the latest price info etc.
e.g.
http://www.shareprice.co.uk/VOD
http://www.shareprice.co.uk/TW.
Now, my problem is that some symbols end in periods, as in the second example there. For some unknown reason, the code above has a problem retrieving these sorts of URLs.
There is no run-time error, but a page is returned back which reports "Symbol could not be found" from the website itself, indicating that something is happening to the period on the end of the URL in between the call to DownloadString and the actual HTTP request.
Does anyone have any idea what might be causing this, and how to fix it?
Thanks
It seems you found a bug in WebClient/WebRequest, though perhaps Microsoft put that in intentionally, who knows. Nonetheless, when you pass in TW., the URI class is translating that to TW without the period. Since WebClient/WebRequest parse strings into URI, your . is disappearing in that world.
You may have to use TcpClient to get around this and roll your own web client. Any variation of this:
TcpClient oClient = new TcpClient("www.shareprice.co.uk", 80);
NetworkStream ns = oClient.GetStream();
StreamWriter sw = new StreamWriter(ns);
sw.Write(
string.Format(
"GET /{0} HTTP/1.1\r\nUser-Agent: {1}\r\nHost: www.shareprice.co.uk\r\n\r\n",
"TW.",
"MyTCPClient" )
);
sw.Flush();
StringBuilder sb = new StringBuilder();
while (true)
{
int i = ns.ReadByte(); // Inefficient but more reliable
if (i == -1) break; // Other side has closed socket
sb.Append( (char) i ); // Accrue 'c' to save page data
}
oClient.Close();
This will give you a 302 redirect, so just parse out the 'Location:' and execute the above again with the new location.
HTTP/1.1 302 Found
Date: Wed, 11 Nov 2009 19:29:27 GMT
Server: lighttpd
X-Powered-By: PHP/5.2.4-2ubuntu5.7
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Location: /TW./TAYLOR-WIMPEY-PLC
Content-type: text/html; charset=UTF-8
Content-Length: 0
Set-Cookie: SSID=668d5d0023e9885e1ef3762ef5e44033; path=/
Vary: Accept-Encoding
Connection: close
Try adding a slash to the end, after the period. Your normal web browser will do that for you, and the WebClient class isn't that smart.
http://www.shareprice.co.uk/TW./
This worked for me as well when I typed it into the browser.
Edit - added
The following all also worked in the browser
http://www.shareprice.co.uk/TW
and
http://www.shareprice.co.uk/TW/
so it looks like you should be able to just check to see if the last character is a period, and remove it.
use URL encoding...it will turn the "." into %2E
To address a single period (.) at the end of a URL use the following:
<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
</system.web>
To address two periods (..) or other denied sequences, see the following article:
http://www.iis.net/ConfigReference/system.webServer/security/requestFiltering/denyUrlSequences
Just add a space after the period, when parsing the space will be removed but the period will stay there.