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

HttpFoundation – An excursion in a Symfony2 component

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
Tweet

More Decks by Magnus Nordlander

Other Decks in Programming

Transcript

  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!