Pobieranie plików protokołem HTTP za pomoca TClientSocket

  Często spotkamy pytanie: "Jak pobrać plik z sieci?" Najczęstszą odpowiedzią jest, iż mamy skorzystać z pakietu Indy. Jednak co zrobić, gdy nie chcemy bądź nie możemy użyć takiego rozwiązania? I tu pojawia się problem, który wydawałby się skomplikowany. W końcu programowanie to nie umieszczanie komponentów (gotowych rozwiązań) na formę, lecz pisanie kodu - wielu linii kodu :P. Takie rozwiązanie jest lepsze, gdyż nie tylko uczymy się, lecz mamy satysfakcje gdy napiszemy sami program i działa on poprawnie.
Wracając do tematu. Na początek proponowałbym od poznania protokołu HTTP -> http://www.w3.org/Protocols/rfc2616/rfc2616.html
Jednak jest on obszerny, więc spróbuje wyjaśnić jego działanie.

Protokół HTTP korzysta z portu 80, dlatego też powinniśmy ustawić ClientSocket1->Port = 80
Ogólna zasada jest prosta. Aplikacja wysyła odpowiednie zapytanie do serwera, ten odsyła odpowiedź.
Rozróżnia się kilka metod HTTP:

GET - pobranie zasobu wskazanego przez URI
HEAD - pobiera informacje o zasobie, stosowane do sprawdzania dostępności zasobu
PUT - przyjęcie danych przesyłanych od klienta do serwera
POST - przyjęcie danych przesyłanych od klienta do serwera (np. wysyłanie zawartości formularzy)
DELETE - żądanie usunięcia zasobu, włączone dla uprawnionych użytkowników
OPTIONS - informacje o opcjach i wymaganiach istniejących w kanale komunikacyjnym
TRACE - diagnostyka, analiza kanału komunikacyjnego
CONNECT - żądanie przeznaczone dla serwerów proxy pełniących funkcje tunelowania

Do pobierania plików będziemy korzystać z GET. Poniżej przedstawiam zapytania HTTP, które będą wykorzystane przez nas:

GET / HTTP/1.1 - prośba o zwrócenie dokumentu o URI / zgodnie z protokołem HTTP 1.1
Host: - jakisserwer.pl, wymagany w HTTP 1.1 nagłówek Host służący do rozpoznania hosta, jeśli serwer na jednym IP obsługuje kilka VirtualHostów
Accept: - text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8 (akceptowane (bądź nieakceptowane dla q=0) przez klienta typy plików)
Range: - prośba od (do) którego bajta serwer ma przesylać dane (parametr wykorzystywany w przypadku wznawiania pobierania danych)
User-Agent: - Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.0.1) Gecko/20060124 Firefox/1.5.0.1 (nazwa aplikacji klienckiej)


Przykład zapytania do serwera:

GET /download/pliczek.rar HTTP/1.1\r\n
Host: jakisserwer.pl\r\n
Accept: * /*\r\n
Range: bytes=0-\r\n
User-Agent: GetFiles(ver. 0.1)\r\n\r\n

Przykład odpowiedzi serwera WWW:

HTTP/1.1 206 Partial Content\r\n
Content-Length: 3265278\r\n
Content-Type: application/octet-stream\r\n
Content-Range: bytes 0-3265277/3265278\r\n
Last-Modified: Fri, 30 Jun 2006 20:18:45 GMT\r\n
Accept-Ranges: bytes\r\n
ETag: "7c7faa63829cc61:21af"\r\n
Server: Microsoft-IIS/6.0\r\n
MicrosoftOfficeWebServer: 5.0_Pub\r\n
X-Powered-By: ASP.NET\r\n
Date: Thu, 13 Jul 2006 20:19:42 GMT\r\n\r\n
--dane przesyłanego pliku--


Najważniejsze linie odpowiedzi serwera to:
HTTP/1.1 206 Partial Content <- stan kodu (200 - plik istnieje - nie ma możliwości wznawiania ściągania, 206 - plik istnieje - możliwość wznawiania, 404 - pliku nie odnaleziono, więcej informacji tutaj)
Content-Length: 3265278 <- wielkość przesyłanego pliku.

Pobieranie plików nie jest trudne, lecz nawet prostsze niż mogła nam sie wydawać.
Chciałbym zwrócić uwagę, iż tym sposobem nie da się pobrać wszystkich danych. Możliwe jest pobieranie plików wysyłanych strumieniowo tzn. w nagłówku przesłany jest rozmiar pliku.

Tutaj możecie pobrać przykładowy program, wraz z kodem źródłowym.

W przypadku jakichkolwiek problemów, proszę pisać na e-maila.