Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2010.09.12;
Скачать: CL | DM;

Вниз

IdHTTPProxyServer и размер ресурса   Найти похожие ветки 

 
kernel ©   (2008-07-01 20:06) [0]

Доброго времени суток, уважаемые.

Бьюсь вторые сутки над "выдачей" информации о файле перед скачиванием через "испеченный" мною на основе  IdHTTPProxyServer прокси сервере.
Т.е. при скачивании файла через свой прокси, например, с помощью IE, должно сначала появиться окно, в котором мне будет хотя бы известен размер файла, после чего, в случае моего согласия, файл скачивается. Так вот дело в том, что мне не известен размер файла, пока сам этот файл не скачается полностью (например, в IE окошко сохранения файла появляется после полного скачивания этого файла), хотя без прокси все нормально. В самом прокси я передаю в заголовке ответа Content-Length, после чего само тело файла.
Кто-нибудь знает, как устранить эту проблемку?
ЗЫ: извиняюсь, если что-то коряво написал - у меня уже ночь, голова не соображает :)


 
umbra ©   (2008-07-01 23:44) [1]


> Т.е. при скачивании файла через свой прокси, например, с
> помощью IE, должно сначала появиться окно, в котором мне
> будет хотя бы известен размер файла, после чего, в случае
> моего согласия, файл скачивается.


Тут дело не в прокси-сервере, а в клиенте. Т.е. при получении ответа с кодом 200 (и с указанием размера в заголовках), клиент должен показывать табличку :)
Прокси-сервер тут ни причем. Хотя табличку может показывать и он, но тогда это не будет иметь отношения к клиенту, собственно скачивающему этот файл. Да и не дело это для сервера - таблички показывать :)


 
Поросенок Винни-Пух ©   (2008-07-01 23:51) [2]

(например, в IE окошко сохранения файла появляется после полного скачивания этого файла),

ну это ты сам так написал свой прокси.


 
umbra ©   (2008-07-02 12:35) [3]

в принципе есть запрос HEAD, предназначенный для получения информации о ресурсе. Прокси может слать сначала его, показывать табличку :) (хотя и не его это дело), а потом уже, в зависимости от реакции пользователя, слать или не слать GET


 
Поросенок Винни-Пух ©   (2008-07-02 12:58) [4]

да у него в дизайне кода проблема.
получив ссылку от браузера он пока его на прокси не выкачает, к передаче обратно в браузер не переходит.


 
Поросенок Винни-Пух ©   (2008-07-02 13:00) [5]

этож какие таймауты надо разрешать в браузере чтобы через такой замечательный прокси качать что-нибуть большее чем testgirl.jpg в 100 кб


 
kernel ©   (2008-07-02 13:19) [6]


> Поросенок Винни-Пух ©   (02.07.08 12:58) [4]
>
> да у него в дизайне кода проблема.
> получив ссылку от браузера он пока его на прокси не выкачает,
>  к передаче обратно в браузер не переходит.


Вообще IdHTTPProxyServer читает требуемые данные в Stream с запрашиваемого сервера, затем отсылает это браузеру. Но заголовок ответа (включая Content-Length) отсылается серверу до сбрасывания данных в/из stream:

{Например, при обработке GET:    }
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;
       //We have to remove the host and port from the request
       LDocument := LURI.Path + LURI.Document + LURI.Params;
     finally Sys.FreeAndNil(LURI); end;
     LClient.Connect; try
       LClient.IOHandler.WriteLn("GET " + LDocument + " HTTP/1.0"); {Do not Localize}
       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) ; {Do not Localize}

// вот ресурс отправляется:   ================================
         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`ом. Я даже сам настоятельно ему отправлял эту информацию, не спрашивая у него разрешения - не помогло :)


 
umbra ©   (2008-07-02 13:38) [7]


> Почему то браузер не просит информацию о ресурсе HEAD`ом

