The term ‘cookie’ shall be familiar not only to programmers, but also to many of the more conscious, ordinary computer users. I’m not, unfortunately, talking about sweet pastry, but HTTP cookies.
Those cookies that we all know and love (if we’re web developers) or hate (if we’re overly paranoid about privacy) are not the only thing in computing to be known under this name, however. I learned this quite recently when talking to a friend of mine who is working in the realm of IT security. As it turns out, ‘cookie’ can refer to quite diverse array of different solutions, all unified through similar underlying concept.
Potrzeba automatycznego przekierowania strony WWW do innego adresu URL pojawia się całkiem często. Dość typowe są na przykład serwisy typu download, gdzie faktyczne ściągnięcie pliku poprzedzone jest krótkim oczekiwaniem i odpowiednim komunikatem. Służy to głównie temu, by użytkownik omyłkowo nie rozpoczął procesu ściągania więcej niż raz.
Przyjrzyjmy się dzisiaj sposobom na dokonywanie takich przekierowań. Jeśli bowiem chwilę się nad tym zastanowić, to okazuje się, że można je przeprowadzać na różnych poziomach protokołów HTTP i nie tylko. Wśród możliwych metod można wyróżnić choćby takie:
window.location
. Ustawienie tej właściwości na adres URL powoduje automatyczne wykonanie przekierowania. Do działania wymaga to naturalnie obsługi Javascriptu po stronie klienta, więc może służyć do odfiltrowania tych klientów, którzy nie spełniają tego warunku. Dotyczy to na przykład przeglądarek tekstowych, takich jak Lynx.<meta>
. HTML przewiduje możliwość odświeżenia strony po określonym czasie, z opcjonalnym przekierowaniem do innego URL-a. Korzysta się w tym celu ze znacznika <meta>
:
Właśnie ta metoda jest zwykle wykorzystywana do implementacji wspomnianego na początku opóźnionego ściągania plików.
Location
). Istnieje cała grupa takich kodów o numerach zaczynających się od 300, jak na przykład 301 (Moved Permanently), będący trwałym przekierowaniem, czy 302/307 (Found/Temporary Redirect), wskazujące na mniej lub bardziej tymczasowe odesłanie do innego adresu.Jeśli przypadkiem zastanawiamy się, który rodzaj przekierowania powinniśmy zastosować, to spieszę z odpowiedzią, że prawie na pewno dobrym wyborem będzie któryś z dwóch środkowych elementów listy. Uzasadnieniem jest tu głównie chęć współpracy z robotami wyszukiwarek internetowych. Nie powinniśmy mianowicie spodziewać się, by uruchamiały one kod Javascript na przeglądanych przez siebie stronach, bo kosztowałoby to je zbyt dużo zasobów. Z drugiej strony istnieje też duża szansa, że nie będą one “świadome” “przekierowań” dokonywanych na poziomie systemu DNS, przez co mogą one potraktować dostępność tych samych treści z dwóch różnych adresów jako świadome duplikowanie contentu i próbę ich oszukania.
W grę wchodzą naturalnie jeszcze kwestie praktyczne. Nie każdy dysponuje własną domeną lub możliwością zmiany jej rekordów DNS. Nie każdy może też zmieniać ustawienia serwera HTTP, na którym funkcjonuje jego serwis. Wtedy przydatne są przekierowania dokonywane po stronie klienta np. za pomocą tagów HTML.
W ramach wyposażania nowozainstalowanego systemu w niezbędne programy, przypomniałem sobie o istnieniu PowerShella. Kiedy jednak chciałem go ściągnąć, spotkała mnie przyjemna niespodzianka: PSh w Windows 7 jest już od razu zainstalowany, więc można go od razu zacząć go używać. Jak sądzę, przyczyni do zwiększenia jego popularności, co jest z pewnością dobrą rzeczą.
Fakt sprawił rzecz jasna, że zaraz zachciało mi się wypróbować go w jakimś nowym zastosowaniu. Padło na wysyłanie update‘ów do Twittera, w którym to zresztą niedawno się zarejestrowałem (i wciąż nie wiem, dlaczego ;)). Sprawa na oko nie jest trudna, bo sprowadza się do wykonania jednego żądania HTTP POST. Ale jak wiadomo, diabeł zwykle tkwi w szczegółach. Oto skrypt:
Jednym z owych detali było kodowanie statusu algorytmem dla URL-i (zamieniającym spacje na %20 itd.), wykonywane poprzez System.Web.HttpUtility.UrlEncode
– stąd konieczność importowania assembly System.Web
. Ale to jest w sumie pikuś.
Znacznie większym “trikiem” jest linijka oznaczona gwiazdką (*)
. Powoduje ona obejście domyślnego zachowania .NET, który do każdego żądania HTTP typu POST dodaje nagłówek:
Powoduje on wysłanie tak naprawdę dwóch requestów: w pierwszym serwer ma tylko sprawdzić poprawność nagłówków (logowania, na przykład) i zwrócić status 100 (Continue). Dopiero w drugim klient wysyła właściwe dane. Mechanizm ten jest w .NET opakowany przezroczyście i ma zapobiegać niepotrzebnemu przesyłaniu dużych ilości danych w żądaniu, które i tak byłoby odrzucone.
API Twittera jednak tego nie obsługuje i jest to właściwe. Trudno przecież nazwać status, mający maks. 160 znaków, “dużą ilością danych”. Lepiej więc przesyłać go od razu, a domyślne zachowanie .NET-a obejść. To właśnie robi zaznaczony wiersz.
Przypomnę jeszcze tylko – gdy ktoś zechciał powyższego skryptu używać do przesyłania tweetów – że uruchomienie skryptu PSh z poziomu zwykłej linii poleceń wymaga parametru -Command
i kropki:
Do takiej komendy można np. utworzyć skrót i przypisać mu kombinację klawiszy w celu szybkiego uruchamiania.
Oprócz ciasteczek (cookies) dwoma podstawowymi sposobami przekazywania parametrów na wejście serwera HTTP są metody znane jako GET i POST. Ta pierwsza wykorzystuje do tego sam adres URL, umieszczając dodatkowe dane po znaku zapytania, np.: /forum/showthread.php?id=12345&filter=none. W przypadku tej drugiej parametry są przekazywane poprzez treść samego żądania HTTP; z punktu widzenia użytkownika są więc one niewidoczne.
Metoda GET zwykle służy do wymiany danych między stronami połączonymi za pomocą zwykłych linków. POST z kolei wykorzystuje się do wysyłania informacji wprowadzanych przez użytkownika w różnego rodzaju formularzach. Przekierowanie następuje wówczas po jego wysłaniu, co zwykle czyni się odpowiednim przyciskiem (submit).
Bywa jednak tak, że chcemy dokonać takiego przekierowania – z ustalonymi parametrami – po zwykłym kliknięciu na link, z pominięciem wypełniania formularza przez użytkownika. Dobrym przykładem jest sytuacja, gdy nasza strona korzysta w jakiś sposób z innego serwisu, do którego przejście wymaga logowania. Jeśli chcielibyśmy, by odbywało się ono automatycznie – po kliknięciu jakiegoś linku – to musimy wysłać odpowiednie żądanie HTTP z parametrami przesłanymi metodą POST. Do tego nie wystarczy niestety sam znacznik <a>
.
Rozwiązaniem jest wtedy użycie dodatkowej strony przekierowującej, na której umieścimy już odpowiednio “wypełniony” formularz:
Oczywiście nazwy i wartości parametrów (zapewne generowane dynamicznie po stronie serwera) zależą ściśle od tego, dokąd chcemy nasz wyrób formularzopodobny wysłać. Wszystkie je deklarujemy jednak jako <input type="hidden" />
, bo w założeniu użytkownik nie powinien ich (łatwo) zobaczyć. Ponadto, jeśli – tak jak wyżej – mówimy o loginie/haśle czy innych danych, które powinno się chronić przed niepowołanym dostępem, to powinniśmy jeszcze wysyłać razem z naszą stroną nagłówki HTTP zabraniające cache‘owania:
W końcu, skoro mamy już gotowy “formularz”, to trzeba jeszcze zadbać o to, by wysłał się on sam natychmiast po załadowaniu strony przekierowującej. Do tego już trzeba wykorzystać skrypt uruchamiany w przeglądarce:
Tak przygotowaną stronę możemy podlinkować pod nasz serwis. Jak widać trochę z tym zabawy, ale tak to jest, gdy chcemy zrobić coś niestandardowego :)
Protokół HTTP i World Wide Web powstały już bardzo dawno temu, chociaż od tamtego czasu doczekały się całego mnóstwa usprawnień. Pewnie największym była możliwość generowania stron HTML dynamicznie przy użyciu skryptów CGI, PHP, i tak dalej. Dzięki temu strony umieją już całkiem sporo i nie są statycznymi dokumentami. Ich tworzenie zaczęło też bardziej przypominać pisanie normalnych aplikacji.
Pewne ograniczenia HTTP ciężko jest jednak przezwyciężyć. Największym jest chyba to, że serwery każde zgłoszenie (request), które do nich napływa, traktują zupełnie odrębnie i w oderwaniu od wszystkich innych. Działają więc na zasadzie pytanie-odpowiedź. Gdyby poszukać odpowiednika tego modelu w zwyczajnych programach, to byłyby nim narzędzia konsolowe obsługiwane w całości przełącznikami wiersza poleceń. W dobie interfejsów graficznych mieniących się wszystkimi kolorami palety RGB nie wyglądają one zbyt imponująco…
Dlatego też wszelkie platformy służące uruchamianiu aplikacji webowych starają się tę niedogodność jakoś obejść i umożliwić powiązanie poszczególnych żądań oraz przechowywanie danych pomiędzy nimi. Standardem jest mechanizm sesji, ale np. w PHP nigdy nie udało mi się do końca go zrozumieć :)
Ostatnio jednak z konieczności (nietrudno się domyślić, jakiej :)) zajmuję się ASP.NET i muszę przyznać, że tam cała sprawa została potraktowana nieporównywalnie lepiej. Przede wszystkim serwis jest tam rzeczywiście traktowany jako aplikacja, której instancja uruchamia się w momencie pierwszego requestu z danego hosta. Poszczególne strony przypominają też raczej okienka zwykłych programów, na których zamieszcza się kontrolki specyficzne dla ASP (przerabiane na wyjściu na HTML). I to ze wszystkimi konsekwencjami: one rzeczywiście istnieją na serwerze. To sprawia, że możemy np. pobrać dane formularza wypełnionego przed chwilą na poprzedniej stronie, po prostu czytając zawartość jej kontrolek.
Cała ta trwałość nie jest oczywiście aż tak daleko posunięta jak w tradycyjnych programach. Zdarza się (i to dość często), że musimy zwracać uwagę na to, kiedy strona może być przeładowywana. Ale i tak stanowi to spory postęp na przykład w stosunku do wspomnianego mechanizmu sesji (który naturalnie też jest dostępny).
Naturalnie wszystko to są jednak tylko obejścia do starego protokołu, który pierwotnie nie został zaprojektowany do tak złożonych zadań, do których się go obecnie wykorzystuje.