-
Для настройки кэширования, решил использовать параметр из HTTP запроса IfModifiedSince. Т.е. на сколько я понял, то в этом поле передается дата файла хранящегося в кэше браузера клиента. CGI-приложение, проверяет эту дату и дату файла хранящегося на сервере, и если даты не поменялись, то возвращает статус 304, и пустой поток. Периодически, при обращении к этому полю объекта Request Класса TWebRequest, приложение вылетает с ошибкой 500 Internal server error HTTP запрос выглядит вполне корректно:
Accept */*
Accept-Encoding gzip, deflate
Accept-Language ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Cache-Control max-age=0
Connection keep-alive
Cookie nut=7b8e525fd6d014a036822efa1e868dcc
Host test.tst
If-Modified-Since Mon, 13 Mar 2017 16:00:46 GMT HTTP заголовок ответа:
Connection close
Content
Content-Length 129
Content-Type text/html; charset=windows-1251
Date Thu, 16 Mar 2017 07:29:50 GMT
А вот содержимое ответа:
<html><body><h1>Internal Application Error</h1>
<p>'Tue' is not a valid integer value
<p><hr width="100%"></body></html>
Сделал проверку, непосредственно в теле процедуры ответа:
procedure TCGI.WebModule1indexAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var st:TstringList;
begin
st:=TStringList.Create;
st.LoadFromFile(ExtractFileDir(ParamStr(0))+'\111.log');
try
st.Append(request.Query+' : '+DateTimeToStr(Request.IfModifiedSince));
except
on e : Exception do
st.Append(request.Query+' : exception:'+e.Message);
end;
st.SaveToFile(ExtractFileDir(ParamStr(0))+'\111.log');
st.Free;
....
Содержимое лога вот такое:
what=/index.html&id=200&log=1 : 29.12.1899
what=/css/struct.css : exception:'Tue' is not a valid integer value
what=/image/img.png : exception:'Mon' is not a valid integer value
Т.е. поле IfModifiedSince, в TwebRequest, работает не правильно, не может преобразовать строку типа "Mon, 13 Mar 2017 16:00:46 GMT" в тип TDateTime Тогда вопрос: Как вытащить заголовок HTTP запроса? Я сам распарсю это поле, но как его получить?
-
попробовал вытащить в виде строки значение этого поля
Request.GetFieldByName('If-Modified-Since')
возвращает всегда пустую строку, несмотря на то что в заголовке HTTP запроса этот параметр есть!!! Его видно в Firebug!! Попробовал получить значения других полей, нуу мало ли может не работает, класс то абстрактный. Значения полей "Connection", "Refer" и остальные возвращает нормально!
-
В Delphi есть отладчик.
-
Request.Headers[]
-
> Плохиш © (16.03.17 13:55) [2] > > В Delphi есть отладчик.
Отладчик есть, но к чему его аттачить? > Плохиш © (16.03.17 14:06) [3] > > Request.Headers[]
"мимо", нет такого свойства. Вот описание этого класса:
TWebRequest = class(TObject)
private
FContentParser: TAbstractContentParser;
FMethodType: TMethodType;
FContentFields,
FCookieFields,
FQueryFields: TStrings;
function GetContentParser: TAbstractContentParser;
function GetContentFields: TStrings;
function GetCookieFields: TStrings;
function GetQueryFields: TStrings;
function GetFiles: TAbstractWebRequestFiles;
protected
function GetStringVariable(Index: Integer): string; virtual; abstract;
function GetDateVariable(Index: Integer): TDateTime; virtual; abstract;
function GetIntegerVariable(Index: Integer): Integer; virtual; abstract;
function GetInternalPathInfo: string; virtual;
function GetInternalScriptName: string; virtual;
procedure UpdateMethodType;
public
constructor Create;
destructor Destroy; override;
function ReadClient(var Buffer; Count: Integer): Integer; virtual; abstract;
function ReadString(Count: Integer): string; virtual; abstract;
function TranslateURI(const URI: string): string; virtual; abstract;
function WriteClient(var Buffer; Count: Integer): Integer; virtual; abstract;
function WriteString(const AString: string): Boolean; virtual; abstract;
function WriteHeaders(StatusCode: Integer; const ReasonString, Headers: string): Boolean; virtual; abstract;
procedure ExtractFields(Separators, WhiteSpace: TSysCharSet;
Content: PChar; Strings: TStrings);
procedure ExtractContentFields(Strings: TStrings);
procedure ExtractCookieFields(Strings: TStrings);
procedure ExtractQueryFields(Strings: TStrings);
function GetFieldByName(const Name: string): string; virtual; abstract;
property MethodType: TMethodType read FMethodType;
property ContentParser: TAbstractContentParser read GetContentParser;
property ContentFields: TStrings read GetContentFields;
property CookieFields: TStrings read GetCookieFields;
property QueryFields: TStrings read GetQueryFields;
property Method: string index 0 read GetStringVariable;
property ProtocolVersion: string index 1 read GetStringVariable;
property URL: string index 2 read GetStringVariable;
property Query: string index 3 read GetStringVariable;
property PathInfo: string index 4 read GetStringVariable;
property PathTranslated: string index 5 read GetStringVariable;
property Authorization: string index 28 read GetStringVariable;
property CacheControl: string index 6 read GetStringVariable;
property Cookie: string index 27 read GetStringVariable;
property Date: TDateTime index 7 read GetDateVariable;
property Accept: string index 8 read GetStringVariable;
property From: string index 9 read GetStringVariable;
property Host: string index 10 read GetStringVariable;
property IfModifiedSince: TDateTime index 11 read GetDateVariable;
property Referer: string index 12 read GetStringVariable;
property UserAgent: string index 13 read GetStringVariable;
property ContentEncoding: string index 14 read GetStringVariable;
property ContentType: string index 15 read GetStringVariable;
property ContentLength: Integer index 16 read GetIntegerVariable;
property ContentVersion: string index 17 read GetStringVariable;
property Content: string index 25 read GetStringVariable;
property Connection: string index 26 read GetStringVariable;
property DerivedFrom: string index 18 read GetStringVariable;
property Expires: TDateTime index 19 read GetDateVariable;
property Title: string index 20 read GetStringVariable;
property RemoteAddr: string index 21 read GetStringVariable;
property RemoteHost: string index 22 read GetStringVariable;
property ScriptName: string index 23 read GetStringVariable;
property ServerPort: Integer index 24 read GetIntegerVariable;
property InternalPathInfo: string read GetInternalPathInfo;
property InternalScriptName: string read GetInternalScriptName;
property Files: TAbstractWebRequestFiles read GetFiles;
свойство IfModifiedSince: TDateTime index 11 read GetDateVariable; Как я писал выше или выдает полную чушь или exception
-
Можно заставить браузер отправлять If-None-Match, если установить в ответе Etag. Но как видите, в классе не предусмотрена обработка этого поля и добраться можно к нему только прочитав весь заголовок и распарсив его. Т.е. вопрос опять - как получить HTTP заголовок запроса?
Пробовал читать StdIn, т.к. он там должен быть, но ... пусто.
-
> Отладчик есть, но к чему его аттачить?
w3wp.exe
-
> Плохиш © (16.03.17 16:46) [6] > > > > Отладчик есть, но к чему его аттачить? > > w3wp.exe
А с чего Вы взяли что я использую IIS? И еще, как Вы собираетесь трассировать абстрактно виртуальный метод?
function GetDateVariable(Index: Integer): TDateTime; virtual; abstract;
Точку останова куда прикажете ставить? Если на вызов метода, то дебагер пролетит его, без захода, или использовать дизассемблер? Тут все проще, надо просто получить заголовок до его парсинга TWebApplication, но вот как? Я пробовал еще до инициализации стырить StdIn - фугшки, пусто там. Сделал приложение спецально, простое консольное и подусунул апачу как CGI, приложение вылетает с ошибкой. ИМХО дело в апаче, который както-то не так передает поток ввода, своему CGI приложению. Но исходя из того что TWebApplication все-таки получает какой-то заголовок (часть параметров то отображается нормально), следовательно как-то его получить можно. КАК?!
-
> ford © (17.03.17 09:42) [7] > А с чего Вы взяли что я использую IIS?
Да мне в общем-то пофигу.
> И еще, как Вы собираетесь трассировать абстрактно виртуальный > метод?
При работе программы нет работающих абстрактных методов.
PS. Проблема -то у вас.
-
> Плохиш © (17.03.17 11:39) [8] > > > > ford © (17.03.17 09:42) [7] > > А с чего Вы взяли что я использую IIS? > > Да мне в общем-то пофигу.
То что Вам пофигу, оно понятно из ваших ответов (лишь бы чего написать). А вот ответ на ту заморочку подсказали на cyberforum.ru, там видимо люди которым не "пофигу": Может кому пригодится, оказывается борланд несколько по другому назвал эти поля. Они описаны в модуле CGIHTTP.pas
CGIServerVariables: array[0..28] of string = (
'REQUEST_METHOD',
'SERVER_PROTOCOL',
'URL',
'QUERY_STRING',
'PATH_INFO',
'PATH_TRANSLATED',
'HTTP_CACHE_CONTROL',
'HTTP_DATE',
'HTTP_ACCEPT',
'HTTP_FROM',
'HTTP_HOST',
'HTTP_IF_MODIFIED_SINCE',
'HTTP_REFERER',
'HTTP_USER_AGENT',
'HTTP_CONTENT_ENCODING',
'HTTP_CONTENT_TYPE',
'HTTP_CONTENT_LENGTH',
'HTTP_CONTENT_VERSION',
'HTTP_DERIVED_FROM',
'HTTP_EXPIRES',
'HTTP_TITLE',
'REMOTE_ADDR',
'REMOTE_HOST',
'SCRIPT_NAME',
'SERVER_PORT',
'',
'HTTP_CONNECTION',
'HTTP_COOKIE',
'HTTP_AUTHORIZATION');
т.е. надо запрашивать не IF-MODIFIED-SINCE (что логично, т.к. в заголовке поле называется именно так), а так HTTP_IF_MODIFIED_SINCE. Тогда Request.GetFieldByName('IF-MODIFIED-SINCE') возвращает строку со значением этого поля. Нууу а дальше преобразовывай не хочу :)
-
описался, т.е. конечно: Request.GetFieldByName('HTTP_IF_MODIFIED_SINCE') вернет строку со значением поля IF-MODIFIED-SINCE из заголовка.
-
function TCGIRequest.GetFieldByName(const Name: string): string;
function AdjustHTTP(const Name: string): string;
const
SHttp = 'HTTP_';
begin
if Pos(SHttp, Name) = 1 then
Result := Copy(Name, 6, MaxInt)
else
Result := SHttp + Name;
end;
begin
Result := GetEnvironmentVariable(Name);
if Result = '' then
Result := GetEnvironmentVariable(AdjustHTTP(Name));
end; или function TCGIRequest.GetFieldByName(const Name: AnsiString): AnsiString;
function AdjustHTTP(const Name: AnsiString): AnsiString;
const
SHttp = AnsiString('HTTP_');
begin
if AnsiStrPos(PAnsiChar(SHttp), PAnsiChar(Name)) = PAnsiChar(Name) then
Result := Copy(Name, 6, MaxInt)
else
Result := SHttp + Name;
end;
function GetCGIEnvironmentVariable(const Name: AnsiString): AnsiString;
const
BufSize = 1024;
var
Len: Integer;
Buffer: array[0..BufSize - 1] of AnsiChar;
begin
Result := '';
Len := GetEnvironmentVariableA(PAnsiChar(Name), @Buffer, BufSize);
if Len < BufSize then
SetString(Result, PAnsiChar(@Buffer), Len)
else
begin
SetLength(Result, Len - 1);
GetEnvironmentVariableA(PAnsiChar(Name), PAnsiChar(Result), Len);
end;
end;
begin
Result := GetCGIEnvironmentVariable(Name);
if Result = '' then
Result := GetCGIEnvironmentVariable(AdjustHTTP(Name));
end; Из кода видно, что без разницы, Request.GetFieldByName('HTTP_IF_MODIFIED_SINCE') или Request.GetFieldByName('IF_MODIFIED_SINCE')
|