4
4
5
5
use Clue \React \Block ;
6
6
use React \EventLoop \Factory ;
7
+ use React \Socket \ConnectionInterface ;
7
8
use React \Socket \Connector ;
9
+ use React \Socket \ConnectorInterface ;
8
10
use React \Socket \TcpServer ;
9
11
10
12
class FunctionalConnectorTest extends TestCase
11
13
{
12
- const TIMEOUT = 1.0 ;
14
+ const TIMEOUT = 30.0 ;
15
+
16
+ private $ ipv4 ;
17
+ private $ ipv6 ;
13
18
14
19
/** @test */
15
20
public function connectionToTcpServerShouldSucceedWithLocalhost ()
@@ -29,4 +34,172 @@ public function connectionToTcpServerShouldSucceedWithLocalhost()
29
34
$ connection ->close ();
30
35
$ server ->close ();
31
36
}
37
+
38
+ /**
39
+ * @test
40
+ * @group internet
41
+ */
42
+ public function connectionToRemoteTCP4n6ServerShouldResultInOurIP ()
43
+ {
44
+ $ loop = Factory::create ();
45
+
46
+ $ connector = new Connector ($ loop , array ('happy_eyeballs ' => true ));
47
+
48
+ $ ip = Block \await ($ this ->request ('dual.tlund.se ' , $ connector ), $ loop , self ::TIMEOUT );
49
+
50
+ $ this ->assertSame ($ ip , filter_var ($ ip , FILTER_VALIDATE_IP , FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 ), $ ip );
51
+ }
52
+
53
+ /**
54
+ * @test
55
+ * @group internet
56
+ */
57
+ public function connectionToRemoteTCP4ServerShouldResultInOurIP ()
58
+ {
59
+ if ($ this ->ipv4 () === false ) {
60
+ // IPv4 not supported on this system
61
+ return ;
62
+ }
63
+
64
+ $ loop = Factory::create ();
65
+
66
+ $ connector = new Connector ($ loop , array ('happy_eyeballs ' => true ));
67
+
68
+ $ ip = Block \await ($ this ->request ('ipv4.tlund.se ' , $ connector ), $ loop , self ::TIMEOUT );
69
+
70
+ $ this ->assertSame ($ ip , filter_var ($ ip , FILTER_VALIDATE_IP , FILTER_FLAG_IPV4 ), $ ip );
71
+ $ this ->assertFalse (filter_var ($ ip , FILTER_VALIDATE_IP , FILTER_FLAG_IPV6 ), $ ip );
72
+ }
73
+
74
+ /**
75
+ * @test
76
+ * @group internet
77
+ */
78
+ public function connectionToRemoteTCP6ServerShouldResultInOurIP ()
79
+ {
80
+ if ($ this ->ipv6 () === false ) {
81
+ // IPv6 not supported on this system
82
+ return ;
83
+ }
84
+
85
+ $ loop = Factory::create ();
86
+
87
+ $ connector = new Connector ($ loop , array ('happy_eyeballs ' => true ));
88
+
89
+ $ ip = Block \await ($ this ->request ('ipv6.tlund.se ' , $ connector ), $ loop , self ::TIMEOUT );
90
+
91
+ $ this ->assertFalse (filter_var ($ ip , FILTER_VALIDATE_IP , FILTER_FLAG_IPV4 ), $ ip );
92
+ $ this ->assertSame ($ ip , filter_var ($ ip , FILTER_VALIDATE_IP , FILTER_FLAG_IPV6 ), $ ip );
93
+ }
94
+
95
+ /**
96
+ * @test
97
+ * @group internet
98
+ *
99
+ * @expectedException \RuntimeException
100
+ * @expectedExceptionMessageRegExp /Connection to ipv6.tlund.se:80 failed/
101
+ */
102
+ public function tryingToConnectToAnIPv6OnlyHostWithOutHappyEyeBallsShouldResultInFailure ()
103
+ {
104
+ $ loop = Factory::create ();
105
+
106
+ $ connector = new Connector ($ loop , array ('happy_eyeballs ' => false ));
107
+
108
+ Block \await ($ this ->request ('ipv6.tlund.se ' , $ connector ), $ loop , self ::TIMEOUT );
109
+ }
110
+
111
+ /**
112
+ * @test
113
+ * @group internet
114
+ *
115
+ * @expectedException \RuntimeException
116
+ * @expectedExceptionMessageRegExp /Connection to tcp:\/\/193.15.228.195:80 failed:/
117
+ */
118
+ public function connectingDirectlyToAnIPv4AddressShouldFailWhenIPv4IsntAvailable ()
119
+ {
120
+ if ($ this ->ipv4 () === true ) {
121
+ // IPv4 supported on this system
122
+ throw new \RuntimeException ('Connection to tcp://193.15.228.195:80 failed: ' );
123
+ }
124
+
125
+ $ loop = Factory::create ();
126
+
127
+ $ connector = new Connector ($ loop );
128
+
129
+ $ host = current (dns_get_record ('ipv4.tlund.se ' , DNS_A ));
130
+ $ host = $ host ['ip ' ];
131
+ Block \await ($ this ->request ($ host , $ connector ), $ loop , self ::TIMEOUT );
132
+ }
133
+
134
+ /**
135
+ * @test
136
+ * @group internet
137
+ *
138
+ * @expectedException \RuntimeException
139
+ * @expectedExceptionMessageRegExp /Connection to tcp:\/\/\[2a00:801:f::195\]:80 failed:/
140
+ */
141
+ public function connectingDirectlyToAnIPv6AddressShouldFailWhenIPv6IsntAvailable ()
142
+ {
143
+ if ($ this ->ipv6 () === true ) {
144
+ // IPv6 supported on this system
145
+ throw new \RuntimeException ('Connection to tcp://[2a00:801:f::195]:80 failed: ' );
146
+ }
147
+
148
+ $ loop = Factory::create ();
149
+
150
+ $ connector = new Connector ($ loop );
151
+
152
+ $ host = current (dns_get_record ('ipv6.tlund.se ' , DNS_AAAA ));
153
+ $ host = $ host ['ipv6 ' ];
154
+ $ host = '[ ' . $ host . '] ' ;
155
+ $ ip = Block \await ($ this ->request ($ host , $ connector ), $ loop , self ::TIMEOUT );
156
+
157
+ $ this ->assertFalse (filter_var ($ ip , FILTER_VALIDATE_IP , FILTER_FLAG_IPV4 ), $ ip );
158
+ $ this ->assertSame ($ ip , filter_var ($ ip , FILTER_VALIDATE_IP , FILTER_FLAG_IPV6 ), $ ip );
159
+ }
160
+
161
+ /**
162
+ * @internal
163
+ */
164
+ public function parseIpFromPage ($ body )
165
+ {
166
+ $ ex = explode ('title="Look up on bgp.he.net"> ' , $ body );
167
+ $ ex = explode ('< ' , $ ex [1 ]);
168
+
169
+ return $ ex [0 ];
170
+ }
171
+
172
+ private function request ($ host , ConnectorInterface $ connector )
173
+ {
174
+ $ that = $ this ;
175
+ return $ connector ->connect ($ host . ':80 ' )->then (function (ConnectionInterface $ connection ) use ($ host ) {
176
+ $ connection ->write ("GET / HTTP/1.1 \r\nHost: " . $ host . "\r\n\r\n" );
177
+
178
+ return \React \Promise \Stream \buffer ($ connection );
179
+ })->then (function ($ response ) use ($ that ) {
180
+ return $ that ->parseIpFromPage ($ response );
181
+ });
182
+ }
183
+
184
+ private function ipv4 ()
185
+ {
186
+ if ($ this ->ipv4 !== null ) {
187
+ return $ this ->ipv4 ;
188
+ }
189
+
190
+ $ this ->ipv4 = !!@file_get_contents ('http://ipv4.tlund.se/ ' );
191
+
192
+ return $ this ->ipv4 ;
193
+ }
194
+
195
+ private function ipv6 ()
196
+ {
197
+ if ($ this ->ipv6 !== null ) {
198
+ return $ this ->ipv6 ;
199
+ }
200
+
201
+ $ this ->ipv6 = !!@file_get_contents ('http://ipv6.tlund.se/ ' );
202
+
203
+ return $ this ->ipv6 ;
204
+ }
32
205
}
0 commit comments