Заголовок Indy, последний измененный - недопустимый аргумент в кодировке даты - PullRequest
0 голосов
/ 26 октября 2018

Я использую TIdHTTP от Indy.Я отправляю 2 разных запроса, один заголовок содержит тег «Last-Modified», а другой - нет.Заголовок с тегом выдает исключение:

'Invalid Argument to date encode'

Я уже сталкивался с этим вопросом, где Реми Лебо сказал, что TIdHttp теперь может анализировать ISO8601даты, но это не похоже на работу для меня.Как вы можете видеть ниже, я ничего не делаю с компонентом, кроме изменения UserAgent.Я что-то пропустил?

url :=  'https://api.priceapi.com/v2/jobs/' + JobID+ '?token=' + Token;
http := TIdHTTP.Create(nil);
http.Request.UserAgent := 'XXXXX'; //Some UserAgent
try
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  try
    http.IOHandler := ssl;
    try
      jo := TJsonObject.ParseJSONValue(http.get(url)) as TJSONObject;
      result := jo.GetValue('status').Value;
    finally
    end;
  finally
    ssl.Free;
  end;
finally
  http.Free;
end;

Заголовок с последним изменением:

Cache-Control: no-cache
Content-Disposition: attachment; 
filename="20181025145103_google_shopping_de_5bd1d857bbd7e520c12841d7.json"
Content-Transfer-Encoding: binary
Content-Type: application/json
Last-Modified: 2018-10-25 14:51:23 +0000
Vary: Origin
X-Accel-Buffering: no
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: b05aa8fe-7ea9-4152-8470-a75f9816549f
X-Runtime: 0.099212
X-XSS-Protection: 1; mode=block
transfer-encoding: chunked
Connection: keep-alive

Заголовок без последнего изменения:

Cache-Control: max-age=0, private, must-revalidate', nil
Content-Type: application/json; charset=utf-8', nil
ETag: W/"43c4a8865a5ebe565f3920779a962e93"', nil
Vary: Origin', nil
X-Content-Type-Options: nosniff', nil
X-Frame-Options: SAMEORIGIN', nil
X-Request-Id: 344ac82e-0d14-4838-ae7e-627c79b78edc', nil
X-Runtime: 0.062357', nil
X-XSS-Protection: 1; mode=block', nil
Content-Length: 157', nil
Connection: Close', nil

StackTrace:

:744717d2 KERNELBASE.RaiseException + 0x62
HIWBase.System.SysUtils.ConvertError($3B68860)
HIWBase.System.SysUtils.EncodeDate(???,???,???)
HIWBase.IdGlobalProtocols.RawStrInternetToDateTime('07:53:37 +0000',0)
HIWBase.IdGlobalProtocols.GMTToLocalDateTime('07:53:37 +0000')
HIWBase.IdHTTPHeaderInfo.TIdEntityHeaderInfo.ProcessHeaders
HIWBase.IdHTTPHeaderInfo.TIdResponseHeaderInfo.ProcessHeaders
HIWBase.IdHTTP.TIdHTTPProtocol.RetrieveHeaders(255)
HIWBase.IdHTTP.TIdCustomHTTP.DoRequest('GET','My URL',nil,$ADF09E0,(...))
HIWBase.IdHTTP.TIdCustomHTTP.Get('My URL',$ADF09E0,(...))
HIWBase.IdHTTP.TIdCustomHTTP.Get('My URL',(...))
HIWBase.IdHTTP.TIdCustomHTTP.Get('My URL')

Я на Indy версии 10.6.2.5311

1 Ответ

0 голосов
/ 26 октября 2018

Заголовок Last-Modified определен в RFC 2616, раздел 14.29 1 как:

Last-Modified  = "Last-Modified" ":" HTTP-date

1: Эквивалентное определение содержится в RFC 7232, раздел 2.2 .

HTTP-date определено в RFC 2616, раздел 3.3 2 как:

HTTP-date    = rfc1123-date | rfc850-date | asctime-date
rfc1123-date = wkday "," SP date1 SP time SP "GMT"
rfc850-date  = weekday "," SP date2 SP time SP "GMT"
asctime-date = wkday SP date3 SP time SP 4DIGIT
date1        = 2DIGIT SP month SP 4DIGIT
               ; day month year (e.g., 02 Jun 1982)
date2        = 2DIGIT "-" month "-" 2DIGIT
               ; day-month-year (e.g., 02-Jun-82)
date3        = month SP ( 2DIGIT | ( SP 1DIGIT ))
               ; month day (e.g., Jun  2)
time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT
               ; 00:00:00 - 23:59:59
wkday        = "Mon" | "Tue" | "Wed"
             | "Thu" | "Fri" | "Sat" | "Sun"
weekday      = "Monday" | "Tuesday" | "Wednesday"
             | "Thursday" | "Friday" | "Saturday" | "Sunday"
month        = "Jan" | "Feb" | "Mar" | "Apr"
             | "May" | "Jun" | "Jul" | "Aug"
             | "Sep" | "Oct" | "Nov" | "Dec"

2: Эквивалентные определения приведены в RFC 7231, раздел 7.1.1.1 .

Показанное вами Last-Modified значение не соответствует ни одному из форматов, разрешенных HTTP.

TIdHTTP использует функцию Indy GMTToLocalDateTime() для анализа заголовка Last-ModifiedDate и Expires). Эта функция является общей для компонентов HTTP, IMAP, NNTP и электронной почты, поэтому она более гибкая в 1038 * форматах даты / времени, которые она поддерживает. Например, он анализирует ISO 8601, который, как вы утверждаете, равен Last-Modified. Однако указанное вами значение также не соответствует стандарту ISO 8601. Если бы это было так, это выглядело бы так:

Last-Modified: 2018-10-26T08:37:01+00:00

Что еще хуже, согласно предоставленной вами трассировке стека, GMTToLocalDateTime() вызывается без какой-либо части даты вообще:

HIWBase.IdGlobalProtocols.GMTToLocalDateTime('07:53:37 +0000')

Способ only , который может произойти в TIdHTTP, заключается в том, что HTTP-сервер отправляет заголовок Last-Modified (или Date или Expires) с этим точным значением, которое также не является соответствует стандартам HTTP или ISO 8601 и не обрабатывается как есть GMTToLocalDateTime().

Короче говоря, API, который вы запрашиваете, отправляет недопустимый формат даты / времени , который TIdHTTP не поддерживает синтаксический анализ (что иронично, потому что основной веб-сайт https://www.priceapi.com отправляет правильно отформатированный HTTP строки даты / времени). Вам следует связаться с администратором сайта и сообщить, что их сервер API нарушает стандарты протокола HTTP в этом отношении.

При этом GMTToLocalDateTime() НЕ вызывает исключение 'Invalid Argument to date encode', когда встречается неверно сформированная строка даты / времени. Вместо этого он возвращает TDateTime из 0.0. только способ, которым вы могли видеть это исключение, если вы выполняете свой код внутри отладчика. Когда GMTToLocalDateTime() задана неверно сформированная строка даты / времени, возможно, что он может извлечь числовые компоненты, которые он считает действительными, но затем потерпит неудачу, когда попытается закодировать окончательный TDateTime с ними. Исключение, которое вы видите, исходит из функции EncodeDate() RTL, когда ему задается неверный месяц / день / год в качестве ввода. Но GMTToLocalDateTime() ловит это исключение внутри. Ваш код никогда не увидит его во время выполнения, его увидит только отладчик.

...