Upgrade to Pro — share decks privately, control downloads, hide ads and more …

HttpFoundation – An excursion in a Symfony2 com...

HttpFoundation – An excursion in a Symfony2 component

In this presentation I talk about one of the most basic components of the Symfony2 framework, HttpFoundation, and how you can use it.

Magnus Nordlander

February 21, 2013

Transcript

35 slides
  1. Who am I • Magnus Nordlander • Developer at E-butik.se

    • ~6 years of Symfony experience • SensioLabs Certified Symfony Developer
  2. HTTP • Created by Tim Berners-Lee back in ’91 •

    Current version is HTTP 1.1, standardized in ’99 in IETF RFC 2616 • Single best advice: You work with HTTP every day. Read RFC 2616.
  3. An HTTP request/response GET /foo/baz HTTP/1.1 Host: www.example.com HTTP/1.1 200

    OK Date: Mon, 18 Feb 2013 20:38:34 GMT Content-Length: 12 Content-Type: text/plain Connection: close Hello world!
  4. Another request/response POST /?foo=quux HTTP/1.1 Host: www.example.com Content-Type: application/x-www-form- urlencoded

    Content-Length: 9 bar=xyzzy HTTP/1.1 200 OK Content-Length: 21 Content-Type: text/plain Connection: close Foo: quux, Bar: xyzzy
  5. Another request/response POST /?foo=quux HTTP/1.1 Host: www.example.com Content-Type: application/x-www-form- urlencoded

    Content-Length: 9 bar=xyzzy HTTP/1.1 200 OK Content-Length: 21 Content-Type: text/plain Connection: close Foo: quux, Bar: xyzzy Symfony\Component\HttpFoundation\Request Symfony\Component\HttpFoundation\Response
  6. As code… <?php $foo = $_GET[‘foo’]; $bar = $_POST[‘bar’]; header(‘Content-Type:

    text/plain’); echo sprintf(“Foo: %s, Bar: %s”, $foo, $bar); <?php use Symfony\Component\HttpFoundation \Request; use Symfony\Component\HttpFoundation \Response; $request = Request::createFromGlobals(); $foo = $request->query->get(‘foo’); $bar = $request->request->get(‘bar’); $response = new Response( 200, sprintf(“Foo: %s, Bar: %s”, $foo, $bar), [‘Content-Type’ => ‘text/plain’]); $response->send();
  7. Yes

  8. Let’s look at the code <?php use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response;

    $request = Request::createFromGlobals(); $foo = $request->query->get(‘foo’); $bar = $request->request->get(‘foo’); $response = new Response(200, sprintf(“Foo: %s, Bar: %s”, $foo, $bar)); $response->send();
  9. Let’s look at the code <?php use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response;

    $request = Request::createFromGlobals(); $foo = $request->query->get(‘foo’); $bar = $request->request->get(‘foo’); $response = new Response(200, sprintf(“Foo: %s, Bar: %s”, $foo, $bar)); $response->send(); Encapsulating the superglobals: great for testing, reduces hidden dependencies
  10. Let’s look at the code <?php use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response;

    $request = Request::createFromGlobals(); $foo = $request->query->get(‘foo’); $bar = $request->request->get(‘foo’); $response = new Response(200, sprintf(“Foo: %s, Bar: %s”, $foo, $bar)); $response->send(); Because these come from an object, easily fakable in tests. Additional features like default values, fetching by path.
  11. Let’s look at the code <?php use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response;

    $request = Request::createFromGlobals(); $foo = $request->query->get(‘foo’); $bar = $request->request->get(‘foo’); $response = new Response(200, sprintf(“Foo: %s, Bar: %s”, $foo, $bar)); $response->send(); Entire response encapsulated: Great for functional tests. No output (nor headers) until send. Processable by listener, middleware etc.
  12. Edge case handling <?php // Let’s get the client IP

    address $ip = $_SERVER[‘REMOTE_ADDR’]; // Right?
  13. Edge case handling • One word: Proxy • Requests through

    proxies originate through the proxy IP • Most send the X-Forwarded-For header, with the client IP • And yes, you want proxy support (for performance reasons)
  14. Edge case handling <?php // Let’s get the client IP

    address if (isset($_SERVER[‘X_FORWARDED_FOR’])) { // This should handle those pesky proxies $ip = $_SERVER[‘X_FORWARDED_FOR’]; } else { $ip = $_SERVER[‘REMOTE_ADDR’]; }
  15. Edge case handling • Now we have a security flaw

    • Any client can send the X-Forwarded-For header, spoofing its IP • Only trusted proxies should be allowed to do that
  16. Edge case handling <?php // Let’s get the client IP

    address $originatingIp = $_SERVER[‘REMOTE_ADDR’]; $clientIp = isset($_SERVER[‘X_FORWARDED_FOR’]) ? $_SERVER[‘X_FORWARDED_FOR’] : null; $trustedProxies = [‘10.0.0.1’, ‘10.0.0.2’]; if (in_array($originatingIp, $trustedProxies) && $clientIp) { return $clientIp; } else { return $originatingIp; }
  17. Edge case handling • That’s not quite it though... •

    You can have multiple upstream proxies, and they send a comma separated list of IP addresses. • Also, not all proxies use X-Forwarded-For, because that’s never been standardized • Are you getting a headache yet? Let’s look at how to do it with HttpFoundation instead.
  18. Edge case handling <?php // Let’s get the client IP

    address use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $request = Request::createFromGlobals(); Request::setTrustedProxies([‘10.0.0.1’, ‘10.0.0.2’]); // Other header name? // Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, ‘Forwarded-For’); $ip = $request->getClientIp();
  19. The Request class • Can be created from Superglobals, or

    manually • HTTP based, not CGI based • HTTP based methods and properties
  20. The Response class • Also HTTP based • Common HTTP

    Header “clusters” have specific methods, e.g. caching • public function __construct($content = '', $status = 200, $headers = [])
  21. Parameter bags • Like PHP arrays, but better • Defaults

    handling • Deep get syntax • Specialized subclasses like HeaderBag and ServerBag
  22. What else is there? • HTTP caching support (expiration and

    validation) • Sessions • Storage abstraction • Flash parameters • Cookies
  23. HttpKernelInterface • Housed in the HttpKernel component • One of

    the most important interfaces in the Symfony2 ecosystem • public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true); • Returns Response
  24. HttpKernelInterface • Foundation for the Request/Response paradigm of Symfony2 •

    Because of this interface, all web stacks implementing HttpKernelInterface is inherently compatible!

More Decks by Magnus Nordlander

Other Decks in Programming