delphiindyidhttp

Delphi: TIdHTTP loses encoding in exception


I make a HTTP POST request using TIdHTTP:

var
  ssRequest, ssResponse: TStringStream;
...
  IdHTTP.Post(fullUrl, ssRequest, ssResponse);

The server responds with:

400 Bad Request

and passes useful information in the response body (this is JSON in UTF-8 encoding). The problem is that in this case, TIdHTTP generates an exception on the POST request of type EIdHTTPProtocolException and I can’t get the original response's bytes. I can only read EIdHTTPProtocolException.ErrorMessage, but the national encodings are already lost in it.

What can be done in this situation?


Solution

  • When TIdHTTP raises the EIdHTTPProtocolException, it takes the response's charset into account when populating the ErrorMessage, so it should not be losing content. But as you noted, there is no direct way to access the original bytes. There is an open ticket in Indy's GitHub repo about that:

    #388: Update EIdHTTPProtocolException to store original stream content

    A different solution is to enable the hoNoProtocolErrorException flag in the TIdHTTP.HTTPOptions property to disable the exception from being raised. By default, the error body will be discarded, so also enable the hoWantProtocolErrorContent flag so your TStream will receive the raw bytes of the error body. You can then check the IdHTTP.ResponseCode after IdHTTP.Post() returns, and parse the TStream data accordingly.


    On a side note: you are receiving the response body using a TStringStream with no encoding specified, so it will use TEncoding.Default, which is the user's ANSI locale on Windows, and UTF-8 on Posix. You can't change the stream's encoding after construction, so if the response body does not match the stream's encoding then you will corrupt the data when reading the TStringStream.DataString property.

    If you use the overload of TIdHTTP.Post() that returns a string, it will take the response's charset into account when decoding the response body's bytes into a string.