Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign upIs the Content-Type header produced by StringContent() correct? #7864
Comments
This comment has been minimized.
This comment has been minimized.
|
Looks like it will always put something out |
davidsh
added
area-System.Net
question
labels
Apr 19, 2016
This comment has been minimized.
This comment has been minimized.
|
The You can always replace the |
This comment has been minimized.
This comment has been minimized.
|
It's certainly invalid. RFC 2046 (RFC 6657 is also relevant) allows for the charset parameter as part of content-types only if it's |
This comment has been minimized.
This comment has been minimized.
|
@benaadams @JonHanna Thanks for finding the references to both. Even if it were valid (e.g., I don't know if this is what is choking my ATS REST service calls, but it's possible, since @davidsh How? I get an exception if I try to mod the header by adding ... client.DefaultRequestHeaders.Add("Content-Type", contentType);... throws ...
Here's the hacked code I'm playing with (i.e., not for production ... I'm just hacking around to get the requests working). How would I set the using (var client = new HttpClient())
{
DateTime requestDT = DateTime.UtcNow;
UTF8Encoding utf8Encoding = new UTF8Encoding();
string storageAccountName = "<STORAGE_ACCOUNT_NAME>";
string tableName = "<TABLE_NAME>";
//string requestMethod = "POST";
string dateInRfc1123Format = requestDT.ToString("R", CultureInfo.InvariantCulture);
string storageServiceVersion = "2015-04-05";
string storageAccountKey = "<STORAGE_ACCOUNT_KEY>";
string canonicalizedResource = $"/{storageAccountName}/{tableName}";
string contentType = "application/atom+xml";
// Content
string requestPayload = GetRequestContentInsertXml(requestDT, "PKEY", "RKEY");
var stringContent = new StringContent(requestPayload, Encoding.UTF8, contentType);
// Will not authorize against the service:
// string stringToSign = $"{requestMethod}\n\n{contentType}\n{dateInRfc1123Format}\n{canonicalizedResource}";
// SharedKeyLite works:
string stringToSign = $"{dateInRfc1123Format}\n{canonicalizedResource}";
string authorizationHeader = CreateAuthorizationParameter(stringToSign, storageAccountName, storageAccountKey);
AuthenticationHeaderValue myAuthHeaderValue = new AuthenticationHeaderValue("SharedKeyLite", authorizationHeader);
// Headers
client.DefaultRequestHeaders.Authorization = myAuthHeaderValue;
client.DefaultRequestHeaders.Add("x-ms-date", dateInRfc1123Format);
client.DefaultRequestHeaders.Add("x-ms-version", storageServiceVersion);
client.DefaultRequestHeaders.Add("DataServiceVersion", "3.0;NetFx");
client.DefaultRequestHeaders.Add("MaxDataServiceVersion", "3.0;NetFx");
// Doesn't work: client.DefaultRequestHeaders.Add("Content-Type", contentType);
var responseMessage = client.PostAsync($"https://{storageAccountName}.table.core.windows.net/{tableName}", stringContent).Result;
responseResult.Append("StatusCode: " + responseMessage.StatusCode.ToString() + " ");
} |
This comment has been minimized.
This comment has been minimized.
|
When modifying "known" headers, you need to use the properties and not the 'DefaultRequestHeaders' method. For request entity-body headers (content), you need to modify the `HttpRequestMessage.Content.Headers1 collection. You are getting an exception telling you that basically. So, you need code like this: var content = new StringContent(...);
content.Headers.ContentType = ...;You can also use methods like this as well: var content = new StringContent(...);
content.Headers.Remove(...);
content.Headers.Add(...); |
This comment has been minimized.
This comment has been minimized.
|
@davidsh Ah ... ok ... thx ... that got the header squared away ... stringContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);And My issue is solved, but do you want to leave this open given what @JonHanna reported? |
This comment has been minimized.
This comment has been minimized.
We will research this to determine if there are RFC issues. This code has existed for 5+ years and was previously reviewed by our RFC compliance experts. I'll leave this open for now. |
davidsh
removed
the
question
label
Apr 19, 2016
davidsh
self-assigned this
Apr 19, 2016
davidsh
added this to the 1.0.0-rtm milestone
Apr 19, 2016
This comment has been minimized.
This comment has been minimized.
|
I was incorrect. While |
This comment has been minimized.
This comment has been minimized.
|
My concern about it remains: If the dev sets a value explicitly on In any case where the header is part of a service-generated hash that will be checked against a supplied signature (without the If the dev sets an explicit value, seems like it should be honored. At least mod the description to note that |
This comment has been minimized.
This comment has been minimized.
|
Just for completeness, I checked the Azure Service REST Service using the default ... StringContent("<data>", Encoding.UTF8, "application/atom+xml");... but supplying the content type to the signature string as ... string contentType = "application/atom+xml; charset=utf-8";
string stringToSign =
$"{requestMethod}\n\n{contentType}\n{dateInRfc1123Format}\n{canonicalizedResource}";That works. It's still awfully cryptic tho without a little help. |
This comment has been minimized.
This comment has been minimized.
darrelmiller
commented
May 13, 2016
•
|
@JonHanna Usually it is the media type registration document that defines what parameters are allowed. In the application/atom+xml the registration refers explicitly back RFC3023 for the rules, as you stated. Interestingly, the .net stack loves adding charset onto
It would be awesome if this could be fixed. |
This comment has been minimized.
This comment has been minimized.
|
We plan to fix this in CoreFx. We need to study if porting this to .NET Framework (Desktop) will have any app-compat issues. |
This comment has been minimized.
This comment has been minimized.
|
This will require a new overload to the StringContent constructor so that the charset isn't specified by default on the |
davidsh
added
area-System.Net.Http
api-needs-work
and removed
area-System.Net
untriaged
labels
Feb 16, 2017
davidsh
modified the milestones:
Future,
2.0.0
Feb 16, 2017
davidsh
added
the
up-for-grabs
label
Feb 16, 2017
This comment has been minimized.
This comment has been minimized.
tknuts
commented
Aug 23, 2018
|
Hi
Quite simpel..... If I do this in Postman it works, but i keep getting 415 error "Unsupported Media Type" :-( Why? Desperate now, tried everything..... Can do GET requests, but not POST. I can get the same error in Postman by removing the Content-Type header... |
This comment has been minimized.
This comment has been minimized.
tknuts
commented
Aug 23, 2018
|
Here is my request in Fiddler:
And here the response:
Here is the one from Postman that works, what am I missing?
|
This comment has been minimized.
This comment has been minimized.
tknuts
commented
Aug 23, 2018
|
Did the trick :-) |
This comment has been minimized.
This comment has been minimized.
@davidsh, can you elaborate on why this would require a new API? |
This comment has been minimized.
This comment has been minimized.
|
This is the current API: public partial class StringContent : System.Net.Http.ByteArrayContent
{
public StringContent(string content) : base (default(byte[])) { }
public StringContent(string content, System.Text.Encoding encoding) : base (default(byte[])) { }
public StringContent(string content, System.Text.Encoding encoding, string mediaType) : base (default(byte[])) { }
}None of the overloads take any 'charset' parameter. But they all create one anyways. See public StringContent(string content, Encoding encoding, string mediaType)
: base(GetContentByteArray(content, encoding))
{
// Initialize the 'Content-Type' header with information provided by parameters.
MediaTypeHeaderValue headerValue = new MediaTypeHeaderValue((mediaType == null) ? DefaultMediaType : mediaType);
headerValue.CharSet = (encoding == null) ? HttpContent.DefaultStringEncoding.WebName : encoding.WebName;
Headers.ContentType = headerValue;
}So, we would need a new overload that could explicitly take a charset parameter (or null) etc. |
guardrex commentedApr 19, 2016
Consider the following code ...
According to Wireshark, I'm seeing a POST using
HttpClientwith this ...Shouldn't that
Content-Typevalue just be ...?? Confused, because something is choking my Azure Table Storage requests with ...
... and since
SharedKeyLite, which only requires the date and resource, works with mydateInRfc1123FormatandcanonicalizedResource, I've sort of narrowed it down to thecontentTypeof the request (shown above) not matching what I'm putting into the signature sting, namely justapplication/atom+xml.