http_test.php 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. <?php
  2. // $Id: http_test.php 1782 2008-04-25 17:09:06Z pp11 $
  3. require_once(dirname(__FILE__) . '/../autorun.php');
  4. require_once(dirname(__FILE__) . '/../encoding.php');
  5. require_once(dirname(__FILE__) . '/../http.php');
  6. require_once(dirname(__FILE__) . '/../socket.php');
  7. require_once(dirname(__FILE__) . '/../cookies.php');
  8. Mock::generate('SimpleSocket');
  9. Mock::generate('SimpleCookieJar');
  10. Mock::generate('SimpleRoute');
  11. Mock::generatePartial(
  12. 'SimpleRoute',
  13. 'PartialSimpleRoute',
  14. array('createSocket'));
  15. Mock::generatePartial(
  16. 'SimpleProxyRoute',
  17. 'PartialSimpleProxyRoute',
  18. array('createSocket'));
  19. class TestOfDirectRoute extends UnitTestCase {
  20. function testDefaultGetRequest() {
  21. $socket = new MockSimpleSocket();
  22. $socket->expectAt(0, 'write', array("GET /here.html HTTP/1.0\r\n"));
  23. $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n"));
  24. $socket->expectAt(2, 'write', array("Connection: close\r\n"));
  25. $socket->expectCallCount('write', 3);
  26. $route = new PartialSimpleRoute();
  27. $route->setReturnReference('createSocket', $socket);
  28. $route->__construct(new SimpleUrl('http://a.valid.host/here.html'));
  29. $this->assertSame($route->createConnection('GET', 15), $socket);
  30. }
  31. function testDefaultPostRequest() {
  32. $socket = new MockSimpleSocket();
  33. $socket->expectAt(0, 'write', array("POST /here.html HTTP/1.0\r\n"));
  34. $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n"));
  35. $socket->expectAt(2, 'write', array("Connection: close\r\n"));
  36. $socket->expectCallCount('write', 3);
  37. $route = new PartialSimpleRoute();
  38. $route->setReturnReference('createSocket', $socket);
  39. $route->__construct(new SimpleUrl('http://a.valid.host/here.html'));
  40. $route->createConnection('POST', 15);
  41. }
  42. function testGetWithPort() {
  43. $socket = new MockSimpleSocket();
  44. $socket->expectAt(0, 'write', array("GET /here.html HTTP/1.0\r\n"));
  45. $socket->expectAt(1, 'write', array("Host: a.valid.host:81\r\n"));
  46. $socket->expectAt(2, 'write', array("Connection: close\r\n"));
  47. $socket->expectCallCount('write', 3);
  48. $route = new PartialSimpleRoute();
  49. $route->setReturnReference('createSocket', $socket);
  50. $route->__construct(new SimpleUrl('http://a.valid.host:81/here.html'));
  51. $route->createConnection('GET', 15);
  52. }
  53. function testGetWithParameters() {
  54. $socket = new MockSimpleSocket();
  55. $socket->expectAt(0, 'write', array("GET /here.html?a=1&b=2 HTTP/1.0\r\n"));
  56. $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n"));
  57. $socket->expectAt(2, 'write', array("Connection: close\r\n"));
  58. $socket->expectCallCount('write', 3);
  59. $route = new PartialSimpleRoute();
  60. $route->setReturnReference('createSocket', $socket);
  61. $route->__construct(new SimpleUrl('http://a.valid.host/here.html?a=1&b=2'));
  62. $route->createConnection('GET', 15);
  63. }
  64. }
  65. class TestOfProxyRoute extends UnitTestCase {
  66. function testDefaultGet() {
  67. $socket = new MockSimpleSocket();
  68. $socket->expectAt(0, 'write', array("GET http://a.valid.host/here.html HTTP/1.0\r\n"));
  69. $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n"));
  70. $socket->expectAt(2, 'write', array("Connection: close\r\n"));
  71. $socket->expectCallCount('write', 3);
  72. $route = new PartialSimpleProxyRoute();
  73. $route->setReturnReference('createSocket', $socket);
  74. $route->__construct(
  75. new SimpleUrl('http://a.valid.host/here.html'),
  76. new SimpleUrl('http://my-proxy'));
  77. $route->createConnection('GET', 15);
  78. }
  79. function testDefaultPost() {
  80. $socket = new MockSimpleSocket();
  81. $socket->expectAt(0, 'write', array("POST http://a.valid.host/here.html HTTP/1.0\r\n"));
  82. $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n"));
  83. $socket->expectAt(2, 'write', array("Connection: close\r\n"));
  84. $socket->expectCallCount('write', 3);
  85. $route = new PartialSimpleProxyRoute();
  86. $route->setReturnReference('createSocket', $socket);
  87. $route->__construct(
  88. new SimpleUrl('http://a.valid.host/here.html'),
  89. new SimpleUrl('http://my-proxy'));
  90. $route->createConnection('POST', 15);
  91. }
  92. function testGetWithPort() {
  93. $socket = new MockSimpleSocket();
  94. $socket->expectAt(0, 'write', array("GET http://a.valid.host:81/here.html HTTP/1.0\r\n"));
  95. $socket->expectAt(1, 'write', array("Host: my-proxy:8081\r\n"));
  96. $socket->expectAt(2, 'write', array("Connection: close\r\n"));
  97. $socket->expectCallCount('write', 3);
  98. $route = new PartialSimpleProxyRoute();
  99. $route->setReturnReference('createSocket', $socket);
  100. $route->__construct(
  101. new SimpleUrl('http://a.valid.host:81/here.html'),
  102. new SimpleUrl('http://my-proxy:8081'));
  103. $route->createConnection('GET', 15);
  104. }
  105. function testGetWithParameters() {
  106. $socket = new MockSimpleSocket();
  107. $socket->expectAt(0, 'write', array("GET http://a.valid.host/here.html?a=1&b=2 HTTP/1.0\r\n"));
  108. $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n"));
  109. $socket->expectAt(2, 'write', array("Connection: close\r\n"));
  110. $socket->expectCallCount('write', 3);
  111. $route = new PartialSimpleProxyRoute();
  112. $route->setReturnReference('createSocket', $socket);
  113. $route->__construct(
  114. new SimpleUrl('http://a.valid.host/here.html?a=1&b=2'),
  115. new SimpleUrl('http://my-proxy'));
  116. $route->createConnection('GET', 15);
  117. }
  118. function testGetWithAuthentication() {
  119. $encoded = base64_encode('Me:Secret');
  120. $socket = new MockSimpleSocket();
  121. $socket->expectAt(0, 'write', array("GET http://a.valid.host/here.html HTTP/1.0\r\n"));
  122. $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n"));
  123. $socket->expectAt(2, 'write', array("Proxy-Authorization: Basic $encoded\r\n"));
  124. $socket->expectAt(3, 'write', array("Connection: close\r\n"));
  125. $socket->expectCallCount('write', 4);
  126. $route = new PartialSimpleProxyRoute();
  127. $route->setReturnReference('createSocket', $socket);
  128. $route->__construct(
  129. new SimpleUrl('http://a.valid.host/here.html'),
  130. new SimpleUrl('http://my-proxy'),
  131. 'Me',
  132. 'Secret');
  133. $route->createConnection('GET', 15);
  134. }
  135. }
  136. class TestOfHttpRequest extends UnitTestCase {
  137. function testReadingBadConnection() {
  138. $socket = new MockSimpleSocket();
  139. $route = new MockSimpleRoute();
  140. $route->setReturnReference('createConnection', $socket);
  141. $request = new SimpleHttpRequest($route, new SimpleGetEncoding());
  142. $reponse = $request->fetch(15);
  143. $this->assertTrue($reponse->isError());
  144. }
  145. function testReadingGoodConnection() {
  146. $socket = new MockSimpleSocket();
  147. $socket->expectOnce('write', array("\r\n"));
  148. $route = new MockSimpleRoute();
  149. $route->setReturnReference('createConnection', $socket);
  150. $route->expect('createConnection', array('GET', 15));
  151. $request = new SimpleHttpRequest($route, new SimpleGetEncoding());
  152. $this->assertIsA($request->fetch(15), 'SimpleHttpResponse');
  153. }
  154. function testWritingAdditionalHeaders() {
  155. $socket = new MockSimpleSocket();
  156. $socket->expectAt(0, 'write', array("My: stuff\r\n"));
  157. $socket->expectAt(1, 'write', array("\r\n"));
  158. $socket->expectCallCount('write', 2);
  159. $route = new MockSimpleRoute();
  160. $route->setReturnReference('createConnection', $socket);
  161. $request = new SimpleHttpRequest($route, new SimpleGetEncoding());
  162. $request->addHeaderLine('My: stuff');
  163. $request->fetch(15);
  164. }
  165. function testCookieWriting() {
  166. $socket = new MockSimpleSocket();
  167. $socket->expectAt(0, 'write', array("Cookie: a=A\r\n"));
  168. $socket->expectAt(1, 'write', array("\r\n"));
  169. $socket->expectCallCount('write', 2);
  170. $route = new MockSimpleRoute();
  171. $route->setReturnReference('createConnection', $socket);
  172. $jar = new SimpleCookieJar();
  173. $jar->setCookie('a', 'A');
  174. $request = new SimpleHttpRequest($route, new SimpleGetEncoding());
  175. $request->readCookiesFromJar($jar, new SimpleUrl('/'));
  176. $this->assertIsA($request->fetch(15), 'SimpleHttpResponse');
  177. }
  178. function testMultipleCookieWriting() {
  179. $socket = new MockSimpleSocket();
  180. $socket->expectAt(0, 'write', array("Cookie: a=A;b=B\r\n"));
  181. $route = new MockSimpleRoute();
  182. $route->setReturnReference('createConnection', $socket);
  183. $jar = new SimpleCookieJar();
  184. $jar->setCookie('a', 'A');
  185. $jar->setCookie('b', 'B');
  186. $request = new SimpleHttpRequest($route, new SimpleGetEncoding());
  187. $request->readCookiesFromJar($jar, new SimpleUrl('/'));
  188. $request->fetch(15);
  189. }
  190. }
  191. class TestOfHttpPostRequest extends UnitTestCase {
  192. function testReadingBadConnectionCausesErrorBecauseOfDeadSocket() {
  193. $socket = new MockSimpleSocket();
  194. $route = new MockSimpleRoute();
  195. $route->setReturnReference('createConnection', $socket);
  196. $request = new SimpleHttpRequest($route, new SimplePostEncoding());
  197. $reponse = $request->fetch(15);
  198. $this->assertTrue($reponse->isError());
  199. }
  200. function testReadingGoodConnection() {
  201. $socket = new MockSimpleSocket();
  202. $socket->expectAt(0, 'write', array("Content-Length: 0\r\n"));
  203. $socket->expectAt(1, 'write', array("Content-Type: application/x-www-form-urlencoded\r\n"));
  204. $socket->expectAt(2, 'write', array("\r\n"));
  205. $socket->expectAt(3, 'write', array(""));
  206. $route = new MockSimpleRoute();
  207. $route->setReturnReference('createConnection', $socket);
  208. $route->expect('createConnection', array('POST', 15));
  209. $request = new SimpleHttpRequest($route, new SimplePostEncoding());
  210. $this->assertIsA($request->fetch(15), 'SimpleHttpResponse');
  211. }
  212. function testContentHeadersCalculated() {
  213. $socket = new MockSimpleSocket();
  214. $socket->expectAt(0, 'write', array("Content-Length: 3\r\n"));
  215. $socket->expectAt(1, 'write', array("Content-Type: application/x-www-form-urlencoded\r\n"));
  216. $socket->expectAt(2, 'write', array("\r\n"));
  217. $socket->expectAt(3, 'write', array("a=A"));
  218. $route = new MockSimpleRoute();
  219. $route->setReturnReference('createConnection', $socket);
  220. $route->expect('createConnection', array('POST', 15));
  221. $request = new SimpleHttpRequest(
  222. $route,
  223. new SimplePostEncoding(array('a' => 'A')));
  224. $this->assertIsA($request->fetch(15), 'SimpleHttpResponse');
  225. }
  226. }
  227. class TestOfHttpHeaders extends UnitTestCase {
  228. function testParseBasicHeaders() {
  229. $headers = new SimpleHttpHeaders(
  230. "HTTP/1.1 200 OK\r\n" .
  231. "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n" .
  232. "Content-Type: text/plain\r\n" .
  233. "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\n" .
  234. "Connection: close");
  235. $this->assertIdentical($headers->getHttpVersion(), "1.1");
  236. $this->assertIdentical($headers->getResponseCode(), 200);
  237. $this->assertEqual($headers->getMimeType(), "text/plain");
  238. }
  239. function testNonStandardResponseHeader() {
  240. $headers = new SimpleHttpHeaders(
  241. "HTTP/1.1 302 (HTTP-Version SP Status-Code CRLF)\r\n" .
  242. "Connection: close");
  243. $this->assertIdentical($headers->getResponseCode(), 302);
  244. }
  245. function testCanParseMultipleCookies() {
  246. $jar = new MockSimpleCookieJar();
  247. $jar->expectAt(0, 'setCookie', array('a', 'aaa', 'host', '/here/', 'Wed, 25 Dec 2002 04:24:20 GMT'));
  248. $jar->expectAt(1, 'setCookie', array('b', 'bbb', 'host', '/', false));
  249. $headers = new SimpleHttpHeaders(
  250. "HTTP/1.1 200 OK\r\n" .
  251. "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n" .
  252. "Content-Type: text/plain\r\n" .
  253. "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\n" .
  254. "Set-Cookie: a=aaa; expires=Wed, 25-Dec-02 04:24:20 GMT; path=/here/\r\n" .
  255. "Set-Cookie: b=bbb\r\n" .
  256. "Connection: close");
  257. $headers->writeCookiesToJar($jar, new SimpleUrl('http://host'));
  258. }
  259. function testCanRecogniseRedirect() {
  260. $headers = new SimpleHttpHeaders("HTTP/1.1 301 OK\r\n" .
  261. "Content-Type: text/plain\r\n" .
  262. "Content-Length: 0\r\n" .
  263. "Location: http://www.somewhere-else.com/\r\n" .
  264. "Connection: close");
  265. $this->assertIdentical($headers->getResponseCode(), 301);
  266. $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com/");
  267. $this->assertTrue($headers->isRedirect());
  268. }
  269. function testCanParseChallenge() {
  270. $headers = new SimpleHttpHeaders("HTTP/1.1 401 Authorization required\r\n" .
  271. "Content-Type: text/plain\r\n" .
  272. "Connection: close\r\n" .
  273. "WWW-Authenticate: Basic realm=\"Somewhere\"");
  274. $this->assertEqual($headers->getAuthentication(), 'Basic');
  275. $this->assertEqual($headers->getRealm(), 'Somewhere');
  276. $this->assertTrue($headers->isChallenge());
  277. }
  278. }
  279. class TestOfHttpResponse extends UnitTestCase {
  280. function testBadRequest() {
  281. $socket = new MockSimpleSocket();
  282. $socket->setReturnValue('getSent', '');
  283. $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
  284. $this->assertTrue($response->isError());
  285. $this->assertPattern('/Nothing fetched/', $response->getError());
  286. $this->assertIdentical($response->getContent(), false);
  287. $this->assertIdentical($response->getSent(), '');
  288. }
  289. function testBadSocketDuringResponse() {
  290. $socket = new MockSimpleSocket();
  291. $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\n");
  292. $socket->setReturnValueAt(1, "read", "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n");
  293. $socket->setReturnValue("read", "");
  294. $socket->setReturnValue('getSent', 'HTTP/1.1 ...');
  295. $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
  296. $this->assertTrue($response->isError());
  297. $this->assertEqual($response->getContent(), '');
  298. $this->assertEqual($response->getSent(), 'HTTP/1.1 ...');
  299. }
  300. function testIncompleteHeader() {
  301. $socket = new MockSimpleSocket();
  302. $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\n");
  303. $socket->setReturnValueAt(1, "read", "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n");
  304. $socket->setReturnValueAt(2, "read", "Content-Type: text/plain\r\n");
  305. $socket->setReturnValue("read", "");
  306. $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
  307. $this->assertTrue($response->isError());
  308. $this->assertEqual($response->getContent(), "");
  309. }
  310. function testParseOfResponseHeadersWhenChunked() {
  311. $socket = new MockSimpleSocket();
  312. $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\nDate: Mon, 18 Nov 2002 15:50:29 GMT\r\n");
  313. $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n");
  314. $socket->setReturnValueAt(2, "read", "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\nConne");
  315. $socket->setReturnValueAt(3, "read", "ction: close\r\n\r\nthis is a test file\n");
  316. $socket->setReturnValueAt(4, "read", "with two lines in it\n");
  317. $socket->setReturnValue("read", "");
  318. $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
  319. $this->assertFalse($response->isError());
  320. $this->assertEqual(
  321. $response->getContent(),
  322. "this is a test file\nwith two lines in it\n");
  323. $headers = $response->getHeaders();
  324. $this->assertIdentical($headers->getHttpVersion(), "1.1");
  325. $this->assertIdentical($headers->getResponseCode(), 200);
  326. $this->assertEqual($headers->getMimeType(), "text/plain");
  327. $this->assertFalse($headers->isRedirect());
  328. $this->assertFalse($headers->getLocation());
  329. }
  330. function testRedirect() {
  331. $socket = new MockSimpleSocket();
  332. $socket->setReturnValueAt(0, "read", "HTTP/1.1 301 OK\r\n");
  333. $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n");
  334. $socket->setReturnValueAt(2, "read", "Location: http://www.somewhere-else.com/\r\n");
  335. $socket->setReturnValueAt(3, "read", "Connection: close\r\n");
  336. $socket->setReturnValueAt(4, "read", "\r\n");
  337. $socket->setReturnValue("read", "");
  338. $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
  339. $headers = $response->getHeaders();
  340. $this->assertTrue($headers->isRedirect());
  341. $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com/");
  342. }
  343. function testRedirectWithPort() {
  344. $socket = new MockSimpleSocket();
  345. $socket->setReturnValueAt(0, "read", "HTTP/1.1 301 OK\r\n");
  346. $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n");
  347. $socket->setReturnValueAt(2, "read", "Location: http://www.somewhere-else.com:80/\r\n");
  348. $socket->setReturnValueAt(3, "read", "Connection: close\r\n");
  349. $socket->setReturnValueAt(4, "read", "\r\n");
  350. $socket->setReturnValue("read", "");
  351. $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
  352. $headers = $response->getHeaders();
  353. $this->assertTrue($headers->isRedirect());
  354. $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com:80/");
  355. }
  356. }
  357. ?>