Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
The HttpKernelInterface is a lie
Search
Igor Wiedler
May 23, 2013
Programming
2.6k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
The HttpKernelInterface is a lie
Igor Wiedler
May 23, 2013
More Decks by Igor Wiedler
See All by Igor Wiedler
Redis Bedtime Stories
igorw
1
370
Wide Event Analytics (LISA19)
igorw
4
950
a day in the life of a request
igorw
0
170
production: an owner's manual
igorw
0
200
The Power of 2
igorw
0
340
LISP 1.5 Programmer's Manual: A Dramatic Reading
igorw
0
490
The Moral Character of Software
igorw
1
320
interdisciplinary computing (domcode)
igorw
0
330
miniKanren (clojure berlin)
igorw
1
340
Other Decks in Programming
See All in Programming
自動化したのに回らない テスト運用の壁―AI時代の品質責任と生産性
mfunaki
0
170
Laravelで学ぶ Webアプリケーションチューニング入門/web_application_tuning_101
hanhan1978
4
1.8k
Claude Code全社展開のためにやったことn選~プラグイン302個・コミッター271人を支えるために~
kenchan
5
1.5k
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
500
AIが無かった頃の素敵な出会いの話
codmoninc
1
430
AWS CDK を「作」ってみた 〜フルスクラッチで見えた CDK の裏側〜 / aws-cdk-from-scratch
gotok365
3
2.8k
属人化した知識を、 AIが辿れる地図にする
pkshadeck
PRO
1
170
komatsuna「分散システムにおけるバグ分析手法」
komatsunaqa
0
260
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
480
いまどきの Codex で開発する visionOS アプリの開発スタイルについて
karad
0
140
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
1
850
OpenSpecのproposalにbrainstormingを持たせてみた
tigertora7571
1
230
Featured
See All Featured
Claude Code のすすめ
schroneko
67
230k
Done Done
chrislema
186
16k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
45k
Accessibility Awareness
sabderemane
1
180
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
Thoughts on Productivity
jonyablonski
76
5.3k
Un-Boring Meetings
codingconduct
0
390
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
630
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.5k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
400
The agentic SEO stack - context over prompts
schlessera
0
860
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.2k
Transcript
the HttpKernelInterface is a lie
@igorwesome
None
“Interface” Protocol Communication Message passing
Catherine Please, from The Noun Project
Paulo Sá Ferreira - Purple Matter, from The Noun Project
hi!
None
10010101110100100
1001010111010010000110101 Massimiliano Mauro, from The Noun Project
Sergey Shmidt, from The Noun Project aloha!
yay!
00101000011101100102
None
None
None
None
None
10010111001010001011
1234 4321
foo bar baz foo baz Patrick n Hawaii, from The
Noun Project
foo moo Anuar Zhumaev, from The Noun Project
find src -name '*.php' | grep -iv tests | cut
-f2- -d/ | cut -f1 -d\. | awk '{ print length, $0 }' | sort -n | tr / \\ ;
Tim Boelaars, from The Noun Project
None
nc
/\_/\ / 0 0 \ ====v==== \ W / |
| _ / ___ \ / / / \ \ | (((-----)))-' / ( ___ \__.=|___E /
None
data Dmitry Baranovskiy, from The Noun Project
xinetd
None
/etc/xinet.d/<service> service <service> { disable = no socket_type = stream
protocol = tcp user = <user> wait = no server = /usr/local/bin/<program> }
/etc/xinet.d/fortune service fortune { disable = no socket_type = stream
protocol = tcp user = xinetd wait = no server = /usr/local/bin/fortune }
#!/bin/bash fortune | cowsay
$ nc <host> 7777
$ nc <host> 7777 ______________________________________ < Eat right, stay fit,
and die anyway. > -------------------------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
/etc/xinet.d/cowsay service cowsay { disable = no socket_type = stream
protocol = tcp user = xinetd wait = no server = /usr/games/cowsay }
$ echo 'moo' | nc <host> 7778
$ echo 'moo' | nc <host> 7778 _____ < moo
> ----- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
#!/usr/bin/php <?php while (!feof(STDIN)) { echo transform(fgets(STDIN)); }
cgi
The Common Gateway Interface (CGI) [22] allows an HTTP [1],
[4] server and a CGI script to share responsibility for responding to client requests. RFC 3875
xinetd tcp http httpd
http httpd script cgi
script env vars data headers data
GET / HTTP/1.1 Host: igor.io Accept: */* REQUEST_METHOD = GET
PATH_INFO = / HTTP_HOST = igor.io HTTP_ACCEPT = */* SERVER_NAME = igor.io =>
Content-Type: text/html <!DOCTYPE html> <html> ... </html>
curl => inetd | web | cgi
fcgi
script
sockets are the new pipes
• 1991: HTTP • 1993: CGI • 1995: PHP •
1996: FastCGI
• 1997: Java Servlet • 2003: Python WSGI • 2007:
Ruby Rack • 2009: Perl PSGI • 2011: Symfony2 HttpKernelInterface
rack
class HelloWorld def call(env) [ 200, {"Content-Type" => "text/plain"}, ["Hello
world!"] ] end end
function helloWorld(array $env) { return [ 200, ["Content-Type" => "text/plain"],
["Hello world!"], ]; }
sapi
$_SERVER header echo exit
HttpKernelInterface
sapi kernel
tcp websocket HTTP/1.1 <soap> {“JSON”}
“legacy” apps: it’s all great until exit;
myths:
myths: caching
myths: caching (use varnish)
myths: caching (use varnish) functional tests
CgiHttpKernel adapter from kernel to cgi functional test “legacy” apps
kernel CGI
kernel CGI anything!
export SCRIPT_NAME=/app.php export SCRIPT_FILENAME=/var/www/app.php export PATH_INFO=/foo export QUERY_STRING="bar=baz&qux=quux" export REQUEST_URI=/foo
export REQUEST_METHOD=GET php-cgi app.php
$kernel = new CgiHttpKernel(__DIR__.'/app'); $request = Request::create('/index.php'); $response = $kernel->handle($request);
var_dump($response->getContent());
use Symfony\Component\HttpKernel\Client; $client = new Client($kernel); $crawler = $client->request('GET', '/index.php');
caution: it’s slow (but could be optimized)
Where is the value?
REQ REP
fcgi roles
authorizer httpd responder filter
rack middlewares
class EmptyDecorator def initialize(app) @app = app end def call(env)
@app.call(env) end end
class CommonLogger def initialize(app, logger=nil) @app = app @logger =
logger end def call(env) began_at = Time.now response = @app.call(env) status, header, _ = response log(env, status, header, began_at) response end private def log(env, status, header, began_at) ... end end
class CommonLogger def initialize(app, logger=nil) @app = app @logger =
logger end def call(env) began_at = Time.now response = @app.call(env) status, header, _ = response log(env, status, header, began_at) response end private def log(env, status, header, began_at) ... end end
class CommonLogger def initialize(app, logger=nil) @app = app @logger =
logger end def call(env) began_at = Time.now response = @app.call(env) status, header, _ = response log(env, status, header, began_at) response end private def log(env, status, header, began_at) ... end end
class CommonLogger def initialize(app, logger=nil) @app = app @logger =
logger end def call(env) began_at = Time.now response = @app.call(env) status, header, _ = response log(env, status, header, began_at) response end private def log(env, status, header, began_at) ... end end
class CommonLogger def initialize(app, logger=nil) @app = app @logger =
logger end def call(env) began_at = Time.now response = @app.call(env) status, header, _ = response log(env, status, header, began_at) response end private def log(env, status, header, began_at) ... end end
HttpKernel middlewares
$app = new CallableHttpKernel(function ($request) { return new Response('Hello World!');
});
class Logger implements HttpKernelInterface { private $app; private $logger; public
function __construct(HttpKernelInterface $app, LoggerInterface $logger) { $this->app = $app; $this->logger = $logger; } public function handle(Request $request, ...) { $response = $this->app->handle($request, $type, $catch); $this->log($request, $response); return $response; } private function log(Request $request, Response $response) { ... } }
use Symfony\Component\HttpKernel\HttpCache\HttpCache; use Symfony\Component\HttpKernel\HttpCache\Store; $app = new HttpCache( $app, new
Store(__DIR__.'/cache') );
use Symfony\Component\HttpKernel\HttpCache\HttpCache; use Symfony\Component\HttpKernel\HttpCache\Store; $app = new HttpCache( $app, new
Store(__DIR__.'/cache') ); use varnish!
App Logger Authentication Session
None
CHH simensen igorw
class Foo implements HttpKernelInterface { private $app; public function __construct(HttpKernelInterface
$app) { $this->app = $app; } public function handle(Request $request, ...) { $response = $this->app->handle($request, $type, $catch); return $response; } } 1 2 3
UrlMap $blog = new Silex\Application(); $blog->get('/', function () { return
'This is the blog!'; }); $app = new Stack\UrlMap($app, [ '/blog' => $blog, ]);
Session $app = new CallableHttpKernel(function ($request) { $session = $request->getSession();
... }); $app = new Stack\Session($app);
OAuth $app = new Stack\OAuth($app, [ 'key' => 'foo', 'secret'
=> 'bar', 'callback_url' => 'http://localhost:8080/auth/verify', 'success_url' => '/', 'failure_url' => '/auth', ]); $app = new Stack\Session($app);
OAuth $app = new CallableHttpKernel(function ($request) { $token = $request->attributes->get('oauth.token');
if (!$token) { return new RedirectResponse('/auth'); } $params = $token->getExtraParams(); return sprintf('Welcome @%s!', $params['screen_name']); });
Composition!
$stack = (new Stack\Builder()) ->push('Stack\Session') ->push('Stack\OAuth', [...]) ->push('Foo'); $app =
$stack->resolve($app);
It doesn’t stop there
• Authentication • Debug toolbar • Injected routes • Signed
cookies • Asset management • Force SSL • Error handling
Choose wisely
Michael Rowe, from The Noun Project
• joind.in/8666 • stackphp.com • @stackphp • @igorwesome • github.com/igorw/CgiHttpKernel