¿ªÔÆÌåÓý

ctrl + shift + ? for shortcuts
© 2025 Groups.io

HttpsClient => Content-Length issue


 

I am here having an issue with the HttpsClient.
The request runs into an "unknown error" whenever I try to add Content-Length to the header. It runs fine otherwise.
About the sample code below: you can directly copy/paste into VS2008 and load it as a test. I added a console command called "getit" to easily trigger the request.
This sample code works fine as is.?I also added my own custom header "Mycustomheader": "foo" and I do see it included on the response from httbin.org. This tells me that the custom headers do work as intended.
?
However, the moment this line gets uncommented:
//request.Header.SetHeaderValue("Content-Length", payload.Length.ToString());
The whole thing breaks down. And I can't figure out why... any help would be greatly appreciated.




using System;
using Crestron.SimplSharp;? ? ? ? ? ? ? ? ? ? ? ? ? // For Basic SIMPL# Classes
using Crestron.SimplSharpPro;? ? ? ? ? ? ? ? ? ? ? ? // For Basic SIMPL#Pro classes
using Crestron.SimplSharpPro.CrestronThread;? ? ? ? // For Threading
using Crestron.SimplSharpPro.Diagnostics; ? ? // For System Monitor Access
using Crestron.SimplSharpPro.DeviceSupport;? ? ? ? ? // For Generic Device Support
using Crestron.SimplSharp.Net.Https;
?
namespace Simplified_Test
{
? ? public class ControlSystem : CrestronControlSystem
? ? {
? ? ? ? #region Private Fields
? ? ? ? private HttpsClient _httpsClient;
? ? ? ? #endregion
?
? ? ? ? public ControlSystem()
? ? ? ? ? ? : base()
? ? ? ? {
? ? ? ? ? ? try
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Thread.MaxNumberOfUserThreads = 20;
?
? ? ? ? ? ? ? ? //Subscribe to the controller events (System, Program, and Ethernet)
? ? ? ? ? ? ? ? CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(ControlSystem_ControllerProgramEventHandler);
?
? ? ? ? ? ? }
? ? ? ? ? ? catch (Exception e)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? ErrorLog.Error("Error in the constructor: {0}", e.Message);
? ? ? ? ? ? }
? ? ? ? }
?
?
? ? ? ? public override void InitializeSystem()
? ? ? ? {
? ? ? ? ? ? try
? ? ? ? ? ? {
? ? ? ? ? ? ? ? CrestronConsole.AddNewConsoleCommand(ConsoleCommandGetIt, "getit", "sends a GET request to httpbin with a small payload", ConsoleAccessLevelEnum.AccessAdministrator); //for tests
?
? ? ? ? ? ? ? ? _httpsClient = new HttpsClient();
? ? ? ? ? ? ? ? _httpsClient.Accept = "application/json";
? ? ? ? ? ? ? ? _httpsClient.KeepAlive = true;
? ? ? ? ? ? ? ? _httpsClient.Timeout = 20;
?
? ? ? ? ? ? ? ? _httpsClient.HostVerification = false;? ?//set to false for now - to keep things simple
? ? ? ? ? ? ? ? _httpsClient.PeerVerification = false;? ?//set to false for now - to keep things simple
?
? ? ? ? ? ? }
? ? ? ? ? ? catch (Exception e)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? ErrorLog.Error("Error in InitializeSystem: {0}", e.Message);
? ? ? ? ? ? }
? ? ? ? }
?
? ? ? ? #region Creates a request and dispatches it Async
? ? ? ? private void ConsoleCommandGetIt(string cmdParameters)
? ? ? ? {
? ? ? ? ? ? string url = "https://httpbin.org/anything";
? ? ? ? ? ? string payload = "{\"memberId\":123,\"resultId\":1,\"timestamp\":\"2022-02-09T18:18:04.000Z\"}";
? ? ?
?
? ? ? ? ? ? var request = new HttpsClientRequest();
? ? ? ? ? ? request.Url.Parse(url);
? ? ? ? ? ? request.RequestType = RequestType.Get;
? ? ? ? ? ? request.Header.ContentType = "application/json";
? ? ? ? ? ? request.Header.SetHeaderValue("myCustomHeader", "foo"); //adding a custom header just to see if it appears on the far end
? ? ? ? ? ??
?
? ? ? ? ? ? //adding the json payload to the body of this request
? ? ? ? ? ? request.ContentString = payload;
?
? ? ? ? ? ? //trying to add a Content-Length to the header
? ? ? ? ? ? //request.Header.SetHeaderValue("Content-Length", payload.Length.ToString());
? ? ? ? ? ? //CrestronConsole.PrintLine("The request header as built is: " + request.Header.ToString());
?
? ? ? ? ? ? CrestronConsole.PrintLine("The request payload is: " + request.ContentString);
? ? ? ? ? ??
? ? ? ? ? ? //trying to dispatch it async
? ? ? ? ? ? var result = _httpsClient.DispatchAsync(request, httpsClientResponseCallback);
? ? ? ? ? ? if (result > 0)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? CrestronConsole.PrintLine("There was an error with the dispatch async. Error code: " + (HttpsClient.DISPATCHASYNC_ERROR)result);
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? CrestronConsole.PrintLine("The request has been dispatched. Now waiting for a reply.");
? ? ? ? ? ? }
?
? ? ? ? }
? ? ? ? #endregion
?
? ? ? ? #region Here is the reply from the far end
? ? ? ? private void httpsClientResponseCallback(HttpsClientResponse response, HTTPS_CALLBACK_ERROR error)
? ? ? ? {
? ? ? ? ? ? CrestronConsole.PrintLine("The response for the request returned " + (HTTPS_CALLBACK_ERROR)error);
?
? ? ? ? ? ? if (error > 0) //if this is true, the response object will be null!!! Don't try to further process it.
? ? ? ? ? ? {
? ? ? ? ? ? ? ? CrestronConsole.PrintLine("httpsClientResponseCallback -> HTTPS_CALLBACK_ERROR=" + error);
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
?
? ? ? ? ? ? CrestronConsole.PrintLine("The response code was " + response.Code);? ? //In the realword, I should make some logic that will look for a 200 OK and properly manage error codes in a log somehow.
?
? ? ? ? ? ? CrestronConsole.PrintLine("The response Encoding was " + response.Encoding);
? ? ? ? ? ? CrestronConsole.PrintLine("The response ContentLength was " + response.ContentLength);
? ? ? ? ? ? CrestronConsole.PrintLine("The URL of whoever provided this response is " + response.ResponseUrl);
? ? ? ? ? ? CrestronConsole.PrintLine("The response.Header.FirstHeader is: " + response.Header.FirstHeader);? ? ? ?//this seems to always return empty.
? ? ? ? ? ? CrestronConsole.PrintLine("The response.Header.RequestVersion is: " + response.Header.RequestVersion); //this seems to always return empty.
?
? ? ? ? ? ? CrestronConsole.PrintLine("The response.Chunked is " + response.Chunked);
?
? ? ? ? ? ? CrestronConsole.PrintLine("The response entire Header was:\n " + response.Header.ToString());
?
? ? ? ? ? ? CrestronConsole.PrintLine("Here is the actual response body:");
? ? ? ? ? ? CrestronConsole.PrintLine(response.ContentString);
?
? ? ? ? }
? ? ? ? #endregion
?
? ? ? ? #region House Cleaning
? ? ? ? void ControlSystem_ControllerProgramEventHandler(eProgramStatusEventType programStatusEventType)
? ? ? ? {
? ? ? ? ? ? switch (programStatusEventType)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? case (eProgramStatusEventType.Stopping):
? ? ? ? ? ? ? ? ? ? _httpsClient.Dispose();
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
?
? ? ? ? }
? ? ? ? #endregion?
?
?
? ? ? ??
? ? }
}


 

