REST request failed: Error receiving data: (12152) The serve

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

REST request failed: Error receiving data: (12152) The serve

Postby Ahmed Sayed » Sun Jan 20, 2019 4:29 pm

Hi, I am facing a problem when I try to stress test a server using TIdHttpServer I am creating to be fast
I am using TRESTClient, and request components to create the test on the client side.

I use both the client tester and server on the same machine

The test is based on creating like 20,000 threads with each one contains an instance of these component and execute a simple GET request from the server. The server only returns a one line of text as response.

1 or 2 of the 20,000 requests get the error exception mentioned in the subject

"REST request failed: Error receiving data: (12152) The server returned an invalid or unrecognized response"

Now I don't know the cause of this error and how can debug this issue because when
run the serve in debug mode the server become very slow and the exception is
never raised in the first place.

Any help will be appreciated
Thanks in Advance

Ahmed Sayed
Ahmed Sayed
Active Poster
Active Poster
 
Posts: 24
Joined: Thu Nov 08, 2018 4:12 pm

Re: REST request failed: Error receiving data: (12152) The s

Postby rlebeau » Mon Jan 21, 2019 1:38 pm

Error code 12152 comes from the WinInet API. It is ERROR_HTTP_INVALID_SERVER_RESPONSE ("The server response could not be parsed"). There is no way to answer this without seeing your actual code, or at least the actual HTTP response that is failing to be parsed.

But, you are really taxing the system trying to create that many concurrent threads. Remember, Indy uses a 1-thread-per-socket model in its servers, so you are not just creating 20000 client threads, you are also creating 20000 server threads. That is a LOT of threads to have running on one machine at a time.

If I had to guess, the 12152 error is probably due to server side failures causing connections to be closed prematurely before the full response has been sent. But it is hard to diagnose for sure with the limited information you have provided.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1584
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: REST request failed: Error receiving data: (12152) The s

Postby Ahmed Sayed » Tue Jan 22, 2019 5:53 am

Here is the code:

