-
Доброго времени суток, уважаемые.
Бьюсь вторые сутки над "выдачей" информации о файле перед скачиванием через "испеченный" мною на основе IdHTTPProxyServer прокси сервере. Т.е. при скачивании файла через свой прокси, например, с помощью IE, должно сначала появиться окно, в котором мне будет хотя бы известен размер файла, после чего, в случае моего согласия, файл скачивается. Так вот дело в том, что мне не известен размер файла, пока сам этот файл не скачается полностью (например, в IE окошко сохранения файла появляется после полного скачивания этого файла), хотя без прокси все нормально. В самом прокси я передаю в заголовке ответа Content-Length, после чего само тело файла. Кто-нибудь знает, как устранить эту проблемку? ЗЫ: извиняюсь, если что-то коряво написал - у меня уже ночь, голова не соображает :)
-
> Т.е. при скачивании файла через свой прокси, например, с > помощью IE, должно сначала появиться окно, в котором мне > будет хотя бы известен размер файла, после чего, в случае > моего согласия, файл скачивается.
Тут дело не в прокси-сервере, а в клиенте. Т.е. при получении ответа с кодом 200 (и с указанием размера в заголовках), клиент должен показывать табличку :) Прокси-сервер тут ни причем. Хотя табличку может показывать и он, но тогда это не будет иметь отношения к клиенту, собственно скачивающему этот файл. Да и не дело это для сервера - таблички показывать :)
-
(например, в IE окошко сохранения файла появляется после полного скачивания этого файла),
ну это ты сам так написал свой прокси.
-
в принципе есть запрос HEAD, предназначенный для получения информации о ресурсе. Прокси может слать сначала его, показывать табличку :) (хотя и не его это дело), а потом уже, в зависимости от реакции пользователя, слать или не слать GET
-
да у него в дизайне кода проблема. получив ссылку от браузера он пока его на прокси не выкачает, к передаче обратно в браузер не переходит.
-
этож какие таймауты надо разрешать в браузере чтобы через такой замечательный прокси качать что-нибуть большее чем testgirl.jpg в 100 кб
-
> Поросенок Винни-Пух © (02.07.08 12:58) [4] > > да у него в дизайне кода проблема. > получив ссылку от браузера он пока его на прокси не выкачает, > к передаче обратно в браузер не переходит.
Вообще IdHTTPProxyServer читает требуемые данные в Stream с запрашиваемого сервера, затем отсылает это браузеру. Но заголовок ответа (включая Content-Length) отсылается серверу до сбрасывания данных в/из stream:
var
LClient: TIdTCPClient;
LDocument: string;
LHeaders: TIdHeaderList;
LRemoteHeaders: TIdHeaderList;
LURI: TIdURI;
LPageSize: Integer;
begin
ASender.PerformReply := false;
LHeaders := TIdHeaderList.Create; try
ASender.Context.Connection.IOHandler.Capture(LHeaders, '');
LClient := TIdTCPClient.Create(nil); try
LURI := TIdURI.Create(ASender.Params.Strings[0]); try
LClient.Port := Sys.StrToInt(LURI.Port, 80);
LClient.Host := LURI.Host;
LDocument := LURI.Path + LURI.Document + LURI.Params;
finally Sys.FreeAndNil(LURI); end;
LClient.Connect; try
LClient.IOHandler.WriteLn('GET ' + LDocument + ' HTTP/1.0');
LClient.IOHandler.Write(LHeaders);
LClient.IOHandler.WriteLn('');
LRemoteHeaders := TIdHeaderList.Create; try
LClient.IOHandler.Capture(LRemoteHeaders, '');
ASender.Context.Connection.IOHandler.Write(LRemoteHeaders);
ASender.Context.Connection.IOHandler.WriteLn('');
LPageSize := Sys.StrToInt(LRemoteHeaders.Values['Content-Length'], -1) ;
TransferData(LClient, ASender.Context.Connection, LDocument, LPageSize, LRemoteHeaders);
finally Sys.FreeAndNil(LRemoteHeaders); end;
finally LClient.Disconnect; end;
finally Sys.FreeAndNil(LClient); end;
finally Sys.FreeAndNil(LHeaders); end; > umbra © (02.07.08 12:35) [3] > > в принципе есть запрос HEAD, предназначенный для получения > информации о ресурсе. Прокси может слать сначала его, показывать > табличку :) (хотя и не его это дело), а потом уже, в зависимости > от реакции пользователя, слать или не слать GET
Почему то браузер не просит информацию о ресурсе HEAD`ом. Я даже сам настоятельно ему отправлял эту информацию, не спрашивая у него разрешения - не помогло :)
-
> Почему то браузер не просит информацию о ресурсе HEAD`ом
а чего он должен ее просить? не для этого его делали :) Надо писат плагин/надстройку. Непонятно только, причем здесь прокси.
-
Бррр... И все же, когда мы скачиваем файл без прокси, нам известно какого он размера (см. окошко в браузере). А известно браузеру размер файла из-за полученного Content-Length. Прокси тоже сначала отправляет заголовок с Content-Length, но почему-то браузер не реагирует :/ Все это работает и без HEAD.
-
значит прокси кривой. Как у вас происходит отдача браузеру? вы видно и правда сначала все на прокси закачиваете, хотя хттп прокси должен создавать туннель, покоторому все идет без задержек.
-
И все же, когда мы скачиваем файл без прокси, нам известно какого он размера
И что же здесь странного? То что контент ленс не только при подаче head отдается?
-
Вообще IdHTTPProxyServer читает требуемые данные в Stream с запрашиваемого сервера, затем отсылает это браузеру
ну как я и говорил. пока твой прокси не всосет четырехгиговый dvd рип целиком, браузер ни байта от него не получит.
-
> значит прокси кривой. Как у вас происходит отдача браузеру? > вы видно и правда сначала все на прокси закачиваете, хотя > хттп прокси должен создавать туннель, покоторому все идет > без задержек.
Само тело ресурса закачивается на прокси, после чего отдается клиенту: ...
var
LStream: TIdStream;
begin
LStream := TIdMemoryStream.Create; try
ASrc.IOHandler.ReadStream(LStream, ASize, ASize = -1);
LStream.Position := 0;
DoHTTPDocument(ADocument, LStream, AHeaders); ADest.IOHandler.Write(LStream);
finally Sys.FreeAndNil(LStream); end;
... Собственно, все это - стандартный код IdHTTPProxyServer (Indy 10), исходники которого есть в самом Delphi (2006 и т.д.). Сам заголовок отдается раньше тела запрашиваемого ресурса (см. пост kernel © (02.07.08 13:19) [6]).
-
> Поросенок Винни-Пух © (02.07.08 15:43) [11] > ну как я и говорил.пока твой прокси не всосет четырехгиговый > dvd рип целиком, браузер ни байта от него не получит.
Как же тогда браузер узнает размер файла, даже без прокси?
-
Как же тогда браузер узнает размер файла, даже без прокси?
из заголовка ответа конечно же.
-
ты наверное думаешь, что ие действует так: посылает гет или пост, читает заголовок, останавливает закачку, показывает окно с кнопкой отмена и пока не нажмешь ок не начинает качать сам контент.
только браузер делает не так да и кнопки "ок" там нет. предположу, что получив заголовок и начав качать само тело файла, он через некоторое время асинхронно показывает окошко, в котором можно прекратить закачку.
-
а твой волшебный прокси отдает только загловок, потом забивает на браузер и занимается высасыванием файла.
-
> а твой волшебный прокси отдает только загловок, потом забивает > на браузер и занимается высасыванием файла
да, TIdHTTPProxyServer сделан криво. Пока он не закачает весь ресурс (причем по умолчанию - в память :)), он ничего не отдает. А поскольку сокеты блокирующие, то и события никакие произойти не могут, пока весь ресурс не закачается. Его надо рихтовать и рихтовать, чтобы до ума довести :)
-
там и события особо никакие не нужны. достаточно иметь два вложенных цикла чтения с сервера и отдачи браузеру. ну и читать/отдавать конечно блочно, а не в стрим.
-
> Как же тогда браузер узнает размер файла, даже без прокси?
Вопрос не правильный. А вот правильный
Как же тогда браузер узнает размер файла, без моего прокси?
-
> Поросенок Винни-Пух © (02.07.08 16:27) [18] > ... > достаточно иметь два вложенных цикла чтения с сервера и > отдачи браузеру.
А почему именно два цикла? В общем, сделал такое "по-блочное" чтение: var
LStream: TIdStream;
StreamBuf: TIdBytes;
DocSize: Integer;
begin
LStream := TIdMemoryStream.Create; try
ReqBlock := not RequestAllow(reqUrl);
DocSize:=0;
while (ASrc.IOHandler.Connected) and
(ADest.IOHandler.Connected) do
begin
if ASrc.IOHandler.Readable then
begin
ASrc.IOHandler.ReadBytes(StreamBuf, -1, false);
ADest.IOHandler.WriteDirect(StreamBuf);
DocSize:=DocSize + SizeOf(StreamBuf);
end;
end;
end; Это единственное, что у меня почти заработало. Почему-то такой код работает через раз :( Складывается впечатление, что происходит где-то в цикле подвисание. Иногда страницы вообще не отдаются :(
-
Кто-нибудь может подсказать, как по-блочно читать? :)
-
> Кто-нибудь может подсказать, как по-блочно читать?
поскольку сокеты блокирующие, то поблочно читать можно только многократными запросами диапазона байтов ресурса. Для файлов это нормально, для страничек - нет. Лучший, по-моему, выход - создать общий ресурс (типа временный файл) + два потока на клиента у прокси. Один читает ответ на запрос и пишет в файл, другой - читает записанное и шлет его клиенту. Но тут надо уже синхронизировать эти потоки так, чтобы тот, который отдает клиенту, не читал все правильно.
-
поскольку сокеты блокирующие, то поблочно читать можно только многократными запросами диапазона байтов ресурса. Для файлов это нормально, для страничек - нет.
не страницу поблочно тянуть, а из тсп соединения читать блоками
-
> а из тсп соединения читать блоками
так оно ж потоковое. тогда всегда есть опасность, что сервер, с которого тянут может обидеться и отключиться :) Еще вариант - скачать инди поновее, потому как тот, для которого есть автоматический инсталлятор имеет версию 10.1.5, а текущая - 10.2.3. И в ней проксисервер сильно переделан и, возможно, доведен до ума. Недостаток в том, что устанавливать придется вручную. Скачать можно отсюда - ftp://indy.fulgan.com/ZIP/
-
> umbra © (04.07.08 11:32) [24]
Спасибо за информацию, сейчас посмотрю новый инди :)
-
Собственно, проблема решилась установкой нового Инди, в котором можно задавать режим полнофайловой или потоковой передачи данных. Огромное спасибо umbra, ну и всем, кто откликнулся :)
-
Удалено модератором
|