а чего он должен ее просить? не для этого его делали :)
Надо писат плагин/надстройку. Непонятно только, причем здесь прокси.


 
kernel ©   (2008-07-02 13:57) [8]

Бррр... И все же, когда мы скачиваем файл без прокси, нам известно какого он размера (см. окошко в браузере). А известно браузеру размер файла из-за полученного Content-Length. Прокси тоже сначала отправляет заголовок с Content-Length, но почему-то браузер не реагирует :/ Все это работает и без HEAD.


 
umbra ©   (2008-07-02 15:18) [9]

значит прокси кривой. Как у вас происходит отдача браузеру? вы видно и правда  сначала все на прокси закачиваете, хотя хттп прокси должен создавать туннель, покоторому все идет без задержек.


 
Поросенок Винни-Пух ©   (2008-07-02 15:42) [10]

И все же, когда мы скачиваем файл без прокси, нам известно какого он размера

И что же здесь странного?
То что контент ленс не только при подаче head отдается?


 
Поросенок Винни-Пух ©   (2008-07-02 15:43) [11]

Вообще IdHTTPProxyServer читает требуемые данные в Stream с запрашиваемого сервера, затем отсылает это браузеру

ну как я и говорил.
пока твой прокси не всосет четырехгиговый dvd рип целиком, браузер ни байта от него не получит.


 
kernel ©   (2008-07-02 15:45) [12]


> значит прокси кривой. Как у вас происходит отдача браузеру?
>  вы видно и правда  сначала все на прокси закачиваете, хотя
> хттп прокси должен создавать туннель, покоторому все идет
> без задержек.

Само тело ресурса закачивается на прокси, после чего отдается клиенту:

...
var
 LStream: TIdStream;
begin
 //TODO: Have an event to let the user perform stream creation
 LStream := TIdMemoryStream.Create; try
   ASrc.IOHandler.ReadStream(LStream, ASize, ASize = -1);
   LStream.Position := 0;
   DoHTTPDocument(ADocument, LStream, AHeaders); // TyT Hu4ero oco6eHHoro
   // Need to recreate IdStream, DoHTTPDocument passes it as a var and user can change the
   // stream that is returned
   ADest.IOHandler.Write(LStream);
 finally Sys.FreeAndNil(LStream); end;
...


Собственно, все это - стандартный код IdHTTPProxyServer (Indy 10), исходники которого есть в самом Delphi (2006 и т.д.).

Сам заголовок отдается раньше тела запрашиваемого ресурса (см. пост kernel ©   (02.07.08 13:19) [6]).


 
kernel ©   (2008-07-02 15:47) [13]

> Поросенок Винни-Пух ©   (02.07.08 15:43) [11]
> ну как я и говорил.пока твой прокси не всосет четырехгиговый
> dvd рип целиком, браузер ни байта от него не получит.

Как же тогда браузер узнает размер файла, даже без прокси?


 
Поросенок Винни-Пух ©   (2008-07-02 15:50) [14]

Как же тогда браузер узнает размер файла, даже без прокси?

из заголовка ответа конечно же.


 
Поросенок Винни-Пух ©   (2008-07-02 15:54) [15]

ты наверное думаешь, что ие действует так:
посылает гет или пост, читает заголовок, останавливает закачку, показывает окно с кнопкой отмена и пока не нажмешь ок не начинает качать сам контент.

только браузер делает не так да и кнопки "ок" там нет.
предположу, что получив заголовок и начав качать само тело файла, он через некоторое время асинхронно показывает окошко, в котором можно прекратить закачку.


 
Поросенок Винни-Пух ©   (2008-07-02 15:56) [16]

а твой волшебный прокси отдает только загловок, потом забивает на браузер и занимается высасыванием файла.


 
umbra ©   (2008-07-02 16:22) [17]


> а твой волшебный прокси отдает только загловок, потом забивает
> на браузер и занимается высасыванием файла

да, TIdHTTPProxyServer сделан криво. Пока он не закачает весь ресурс (причем по умолчанию - в память :)), он ничего не отдает. А поскольку сокеты блокирующие, то и события никакие произойти не могут, пока весь ресурс не закачается. Его надо рихтовать и рихтовать, чтобы до ума довести :)


 
Поросенок Винни-Пух ©   (2008-07-02 16:27) [18]

там и события особо никакие не нужны.
достаточно иметь два вложенных цикла чтения с сервера и отдачи браузеру.
ну и читать/отдавать конечно блочно, а не в стрим.


 
Anatoly Podgoretsky ©   (2008-07-02 16:50) [19]


> Как же тогда браузер узнает размер файла, даже без прокси?

Вопрос не правильный. А вот правильный

Как же тогда браузер узнает размер файла, без моего прокси?


 
kernel ©   (2008-07-03 19:46) [20]


> Поросенок Винни-Пух ©   (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;


Это единственное, что у меня почти заработало.
Почему-то такой код работает через раз :(
Складывается впечатление, что происходит где-то в цикле подвисание. Иногда страницы вообще не отдаются :(


 
kernel ©   (2008-07-04 10:45) [21]

Кто-нибудь может подсказать, как по-блочно читать? :)


 
umbra ©   (2008-07-04 11:13) [22]


> Кто-нибудь может подсказать, как по-блочно читать?

поскольку сокеты блокирующие, то поблочно читать можно только многократными запросами диапазона байтов ресурса. Для файлов это нормально, для страничек - нет.
Лучший, по-моему, выход - создать общий ресурс (типа временный файл) + два потока на клиента у прокси. Один читает ответ на запрос и пишет в файл, другой - читает записанное и шлет его клиенту. Но тут надо уже синхронизировать эти потоки так, чтобы тот, который отдает клиенту, не читал все правильно.


 
Поросенок Винни-Пух ©   (2008-07-04 11:16) [23]

поскольку сокеты блокирующие, то поблочно читать можно только многократными запросами диапазона байтов ресурса. Для файлов это нормально, для страничек - нет.

не страницу поблочно тянуть, а из тсп соединения читать блоками


 
umbra ©   (2008-07-04 11:32) [24]


> а из тсп соединения читать блоками

так оно ж потоковое. тогда всегда есть опасность, что сервер, с которого тянут может обидеться и отключиться :)

Еще вариант - скачать инди поновее, потому как тот, для которого есть автоматический инсталлятор имеет версию 10.1.5, а текущая - 10.2.3. И в ней проксисервер сильно переделан и, возможно, доведен до ума. Недостаток в том, что устанавливать придется вручную.
Скачать можно отсюда - ftp://indy.fulgan.com/ZIP/


 
kernel ©   (2008-07-04 12:26) [25]


> umbra ©   (04.07.08 11:32) [24]

Спасибо за информацию, сейчас посмотрю новый инди :)


 
kernel ©   (2008-07-06 17:31) [26]

Собственно, проблема решилась установкой нового Инди, в котором можно задавать режим полнофайловой или потоковой передачи данных. Огромное спасибо umbra, ну и всем, кто откликнулся :)


 
имя   (2008-11-09 15:32) [27]

Удалено модератором



Страницы: 1 вся ветка

Текущий архив: 2010.09.12;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.014 c
2-1275988122
worldmen
2010-06-08 13:08
2010.09.12
Структура файлов караоке - kar. Или как извлеч текст


2-1276375219
AKE
2010-06-13 00:40
2010.09.12
Как получить координаты всех точек?


15-1275932643
test
2010-06-07 21:44
2010.09.12
База данных Delphi?


11-1196527644
Byka (345-824-826)
2007-12-01 19:47
2010.09.12
помогите с Lazarus?


15-1276723981
KilkennyCat
2010-06-17 01:33
2010.09.12
Грамотный перевод AutoExpand?