Client code:
Code: Select all
void TMain::Execute(String aFramework, String ID)
{
if (aFramework == "REST")
   Thread(FuncBind( &TMain::RESTExecute, this,ID));

if (aFramework == "Net")
   Thread(FuncBind( &TMain::NetExecute, this,ID));

if (aFramework == "Indy")
   Thread(FuncBind( &TMain::IndyExecute, this, ID));
}
//---------------------------------------------------------------------------
void TMain::RESTExecute(String ID)
{
if (Headers->Strings->Text.Trim() == "=")
   Headers->Strings->Clear();

unique_ptr<TRESTClient> RESTClient(new TRESTClient(nullptr));
unique_ptr<TRESTRequest> RESTRequest(new TRESTRequest(nullptr));
unique_ptr<TRESTResponse> RESTResponse(new TRESTResponse(nullptr));

try
   {
   RESTClient->HandleRedirects = false;
   RESTClient->BaseURL = URL->Text;
   RESTClient->RaiseExceptionOn500 = true;
   RESTClient->SynchronizedEvents = false;
   RESTRequest->HandleRedirects = false;
   RESTRequest->Client = RESTClient.get();
   RESTRequest->Response = RESTResponse.get();
   RESTRequest->Timeout = TimeOut->Value;

   RESTRequest->AddParameter("Connection","close", pkHTTPHEADER);

   if (Headers->Strings->Count > 0)
      {
      for (int i = 0; i < Headers->Strings->Count; i++)
         {
         RESTRequest->AddParameter(Headers->Strings->Names[i],Headers->Strings->ValueFromIndex[i], pkHTTPHEADER);
         }
      }

   RESTRequest->Method = (TRESTRequestMethod)GetEnumValue(__delphirtti(TRESTRequestMethod), "rm" + Method->Text);

   RESTRequest->Execute();

   if (RESTResponse->StatusCode == 200)
      {
//      DoAddCount(2);
      SuccessCount++;
      }
   else
      {
//      DoAddCount(3);
      ErrorsCount++;
      ShowError(ID, String(RESTResponse->StatusCode) + ": " + RESTResponse->StatusText + "\n" + RESTResponse->Content);
      }
   }
catch (const Exception &E)
   {
//   DoAddCount(4);
   ExceptionsCount++;
   unique_ptr<TStringList> error(new TStringList);
   error->TrailingLineBreak = false;
   error->Add("Exception: " + E.Message);
   error->Add("URL: " + RESTResponse->FullRequestURI);
   error->Add("Status: " + String(RESTResponse->StatusCode) + " - " + RESTResponse->StatusText);
   error->Add("Headers: ");
   error->Add(RESTResponse->Headers->Text);
   error->Add("");
   error->Add("Content: ");
   error->Add(RESTResponse->Content);
   error->Add("--------------------");

   ShowError(ID,error->Text);
   }
}
//---------------------------------------------------------------------------
void TMain::NetExecute(String ID)
{
if (Headers->Strings->Text.Trim() == "=")
   Headers->Strings->Clear();

unique_ptr<TNetHTTPClient> HTTPClient(new TNetHTTPClient(nullptr));

String Response;

try
   {
   HTTPClient->CustomHeaders["Connection"] = "close";
   HTTPClient->HandleRedirects = false;
   HTTPClient->ConnectionTimeout = TimeOut->Value;
   HTTPClient->ResponseTimeout = TimeOut->Value;

   if (Headers->Strings->Count > 0)
      {
      for (int i = 0; i < Headers->Strings->Count; i++)
         HTTPClient->CustomHeaders[Headers->Strings->Names[i]] = Headers->Strings->ValueFromIndex[i];
      }

   TStopwatch Timer = TStopwatch::Create();
   Timer.Reset();
   Timer.Start();

   _di_IHTTPResponse AResponse = HTTPClient->Execute(Method->Text, URL->Text);

   Timer.Stop();
   String Timing = Timer.ElapsedMilliseconds / 1000.0;

   Response = AResponse->ContentAsString();

   if (AResponse->StatusCode == 200)
      DoAddCount(2);
   else
      {
      Response = AResponse->ContentAsString();
      DoAddCount(3);
      ShowError(ID, String(AResponse->StatusCode) + ": " + AResponse->StatusText + " - " + Timing + "\n" + Response);
      }
   }
catch (Exception &E)
   {
   DoAddCount(4);
   ShowError(ID,"Exception " + E.Message + " - " + Response);
   }
}
//---------------------------------------------------------------------------
void TMain::IndyExecute(String ID)
{
if (Headers->Strings->Text.Trim() == "=")
   Headers->Strings->Clear();

unique_ptr<TIdHTTP> IdHTTP(new TIdHTTP(nullptr));

String Response;
try
   {
   IdHTTP->ConnectTimeout = TimeOut->Value;
   IdHTTP->ReadTimeout = TimeOut->Value;

   IdHTTP->Request->Connection = "close";
   if (Headers->Strings->Count > 0)
      {
      for (int i = 0; i < Headers->Strings->Count; i++)
         {
         IdHTTP->Request->RawHeaders->Values[Headers->Strings->Names[i]] = Headers->Strings->ValueFromIndex[i];
         }
      }

   TStopwatch Timer = TStopwatch::Create();
   Timer.Reset();
   Timer.Start();

   if (Method->Text == "GET")
      Response = IdHTTP->Get(URL->Text);

   if (Method->Text == "POST")
      Response = IdHTTP->Post(URL->Text,"");

   if (Method->Text == "PUT")
      Response = IdHTTP->Put(URL->Text, nullptr);

   if (Method->Text == "DELETE")
      Response = IdHTTP->Delete(URL->Text);

   Timer.Stop();
   String Timing = Timer.ElapsedMilliseconds / 1000.0;


   if (IdHTTP->ResponseCode == 200)
      DoAddCount(2);
   else
      {
      DoAddCount(3);
      ShowError(ID, String(IdHTTP->ResponseCode) + ": " + IdHTTP->ResponseText + " - " + Timing + "\n" + Response);
      }
   }
catch (const Exception &E)
   {
   DoAddCount(4);
   ShowError(ID,"Exception " + E.Message + " - " + Response);
   }
}
//---------------------------------------------------------------------------
void TMain::DoRunTest()
{
for (int i = 0; i < RequestsCount->Value; i++)
   {
   try
      {
      Execute(Framework->Text,i+1);
      DoAddCount(1);
      }
   catch (const Exception &E)
      {
      DoAddCount(4);
      ShowError(i+1,"Client Exception " + E.Message);
      }

   if (Interval->Value > 0)
      Sleep(Interval->Value);

   if (Stopped)
        break;
   }
Stopped = true;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void TMain::RunTest()
{
Results->Clear();

ResetCounter();

Thread(FuncBind( &TMain::DoRunTest, this));
}
//---------------------------------------------------------------------------


Server Side:
Code: Select all
void __fastcall TCloudDM::ServerCommandGet(TIdContext *AContext, TIdHTTPRequestInfo *ARequestInfo,
        TIdHTTPResponseInfo *AResponseInfo)
{
if (ARequestInfo->URI == "/")
   AResponseInfo->ContentText = "Cloud BaaS Server Working " + ReplaceStr(Version.UpperCase(), "/","");
}
//---------------------------------------------------------------------------
Ahmed Sayed
Active Poster
Active Poster
 
Posts: 24
Joined: Thu Nov 08, 2018 4:12 pm


Return to Technical

Who is online

Users browsing this forum: No registered users and 16 guests

cron