Как загрузить не большой удалённый файл по проще

Тема в разделе "WASM.NETWORKS", создана пользователем s_d_f, 29 сен 2009.

  1. s_d_f

    s_d_f New Member

    Публикаций:
    0
    Регистрация:
    15 май 2008
    Сообщения:
    342
    Всем здрасте. Пожалуйста помоготи разобраться с одной проблемой. Мне нужно написать простую программу загружающую малые удалённые файлы и HTML страницы, скажем не более 300 кб. Для загрузки я использую функцию URLDownloadToFile. Ей достаточно передать указатели на URL и файл, и она загружает файл. Вот только нужно ещё за ранее узнать размер файла или HTML страницы, чтобы точно знать, что он не большой. Да и имя файла далеко не всегда в явном виде присутствует в URL.
    Вот процедура получения размера файла которая почему-то не всегда страбатывает
    Код (Text):
    1. HTML struc
    2.     URL dd ?        ;URL - ОТКУДА СКАЧИВАТЬ
    3.     PATH dd ?   ;ПОЛНОЕ ИМЯ ФАЙЛА
    4. HTML ends
    5.  
    6. SizeURL proc psHtm:DWORD
    7. LOCAL hUrl:DWORD
    8. LOCAL dwRWurl:DWORD
    9. LOCAL dwRWfile:DWORD
    10. LOCAL dwBuffer[20]:BYTE
    11. LOCAL lpdwBufferLength
    12. LOCAL dwIndex
    13. LOCAL hInt
    14. assume ebx:ptr HTML
    15.     mov ebx,psHtm
    16.     invoke InternetOpen,offset AppName,0,0,0,0
    17.     mov hInt,eax
    18.     xor eax,eax
    19.     invoke InternetOpenUrl,hInt,[ebx].URL,eax,eax,eax,eax
    20.     mov hUrl,eax
    21.     .if eax
    22.         mov lpdwBufferLength,sizeof dwBuffer
    23.         mov dwIndex,0
    24.         invoke HttpQueryInfo,hUrl,HTTP_QUERY_CONTENT_LENGTH,addr dwBuffer,addr lpdwBufferLength,addr dwIndex
    25.         invoke InternetCloseHandle,hUrl
    26.         invoke crt_atol,addr dwBuffer
    27.     .endif
    28.     push eax
    29.     invoke InternetCloseHandle,hInt
    30.     pop eax
    31.     ret
    32. assume ebx:nothing
    33. SizeURL endp
    Например если URL 'http://www.wasm.ru/baixado.php?mode=tool&id=403', то размер узнать не получается, а ещё с таким URL надо-бы ещё и имя файла узнавать. А если имя файла задано явно, то обычно проходит всё без проблем, скажем URL db 'http://www.somesite.ru/somearchive.zip',0.
     
  2. valterg

    valterg Active Member

    Публикаций:
    0
    Регистрация:
    19 авг 2004
    Сообщения:
    2.105
    Просто не всякий линк - это файл. Есть еще всякие "премудрости".
    baixado.php - это скрипт написанный на специальном языке, хранящийся на сервере и там же выполняющийся. Тут, видимо, нужны другие методы.
     
  3. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    К сожалению, ты не очень понимаешь суть HTTP-протокола. Дело в том, что тут нет понятия файл/не файл. Есть понятия запрос/ответ.

    Вот это запрос. Внутри он может выглядеть следующим образом (сформировано Google Chrome):

    Ответ на него выглядит так:

    Это страница-перенаправление (код 302). Поле Location в этом случае указывает броузеру, куда следует идти дальше. Он и идёт:

    И в ответе теперь то, что нужно:

    Учитесь снифером пользоваться, господа.
     
  4. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Конкретно: что есть "не получается"? В чём это проявляется? Функция ошибку возвращает? Какая функция? Какую именно ошибку? Подозреваю, что ты просто поле Accept: */* забыл указать в InternetOpenUrl(), не знаю, проверять лень сейчас.

    В случае выше у тебя только два варианта:

    1. Оставить обработку перенаправления системе, при этом имя ты уже получить не сможешь никак, только размер.
    2. Выполнять перенаправление самостоятельно, тогда получишь и имя и размер.

    Для обработки вручную надо указать флаг INTERNET_FLAG_NO_AUTO_REDIRECT в функции InternetOpenUrl() и проверить наличие поля Location: ..., оно указывает, где реально лежит запрашиваемый объект, при этом первый запрос следует повторять рекурсивно, пока будет возвращаться поле Location в ответе (скорее всего попадание будет уже со второго раза, но мало ли...). На каждой итерации запоминай последнее возвращённое значение поля Location. Имя файла ты сможешь получить из последнего возвращённого Location'а, а размер - из запроса на URL, указанный в последнем Location.
     
  5. s_d_f

    s_d_f New Member

    Публикаций:
    0
    Регистрация:
    15 май 2008
    Сообщения:
    342
    Протоколов я действительно не знаю, просто надеялся, что и без этого можно обойтись. Жаль что нет API URLGetSize и URLGetName. Придётся самому по сидеть разобраться.
     
  6. valterg

    valterg Active Member

    Публикаций:
    0
    Регистрация:
    19 авг 2004
    Сообщения:
    2.105
    Таких функций URLGetSize и URLGetName в принципе не может быть. URL - это действительно скорее указание к действию, чем ссылка на файл. Ты бы уточнил свою задачу, может что-то подсказали тогда.
     
  7. HeadHunter

    HeadHunter New Member

    Публикаций:
    0
    Регистрация:
    5 авг 2009
    Сообщения:
    30
    Всё работает, нужно использовать два способа:

    Код (Text):
    1. (FASM синтаксис)
    2. 1. invoke HttpQueryInfo, [hUrl], HTTP_QUERY_CONTENT_LENGTH, addr dwBuffer, addr lpdwBufferLength, 0
    3. 2. invoke InternetQueryDataAvailable, [hUrl], addr lpdwBufferLength, 0, 0
    Если "HttpQueryInfo" возвращает "ERROR_HTTP_HEADER_NOT_FOUND", значит нет запрашиваемого заголовка, неоткуда его просто взять, и в этом случае прибегаем ко второму способу.

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

    У меня "HttpQueryInfo" возвратил корректный размер файла по ссылке - http://www.wasm.ru/baixado.php?mode=tool&id=403, следовательно если у тебя не работает, то ошибка в коде.
     
  8. maksim_

    maksim_ New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2009
    Сообщения:
    263
    хм.. в протоколе http есть несколько методов передачи данных. и понятие "файл" там всё-таки есть - при передаче multimedia данных.

    в Вашем случа запросить размер файла, думаю, можно. нужно покапаться в rfc. суть заключается в том, чтобы запросить нужный файл не методом GET, а ... (забыл, вроде HEADER или как-то так) - сервер выдаст только заголовок ответа. ещё нужно указать серверу поддерживаемый тип передачи данных, чтобы он выдавал ответ не через chunked, а через content-length.