Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2010.09.12;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.004 c
2-1276534233
akosh12345
2010-06-14 20:50
2010.09.12
Вывод кнопок динамически


15-1274256143
12
2010-05-19 12:02
2010.09.12
Помогите пропатчить dll. Обход ошибочного кода. Не взлом!


2-1277059445
Delphist2
2010-06-20 22:44
2010.09.12
savedialog


2-1276611901
john-s
2010-06-15 18:25
2010.09.12
Не читает данные из файла


2-1276374865
AKE
2010-06-13 00:34
2010.09.12
Как нарисовать закрашенный треугольник?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский