HTTP W 5-CIU PYTANIACH MICHAŁ KOPACZ



Podobne dokumenty
Technologie internetowe


Systemy internetowe. Wykład 5 Architektura WWW. West Pomeranian University of Technology, Szczecin; Faculty of Computer Science

Protokół HTTP 1.1 *) Wprowadzenie. Jarek Durak. rfc2616 źródło

Programowanie Sieciowe 2 Protokoły komunikacyjne: HTTP

Protokół HTTP. 1. Protokół HTTP, usługi www, model request-response (żądanie-odpowiedź), przekazywanie argumentów, AJAX.

Programowanie w Internecie

Ataki na aplikacje WWW. Łomem, czy wytrychem? Jak dobrać się do aplikacji WWW

Plan wykładu. 1. Protokół FTP. 2. Protokół HTTP, usługi www, model request-response (żądanie-odpowiedź), przekazywanie argumentów, AJAX.

Politechnika Gdańska Wydział Elektrotechniki i Automatyki Kierunek: Automatyka i Robotyka Studia stacjonarne I stopnia: rok I, semestr II

Tworzenie witryn internetowych PHP/Java. (mgr inż. Marek Downar)

Technologie Internetu. Protokół HTTP. Aleksander Denisiuk.

Programowanie w Internecie

Języki programowania wysokiego poziomu WWW

Aplikacje WWW. Wykład 4. Protokół HTTP. wykład prowadzi: Maciej Zakrzewicz. Protokół HTTP

Sieciowe systemy informacyjne

Sieci komputerowe. Wykład 8: Warstwa zastosowań: FTP i HTTP. Marcin Bieńkowski. Instytut Informatyki Uniwersytet Wrocławski

XML-RPC: Zdalne wykonywanie procedur

Hosting WWW Bezpieczeństwo hostingu WWW. Dr Michał Tanaś (

HTTP. literatura:

Bezpieczeństwo WWW. Plan prezentacji. WWW a protokoły TCP/IP; URL. Czym jest WWW?

Sprawozdanie Sieci komputerowe i bazy danych Laboratorium nr 4

Sprawozdanie Sieci komputerowe i bazy danych Laboratorium nr 4 Wojciech Kaczmarski

The OWASP Foundation Session Management. Sławomir Rozbicki.

Tworzenie witryn internetowych PHP/Java. (mgr inż. Marek Downar)

ZESZYTY ETI ZESPOŁU SZKÓŁ W TARNOBRZEGU Nr 2 Seria: Teleinformatyka 2013

I.Wojnicki, Tech.Inter.

Technologie sieciowe Sprawozdanie z labolatorium. Lista 5

Kontrola sesji w PHP HTTP jest protokołem bezstanowym (ang. stateless) nie utrzymuje stanu między dwoma transakcjami. Kontrola sesji służy do

PSI Protokół HTTP + wstęp do przedmiotu. Kraków, 10 październik 2014 mgr Piotr Rytko Wydział Matematyki i Informatyki UJ

Specyfikacja techniczna. mprofi Interfejs API

Wybrane działy Informatyki Stosowanej

Obsługa incydentów bezpieczeństwa: część I, z punktu widzenia menadżera. OWASP The OWASP Foundation

Sprawozdanie nr 4. Ewa Wojtanowska

OPIS TECHNICZNY SYSTEM HOSTED SMS

Gatesms.eu Mobilne Rozwiązania dla biznesu

Aplikacje webowe. mgr inż. Aleksander Smywiński-Pohl. Elektroniczne Przetwarzanie Informacji

Czym jest AJAX. AJAX wprowadzenie. Obiekt XMLHttpRequest (XHR) Niezbędne narzędzia. Standardowy XHR. XHR z obsługą baz danych

Architektura aplikacji sieciowych. Architektura klient-serwer

Analiza malware'u SandroRAT_sec Kaspersky_Mobile_Security.apk

HTTP, CGI, Perl. HTTP HyperText Transfer Protocol. CGI Common Gateway Interface. Perl Practical Extraction and Report Language

PHP. Tematyka wykładów: Język PHP PHP i bazy danych Rozszerzenia PHP

FTP co to takiego? FTP File Transfer Protocol (Protokół Przesyłania Plików) RFC 114,959

I.Wojnicki, Tech.Inter.

Protokół HTTP. Omówienie standardu z analizą ruchu sieciowego

Uwierzytelnianie HTTP

Kontrola sesji w PHP HTTP jest protokołem bezstanowym (ang. stateless) nie utrzymuje stanu między dwoma transakcjami. Kontrola sesji służy do

Bezpieczeństwo frameworków WEBowych Java na przykładzie ataku CSRF

Kurs WWW. Paweł Rajba

SEO Audyt. Podsumowanie. 51/100 punktów. Masz 11 rzeczy, które możesz poprawić! Uzyskany wynik: Data przeprowadzenia: :33:47

Aplikacje internetowe Koncepcja Architektura Technologie

I.Wojnicki, JiTW. Języki i Technologie Webowe. Protokół HTTP, Przegladarki. Igor Wojnicki

Sieci komputerowe. Wykład 7: Warstwa zastosowań: DNS, FTP, HTTP. Marcin Bieńkowski. Instytut Informatyki Uniwersytet Wrocławski

Sieci komputerowe. Tadeusz Kobus, Maciej Kokociński Instytut Informatyki, Politechnika Poznańska

Podstawy implementacji usług sieciowych OGC

Orange Send MMS. Autoryzacja. Metoda HTTP. Parametry wywołania. API wyślij MMS dostarcza wiadomości MMS. Basic POST

Wykład 5: Najważniejsze usługi sieciowe: DNS, SSH, HTTP, . A. Kisiel,Protokoły DNS, SSH, HTTP,

Referat z przedmiotu Technologie Internetowe SPIS TREŚCI

Bazy Danych i Usługi Sieciowe

TCP/IP. Warstwa aplikacji. mgr inż. Krzysztof Szałajko

Systemy internetowe. Wykład 3 PHP. West Pomeranian University of Technology, Szczecin; Faculty of Computer Science

Laboratorium nr 4 - Badanie protokołów WWW

Warszawa Specyfikacja techniczna. mprofi Interfejs API wersja 1.0.7

Zbieranie podstawowych śladów działalności.

INTERNETOWE BAZY DANYCH materiały pomocnicze - wykład VII

Raport dla strony: Data wygenerowania raport: :37:26 Liczba wykrytych problemów: 34

PHP: bloki kodu, tablice, obiekty i formularze

Warstwa aplikacji. część 1. Sieci komputerowe. Wykład 8. Marcin Bieńkowski

Aktualizacja SMSFall v Data publikacji:

API System Partnerski

Języki programowania wysokiego poziomu. PHP cz.3. Formularze

MODEL WARSTWOWY PROTOKOŁY TCP/IP

Jak okiełznać frontend w Django? Piotr Maliński

Źródła. cript/1.5/reference/ Ruby on Rails: AJAX: ssays/archives/

Kurs WWW 1. Paweł Rajba

Stos TCP/IP. Warstwa aplikacji cz.2

Zaawansowane Techniki WWW (HTML, CSS i JavaScript)

PHP. i komunikacja klient-serwer PAWEŁ RAJBA

Paweł Rajba

SSL (Secure Socket Layer)

1. Model klient-serwer

Zarządzanie sesją w aplikacjach Internetowych. Kraków, Paweł Goleń

Adres IP

Dokumentacja interfejsu HTTPD. Platforma BSMS.PL Instrukcja podłączenia po przez http

SEO Audit for domain zdrowewidzenie.pl

Bazy Danych i Usługi Sieciowe

Protokół HTTP wprowadzenie. Protokół HTTP podstawowe cechy. Protokół HTTP podstawowe cechy. Protokół HTTP. Podstawowy protokół World Wide Web

Aplikacje WWW Wprowadzenie

Systemy internetowe Wykład 3 PHP

Tworzenie stron internetowych z wykorzystaniem HTM5, JavaScript, CSS3 i jquery. Łukasz Bartczuk

Problemy z uwierzytelnianiem HTTP

Dokumentacja serwera REST do obsługi rezerwacji w systemie SaNAtoRIUm.pro

I.Wojnicki, PHP. PHP PHP Hypertext Preprocessor. Igor Wojnicki. Ktedra Informatyki Stosowanej Akademia Górniczo-Hutnicza w Krakowie.

Internetowe bazy danych

mgr inż. Michał Paluch

Aplikacje internetowe - laboratorium

Projektowanie stron WWW

NoSQL Not Only SQL: CouchDB. I.Wojnicki, NoSQL. Apache CouchDB has started. Time to relax. Przetwarzanie dokumentów i widoków.

Transkrypt:

HTTP W 5-CIU PYTANIACH MICHAŁ KOPACZ

1 Co się dzieje po wpisaniu URL w przeglądarce?

https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content

Uniform Resource Locator (ujednolicony format adresowania zasobów)

ZASÓB Zasobem może być wszystko co jest na tyle istotne by umieścić to pod danym URL. function sort() {... }

ul. Krzywa 12/5 55-323 Wrocław Polska 88050152312 NIE SĄ UJEDNOLICONE

scheme://username:password@host:port/path?query_string#fragment_id

SCHEMAT scheme://username:password@host:port/path?query_string#fragment_id http ftp https file chrome https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content

LOGIN I HASŁO scheme://username:password@host:port/path?query_string#fragment_id git clone https://michalkopacz:mktest123@github.com/michalkopacz/zf-apigility.git https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content

ADRES SERWERA scheme://username:password@host:port/path?query_string#fragment_id api.github.com 173.194.34.5 [db8:0cec::99:123a] www.facebook.com subdomena https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content

PORT scheme://username:password@host:port/path?query_string#fragment_id http: 80 https: 443 8080 https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content

ŚCIEŻKA DO ZASOBU scheme://username:password@host:port/path?query_string#fragment_id file:///c:/books/http%20the%20definitive%20guide.pdf https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content

ŁADNE URL http://mojastrona.pl/regulamin RewriteEngine On RewriteRule ^regulamin$ index.php?page=regulamin http://mojastrona.pl/index.php?page=regulamin

ŚCIEŻKA WYSZUKIWANIA scheme://username:password@host:port/path?query_string#fragment_id http://allegro.pl/listing/listing.php?order=qd&string=http&search_scope=category-7 https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content

FRAGMENT scheme://username:password@host:port/path?query_string#fragment_id przeglądarki nie wysyłają go do serwera może być używany przez JavaScript, np. https://www.youtube.com/watch?v=tl4bj1s66ga#t=95 https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content

https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content github.com DNS 192.30.252.131

https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content github.com DNS 192.30.252.131 192.30.252.131:443 TCP

TCP Transmission Control Protocol wszystkie bity otrzymane są identyczne jak bity wysłane wszystkie bity otrzymane są w kolejności ich wysłania

Hypertext Transfer Protocol (protokół przesyłania dokumentów hipertekstowych)

REQUEST-RESPONSE REQUEST TCP RESPONSE

HTTPbis

MODEL OSI Open Systems Interconnection aplikacji prezentacji HTTP, DNS HTTPS TLS (SSL) sesji transportowa TCP sieciowa IPv4 łącza danych fizyczna

REQUEST https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content TCP

REQUEST <metoda> <cel żądania> <wersja HTTP> <nagłówek> <nagłówek> <ciało żądania>

REQUEST GET /michalkopacz/zf-apigility/commits?page=4 HTTP/1.1 Host: github.com User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9, image/webp,*/*;q=0.8 Accept-Encoding: gzip, deflate, sdch Accept-Language: pl-pl,pl;q=0.8,en-us;q=0.6,en;q=0.4 Connection: keep-alive Cookie: user_session=61tko8wcdukce;

METODY HTTP GET HEAD POST PUT DELETE CONNECT OPTIONS TRACE

METODY BEZPIECZNE używane tylko dla pobrania informacji o zasobie nie powinny zmieniać stanu danych na serwerze mogą powodować m.in. efekty takie jak logowanie, keszowanie lub podbijanie statystyk

METODY IDEMPOTENTNE wykonanie tego samego żądania wiele razy, ma taki sam efekt po stronie serwera, jak wykonanie pojedynczego żądania

GET żądanie używające GET powinno pobierać tylko dane zasobu i nie powinno powodować zmiany jego stanu

GET bezpieczna idempotentna

POST POST jest używany do wysyłania danych na serwer URL w żądaniu typu POST oznacza zasób, który przetworzy ciało żądania

POST <form action="/zfcampus/zf-apigility/issue_comments" method="post"> <input type="hidden" name="issue" value="74"> <textarea name="comment[body]" id="new_comment_field"> </textarea> <button type="submit">comment</button> </form>

POST nie jest bezpieczna nie jest idempotentna

PUT tworzy nowy zasób określony przez wysłane żądanie jeśli zasób pod URL już istnieje, to modyfikuje jego stan, używając ciała żądania

POST vs PUT POST /blog/1124234/entry/43/comments GET /blog/1124234/entry/43/comments/1 vs PUT /blog/1124234/entry/43/comments/2 GET /blog/1124234/entry/43/comments/2

PUT nie jest bezpieczna idempotentna

DELETE usuwa zasób identyfikowany przez URL

DELETE nie jest bezpieczna idempotentna

POZA RFC 7231 LINK (draft-snell-link-method-11) UNLINK (draft-snell-link-method-11) PATCH (rfc5789) COPY (rfc2518) MOVE (rfc2518)

RESPONSE https://github.com/michalkopacz/zf-apigility/commits?page=4#start-of-content TCP

RESPONSE <wersja HTTP> <status> <uzasadnienie> <nagłówek> <nagłówek> <ciało odpowiedzi>

RESPONSE HTTP/1.1 200 OK Date: Mon, 19 Jan 2015 20:35:12 GMT Server: GitHub.com Cache-Control: no-cache, private Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Transfer-Encoding: chunked <!DOCTYPE html> <html lang="en" class="">...

KODY ODPOWIEDZI 1xx Informacyjne 2xx Sukces 3xx Przekierowanie 4xx Błąd klienta 5xx Błąd serwera

NAJBARDZIEJ ZNANE KODY 200 OK 302 Found 400 Bad Request 404 Not Found 500 Internal Server Error 504 Gateway Timeout

2 Jak działają sesje?

LOGOWANIE

BEZSTANOWOŚĆ HTTP nie przechowuje żadnych informacji o poprzednich transakcjach klienta z serwerem

POST REQUEST POST /session HTTP/1.1 Host: github.com Content-Type: application/x-www-form-urlencoded login=michalkopacz.mk%40gmail.com&password=pass

SESJA W PHP $userid = authenticateuser($_post['login'], $_POST['password']); if ($userid!== null) { session_name('user_session'); session_set_cookie_params(1209600, '/', 'github.com', true, true); session_start(); $_SESSION['userId'] = $userid; header("location: https://github.com/", true, 302); exit; }

DANE SESJI SET UB90l88D5haE {"user_id":"12345"}

PRZEKIEROWANIE HTTP/1.1 302 Found Location: https://github.com/ Set-Cookie: user_session=ub90l88d5hae; path=/; domain=github.com; expires=sun, 08-Feb-2015 13:38:31 GMT; secure; HttpOnly

CIASTECZKA dane trzymane po stronie przeglądarki przeglądarka wysyła ciasteczka w każdym żądaniu HTTP tylko dla domeny na której zostały utworzone github.com lub domen niższego poziomu *.github.com

PO PRZEKIEROWANIU POST / HTTP/1.1 Host: github.com Cookie: user_session=61tko8wcdukce;

3 Jak nie wygenerować tej samej odpowiedzi dwa razy?

STAŁE ZASOBY

BUFOROWANIE ODPOWIEDZI unieważnianie walidacja

UNIEWAŻNIANIE Expires: Sun, 25 Jan 2016 16:56:27 GMT Cache-Control: max-age=3600

NAGŁÓWEK EXPIRES czas na serwerze i czas w przeglądarce musi być zsynchronizowany

PIERWSZY REQUEST GET u/194026?v=3 Host: https://avatars0. githubusercontent.com P R Z E G L Ą D A R K A HTTP/1.1 200 OK Cache-Control: max-age=3600 B U F O R P R Z E G L Ą D A R K I GET u/194026?v=3 Host: https://avatars0. githubusercontent.com S E R W E R HTTP/1.1 200 OK Cache-Control: max-age=3600

PRZED WYGAŚNIĘCIEM GET u/194026?v=3 Host: https://avatars0. githubusercontent.com P R Z E G L Ą D A R K A HTTP/1.1 200 OK Cache-Control: max-age=3600 B U F O R P R Z E G L Ą D A R K I S E R W E R

PO WYGAŚNIĘCIU GET u/194026?v=3 Host: https://avatars0. githubusercontent.com P R Z E G L Ą D A R K A HTTP/1.1 200 OK Cache-Control: max-age=3600 B U F O R P R Z E G L Ą D A R K I GET u/194026?v=3 Host: https://avatars0. githubusercontent.com S E R W E R HTTP/1.1 200 OK Cache-Control: max-age=3600

WYMUSZENIE CZYSZCZENIA Co jeśli użytkownik zmieni avatar? Jak wtedy wymusić aby przeglądarka nie brała avatara z bufora?

WYMUSZENIE CZYSZCZENIA Zmieńmy url avatara. https://avatars0.githubusercontent.com/u/194026?v=4

UNIEWAŻNIANIE unieważnianie pozwala nam na skalowanie aplikacji, dzięki temu, że mniej żądań dochodzi do serwera

WALIDACJA Last-Modified / If-Modified-Since 1.0 Etag / If-None-Match 1.1

PIERWSZY REQUEST GET u/194026 Host: https://avatars0. githubusercontent.com P R Z E G L Ą D A R K A HTTP/1.1 200 OK Etag: abcdefg B U F O R P R Z E G L Ą D A R K I GET u/194026 Host: https://avatars0. githubusercontent.com S E R W E R HTTP/1.1 200 OK Etag: abcdefg

ZASÓB SIĘ NIE ZMIENIŁ GET u/194026 Host: https://avatars0. githubusercontent.com P R Z E G L Ą D A R K A HTTP/1.1 200 OK Etag: abcdefg B U F O R P R Z E G L Ą D A R K I GET u/194026 Host: https://avatars0. githubusercontent.com If-None-Match: abcdefg S E R W E R HTTP/1.1 304 Not Modified

ZASÓB ZOSTAŁ ZMIENIONY GET u/194026 Host: https://avatars0. githubusercontent.com P R Z E G L Ą D A R K A HTTP/1.1 200 OK Etag: 1234567 B U F O R P R Z E G L Ą D A R K I GET u/194026 Host: https://avatars0. githubusercontent.com If-None-Match: abcdefg S E R W E R HTTP/1.1 200 OK Etag: 1234567

WALIDACJA oszczędza łącze danych

KIEDY NIE DA SIĘ BUFOROWAĆ? metody inne niż GET i HEAD niektóre nagłówki, m.in. Set-Cookie i Cookie kody odpowiedzi inne niż 200, 300, 301, 410

4 Jak wysłać żądanie HTTP z przeglądarki bez przeładowania strony?

PISZEMY KOMUNIKATOR

XMLHttpRequest obiekt w JavaScript, wystawiony przez przeglądarki, umożliwiający wysyłanie żądań HTTP(S)

POBIERANIE WIADOMOŚCI function checkmessages() { var xhr = new XMLHttpRequest(); xhr.open( 'GET', 'https://mysite.pl/chat/pull?viewer_uid=6237374' ); xhr.onload = function(e) {... }; xhr.send(); } checkmessages();

REQUEST GET chat/pull?viewer_uid=6237374 HTTP/1.1 Host: mysite.pl Accept: */* Accept-Encoding: gzip, deflate, sdch Cookie: session_id=61tko8wcdukce; X-Requested-With: XMLHttpRequest Większość bibliotek do JavaScript-u dodaje ten nagłówek, gdy wysyłane jest żądanie HTTP, ale nie jest to natywny mechanizm XMLHttpRequest.

Xnagłówek nie opisany w żądnym standardzie "experimental" lub "extension" uznany za przestarzały w rfc6648

X-Requested-With function checkmessages() { var xhr = new XMLHttpRequest(); xhr.setrequestheader('x-requested-with', 'XMLHttpRequest'); xhr.open( 'GET', 'https://mysite.pl/chat/pull?viewer_uid=6237374' ); xhr.onload = function(e) {... }; xhr.send(); } checkmessages();

RESPONSE HTTP/1.1 200 OK Server: mysite.pl Content-Type: application/json; charset=utf-8 [ {"message": "Jak się masz?", "user_id": 2323}, {"message": "Co to jest HTTP?", "user_id": 322322} ]

JSON tekstowy format wymiany danych składania oparta jest na języku JavaScript istnieje wiele parserów formatu JSON w różnych językach

TYPY null Number 12.44 String "Co to jest HTTP?" Boolean true false Array [1, false, "hi"] Object {"foo": "bar"}

parsowanie JSON a function checkmessages() { var xhr = new XMLHttpRequest(); xhr.setrequestheader('x-requested-with', 'XMLHttpRequest'); xhr.open( 'GET', 'https://mysite.pl/chat/pull?viewer_uid=6237374' ); xhr.onload = function(e) { var messages = JSON.parse(e.target.response);... }; xhr.send(); } checkmessages();

Negocjacja kontentu (Content negotiation)

TYP MIME text/css text/html text/plain image/png image/jpeg audio/mpeg video/quicktime application/xml application/json application/javascript

NAGŁÓWKI Accept headers: Accept Accept-Language Accept-Charset Accept-Encoding

REQUEST GET /michalkopacz/zf-apigility/commits?page=4 HTTP/1.1 Host: github.com Accept: text/html,application/xhtml+xml,application/xml;q=0.9, image/webp,*/*;q=0.8 Accept-Encoding: gzip, deflate, sdch Accept-Language: pl-pl,pl;q=0.8,en-us;q=0.6,en;q=0.4 Accept-Charset: utf-8

NAGŁÓWKI Content headers: Content-Type Content-Language Content-Type Content-Encoding

REQUEST POST /chat/push HTTP/1.1 Host: mysite.pl Content-Type: application/json {"message": "Dobrze, a ty?", "user_id": 2323}

REQUEST POST /session HTTP/1.1 Host: github.com Content-Type: application/x-www-form-urlencoded login=michalkopacz.mk%40gmail.com&password=pass

ODCZYT ŻĄDANIA W PHP //application/json $message = json_decode(file_get_contents('php://input')); //application/x-www-form-urlencoded $credentials = urldecode(file_get_contents('php://input')); list($login, $password) = explode('&', $credentials); $login = $_POST['login']; $password = $_POST['password'];

RESPONSE HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Content-Encoding: gzip HTTP/1.1 200 OK Content-Type: text/css Content-Encoding: gzip

POOLING function checkmessages() { var xhr = new XMLHttpRequest(); xhr.setrequestheader('x-requested-with', 'XMLHttpRequest'); xhr.open( 'GET', 'https://mysite.pl/chat/pull?viewer_uid=6237374' ); xhr.onload = function(e) { var messages = JSON.parse(e.target.response);... }; xhr.send(); } setinterval(function() { checkmessages() }, 60000);

LONG POOLING function checkmessages() { var xhr = new XMLHttpRequest(); xhr.setrequestheader('x-requested-with', 'XMLHttpRequest'); xhr.timeout = 60000; xhr.open( 'GET', 'https://mysite.pl/chat/pull?viewer_uid=6237374' ); xhr.onload = function(e) { var messages = JSON.parse(e.target.response);... checkmessages(); }; xhr.send(); } checkmessages();

WEBSOCKET umożliwia dwukierunkową transmisję danych używa schematu ws: i wss:

5 Jak wysyłać żądania i odbierać odpowiedzi HTTP?

Chrome DevTools

PHP fsockopen file_get_contents curl Zend\Http Guzzle

DZIĘKUJE