#!/usr/bin/perl use v5.10; say ' This script explores how Plack::Request and CGI.pm interact with the global %ENV. '; say; say ' Does changing the globah hash after the object is created modify the object '; say ' behavior? Do changes to the object cause the external environment to be '; say ' modified? '; say; say ' Run it and press as prompted to see. Some of the answers for both'; say ' CGI.pm and Plack::Request may surprise you.'; use CGI; use Plack::Request; use strict; $ENV{REMOTE_ADDR} = "initial global value"; say; say; say 'Create objects with CGI->new() and Plack::Request->new(\%ENV)'; my $q = CGI->new; my $r = Plack::Request->new(\%ENV); say; say 'Reality Check: Both CGI.pm and Plack::Request pick up REMOTE_ADDR from the environment:'; say ' $ENV{REMOTE_ADDR} = "initial global value"; '; say ' CGI.pm, $q->remote_addr: '.$q->remote_addr; say ' Plack::Request: $r->address: '.$r->address; $ENV{REMOTE_ADDR} = 'changed global value after object was created.'; say; say 'Now, modify the global %ENV hash after the object is created.'; say ' ( press enter to see the results )'; <>; say ' $ENV{REMOTE_ADDR} = "changed global value after object was created."; '; say ' CGI.pm, $q->remote_addr: '.$q->remote_addr; say ' Plack::Request: $r->address: '.$r->address; say; say 'While isolation might be hoped for, they both picked up the changes.'; say ' ( press enter to continue. )'; <>; say; say 'Another experiment is to modify the internal environment hash. '; say 'Plack::Request allows this, but CGI.pm does not.'; say 'Will it cause the internal state to be modified? What about the global %ENV?'; $r->env->{REMOTE_ADDR} = 'modified through internal hash'; say ' ( press enter to see the results )'; <>; say ' $r->env->{REMOTE_ADDR} = "modified via internal environment."; '; say ' Plack::Request, $r->address: '.$r->address; say ' $ENV{REMOTE_ADDR}: '.$ENV{REMOTE_ADDR}; say; say 'Perhaps surprisingly, Plack::Request is modifying the global environment through what'; say 'appears to be a private copy of it.'; say; say 'The Plack::Request documentation hints at this behavior in the docs for env():'; say ' "This is a reference, so writing to this environment passes through'; say ' during the whole PSGI request/response cycle."'; say; say 'I think this could be even more explicit that "passes through" means that'; say 'the hash passed in modified by reference.'; say ' (press enter to continue);'; <>; say 'Now let\'s try another experiment, using a syntax to pass in a copy'; say 'of the environment to Plack::Request: Plack::Request->new({ %ENV })'; say 'This has no equivalent in CGI.pm, but they are still useful to compare'; say 'to see this allows Plack::Request to achieve a different behavior.'; $ENV{REMOTE_ADDR} = 'initial global value'; $q = CGI->new; $r = Plack::Request->new({ %ENV }); say ' $ENV{REMOTE_ADDR} = "initial global value";'; say ' $q = CGI->new; '; say ' $r = Plack::Request->new({ %ENV }); '; say ' CGI.pm, $q->remote_addr: '.$q->remote_addr; say ' Plack::Request: $r->address: '.$r->address; say ' ( press enter to continue. )'; <>; say; $ENV{REMOTE_ADDR} = 'changed global value after object was created'; say; say 'Now test again changing the external environment.'; say ' ( press enter to see the results )'; <>; say ' $ENV{REMOTE_ADDR} = "changed global value after object was created"; '; say ' CGI.pm, $q->remote_addr: '.$q->remote_addr; say ' Plack::Request: $r->address: '.$r->address; say; say 'Now Plack::Request is \'protecting\' the internal object from global changes.'; say ' ( press enter to continue. )'; <>; say; say 'Now, modify Plack::Request\'s internal environment (no CGI.pm equivalent).'; $r->env->{REMOTE_ADDR} = 'modified via internal environment.'; say; say 'Let\'s check if this changed the value internally and externally:'; # PSGI docs say: 'The application is free to modify the environment.' say ' ( press enter to see the results )'; <>; say ' $r->env->{REMOTE_ADDR} = "modified via internal environment."; '; say ' Plack::Request, $r->address: '.$r->address; say ' $ENV{REMOTE_ADDR}: '.$ENV{REMOTE_ADDR}; say; say 'So, now Plack::Request did not modify the global environment.'; say; say 'That\'s all. Were the answers what you expected?'; say; say 'If you found this interesting, you also be interested to review my'; say 'tests for the parameter related methods in Plack::Request'; say 'They show inconsistency there about their read/write nature.'; say 'https://github.com/markstos/Plack/commit/0aefed0900eeb2281eb0fe925bd18dfd60076b1e'; # written by Mark Stosberg , 2011. Public domain.