I'm not certain what is going wrong with your content length header, however I wanted to share how I was handling the headers in a different way than your code. Perhaps it will be helpful to you. This seems to work consistently for me with any type of header I have tried so far. Hope this helps.

Partial code below:

?????? public void SomeMethod()
??????????????? url = "someURL";

??????????????? var headers = new HttpsHeaders();
??????????????? var authHeader = new HttpsHeader("Authorization", authToken);
??????????????? headers.AddHeader(authHeader);

??????????????? response = SendRequest(url, RequestType.Get, headers, "");
??????????????? // do some response processing here


????? private HttpsClientResponse SendRequest(string url, RequestType type, HttpsHeaders headers, string body)
??????? {
??????????? string myURL;

??????????? // setup the client
??????????? HttpsClient client = new HttpsClient();
??????????? client.HostVerification = false;
??????????? client.PeerVerification = false;
?????????? ?

??????????? // setup request
??????????? HttpsClientRequest request = new HttpsClientRequest();
??????????? myURL = String.Format("https://{0}/{1}/{2}", ServerAddress, APIVersion, url);
??????????? request.Url.Parse(myURL);
??????????? request.RequestType = type;
??????????? if (headers != null)
??????????? {
??????????????? request.Header = headers;
??????????? }
??????????? request.Encoding = Encoding.UTF8;
??????????? request.ContentString = body;
??????????? request.ContentSource = ContentSource.ContentString;

??????????? // dispatch the request below


 

Take a look at my example on Github for the HttpsUtility.

--
?
Crestron Service Provider - TBD Enterprises Inc.


 

Thank you guys for the replies, but the issue seems to be very peculiar indeed.
Important to note that things work properly on the http version. This issue?only?occurs?on https .
The problem seems to be that Crestron https fails to include the Content-Length in the header, and if I try to add it myself, it will cause the https client to fail (becomes unresponsive, with nothing on the error log that I can tell).
Important to note that this is not a matter of making a mistake when adding the header: I tested this by adding some other custom headers and they work just fine. But as soon as I try to add a Content-Length header it will freeze without any clues as to why (which is something I shouldn't have to do to begin with).
?
Here is a more simplified version of the code with a functional example demonstrating both the pass/fail scenarios. It can be loaded in a 3-series and tested from the console.
?
Troy: I ran a test with your utility to send out a GET request to??and the exact same thing happened: crestron does not seem to send Content-Length, but if I add a Content-Length as custom header (which matches my payload, of course)? the module doesn't work (I suspect Crestron never sends the request to begin with).
Erik: I gave it a shot using your way as well but the problem persisted. The issue seems deeper than the just the code-base we are using.
?
Based on some reading I did, Content-Length is one of those things that is optional or mandatory depending on the HTTP version, and I can't really sniff anything meaningful with Wireshark because its all encrypted.
I'm starting to think if this has anything to do with what HTTP Version Crestron is using... I might open a case with crestron, will keep trying...?
?


Master He
 

When you send a "GET" request, there should be no Content.

I have never needed to add content length myself in the header for Crestron http or https.

Cheers,

On Friday, February 11, 2022, 07:54:42 a.m. PST, fabiodaubermann <fdaubermann@...> wrote:


Thank you guys for the replies, but the issue seems to be very peculiar indeed.
Important to note that things work properly on the http version. This issue?only?occurs?on https .
The problem seems to be that Crestron https fails to include the Content-Length in the header, and if I try to add it myself, it will cause the https client to fail (becomes unresponsive, with nothing on the error log that I can tell).
Important to note that this is not a matter of making a mistake when adding the header: I tested this by adding some other custom headers and they work just fine. But as soon as I try to add a Content-Length header it will freeze without any clues as to why (which is something I shouldn't have to do to begin with).
?
Here is a more simplified version of the code with a functional example demonstrating both the pass/fail scenarios. It can be loaded in a 3-series and tested from the console.
?
Troy: I ran a test with your utility to send out a GET request to??and the exact same thing happened: crestron does not seem to send Content-Length, but if I add a Content-Length as custom header (which matches my payload, of course)? the module doesn't work (I suspect Crestron never sends the request to begin with).
Erik: I gave it a shot using your way as well but the problem persisted. The issue seems deeper than the just the code-base we are using.
?
Based on some reading I did, Content-Length is one of those things that is optional or mandatory depending on the HTTP version, and I can't really sniff anything meaningful with Wireshark because its all encrypted.
I'm starting to think if this has anything to do with what HTTP Version Crestron is using... I might open a case with crestron, will keep trying...?
?


 

On Fri, Feb 11, 2022 at 08:54 AM, fabiodaubermann wrote:
Troy: I ran a test with your utility to send out a GET request to??and the exact same thing happened: crestron does not seem to send Content-Length, but if I add a Content-Length as custom header (which matches my payload, of course)? the module doesn't work (I suspect Crestron never sends the request to begin with).
I've never seen the need for a Content-Length on a GET requests because it isn't really standard to have a message body in GET requests. Think about what happens when you type a URL in your browser.
?
--
?
Crestron Service Provider - TBD Enterprises Inc.


 

Hi Troy and MasterHe,
?
Good points indeed. What you said makes?sense:? a GET request should have no body (if we are to follow the standard).
One of the things that threw me off is the inconsistency on the crestron libraries between http and https. Got me into a rabbit hole.
?
The Http library does add a content-length on a GET request, even though it shouldn't (its a bug! not a feature!)
The Https library does not add a content-length on a GET (It's a feature! Not a bug!) and will even freeze if you try to add one (ok so this one might be a bug! not a feature.)
?
Now on to the next hurdle: POST request. Based on my tests here, looks like Crestron only sends POST messages with Content-Type: application/x-www-form-urlencoded.
It seems to be ignoring the fact that I am trying to send data as?Content-Type:?application/json
I'm wondering if I'm missing something obvious.
?
I updated the sample program (on github)? in case you would like to see what I am referring to.
?


Master He
 

Hi there,


"Now on to the next hurdle: POST request. Based on my tests here, looks like Crestron only sends POST messages with Content-Type: application/x-www-form-urlencoded.
It seems to be ignoring the fact that I am trying to send data as?Content-Type:?application/json"

You can specify the content type in request header, example code:

? ? ? ? ? ? ? ? HttpsClientRequest request = new HttpsClientRequest();
? ? ? ? ? ? ? ? request.RequestType = RequestType.Post;
? ? ? ? ? ? ? ? request.Url.Parse(fullUrlString);
? ? ? ? ? ? ? ? request.Header.AddHeader(this.credHeader);

? ? ? ? ? ? ? ? request.Header.AddHeader(new HttpsHeader("Content-Type", "application/json"));


Cheers,


On Sunday, February 13, 2022, 06:48:21 p.m. PST, fabiodaubermann <fdaubermann@...> wrote:


Hi Troy and MasterHe,
?
Good points indeed. What you said makes?sense:? a GET request should have no body (if we are to follow the standard).
One of the things that threw me off is the inconsistency on the crestron libraries between http and https. Got me into a rabbit hole.
?
The Http library does add a content-length on a GET request, even though it shouldn't (its a bug! not a feature!)
The Https library does not add a content-length on a GET (It's a feature! Not a bug!) and will even freeze if you try to add one (ok so this one might be a bug! not a feature.)
?
Now on to the next hurdle: POST request. Based on my tests here, looks like Crestron only sends POST messages with Content-Type: application/x-www-form-urlencoded.
It seems to be ignoring the fact that I am trying to send data as?Content-Type:?application/json
I'm wondering if I'm missing something obvious.
?
I updated the sample program (on github)? in case you would like to see what I am referring to.
?