Blog (2)
Komentarze (36)
Recenzje (0)
@maciejkaczkowskiBASH: Implementacja metod GET i POST protokołu HTTP

BASH: Implementacja metod GET i POST protokołu HTTP

14.05.2013 20:30

System Linux, w bardzo łatwy sposób, umożliwia nam dostęp do protokołu TCP, za pomocą którego możemy zaimplementować wiele tekstowych protokołów wyższych warstw. W tym wpisie zaprezentuje jak uzyskać dostęp do zasobów HTTP przez metody GET i POST, za pomocą języka skryptowego BASH.

Zacznijmy od typowego zapytania GET (RFC 2616). Wygląda następująco:

GET / HTTP/1.1
Host: www.wp.pl

Pierwsza linia składa się z: metody - GET zasobu - / wersji - HTTP/1.1

W następnej linii określony został host (serwer), z którego pobieramy zasoby.

Standardowo każdy skrypt w Linuksie uruchamiany jest z trzema strumieniami stdin (0), stdout (1), strerr (2). Dostęp do protokołu TCP otrzymujemy przez wirtualne urządzenie /dev/tcp, HTTP jest protokołem wyższej warstwy pracującym na porcie 80. Aby nawiązać połączenie, należy utworzyć kolejny strumień, który zestawi nam transmisję klient-serwer na porcie 80, w tym celu wpisujemy

exec 3<>/dev/tcp/www.wp.pl/80

3 - oznacza nowy strumień, który będzie używany do wysyłania i odbierania komunikatów <> - to przekierowanie wejścia i wyjścia /dev/tcp/www.wp.pl/80 - to określenie serwera do jakiego uzyskujemy dostęp

W tym momencie mamy zestawione połączenie klient-serwer. Teraz wyślemy żądanie dostępu do zasobu. Wpiszmy sekwencję:

echo "GET / HTTP/1.1" >&3
echo "Host: www.wp.pl" >&3
echo "" >&3

>&3 oznacza przekierowanie danych do strumienia "3", który jest naszym połączeniem (klient-serwer). Pierwsze dwie linie zostały omówione wcześniej, trzecia (pusta) wg standardu stanowi separator/zakończenie komunikatu GET. Zapytanie zostało wysłane do serwera, a jego wynik oczekuje na nas w strumieniu "3". Aby go wyświetlić należy przekierować wyjście na ekran za pomocą polecania cat:

cat <&3

Uzyskamy w ten sposób zasób "/" z serwera "www.wp.pl", łącznie z nagłówkami GET/HTTP. Niektóre serwery (np. google.com) po wykonaniu zapytania nie zamkną automatycznie połączenia, dlatego też należy określić, że chcemy je zamknąć po pobraniu zasobu:

echo "GET / HTTP/1.1" >&3
echo "Host: www.google.com" >&3
echo "Connection: close" >&3
echo "" >&3

Jako podsumowanie GET zapiszmy całość jako funkcję bash:


http_get()
{
  HOST=`echo $1 | sed "s/.*\:\/\///"`
  PARAM="/"`echo $HOST | sed "s/.*\///"`
  HOST=`echo $HOST | sed "s/\/.*//"`
  PORT="80"
  exec 3<>/dev/tcp/$HOST/$PORT
  if [ $? -ne 0 ]; then
    exit
  fi
  echo "GET $PARAM HTTP/1.1" >&3
  echo "Host: $HOST" >&3
  echo "Connection: close" >&3
  echo "" >&3
  cat <&3
}

http_get "http://www.wp.pl/"

Przejdźmy teraz do metody POST, która umożliwia przekazywanie parametrów do serwera. Minimalna postać zapytania wygląda następująco:

POST / HTTP/1.1
Host: www.wp.pl
Content-Length: 4
Content-Type: application/x-www-form-urlencoded

dane

W pierwszej linii POST oznacza metodę przekazywania danych do serwera, reszta jest identycznie jak w GET. Podobnie jest w drugiej linii. Content-Length oznacza długość danych, wysłanych za separatorem (pusta linia), Content-Type - to format przesyłanych danych.

Implementacja w postaci funkcji:


http_post()
{
  HOST=`echo $1 | sed "s/.*\:\/\///"`
  PARAM="/"`echo $HOST | sed "s/.*\///"`
  HOST=`echo $HOST | sed "s/\/.*//"`
  PORT="80"
  DATA="$2"
  SIZE=${#DATA}
  TYPE="$3"
  exec 3<>/dev/tcp/$HOST/$PORT
  if [ $? -ne 0 ]; then
    exit
  fi
  echo "POST $PARAM HTTP/1.1" >&3
  echo "Host: $HOST" >&3
  echo "Connection: close" >&3
  echo "Content-Length: $SIZE" >&3
  echo "Content-Type: $TYPE" >&3
  echo "" >&3
  echo "$DATA" >&3
  cat <&3
}

Podobnie jak w metodzie GET wysyłamy dla pewności opcję zakończenia połączenia (Connection: close) po przesłaniu danych. Content-Length zliczany jest z długości przekazanych danych ${#DATA}. Pomiędzy danymi, a nagłówkiem zostawiamy linię wolną - oznacza to zakończenie przesyłania nagłówka i rozpoczęcie przesyłania danych.

Przykład zastosowania:

http_post "http://localhost/login.php" "username=nazwa&password=haslo" "application/x-www-form-urlencoded"

Znając podstawy można spróbować zaimplementować inne protokoły warstwy aplikacji.

Wybrane dla Ciebie
Komentarze (12)