CurlHandler.php 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <?php
  2. /*
  3. * This file is part of Raven.
  4. *
  5. * (c) Sentry Team
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. /**
  11. * Asynchronous Curl connection manager.
  12. *
  13. * @package raven
  14. */
  15. // TODO(dcramer): handle ca_cert
  16. class Raven_CurlHandler
  17. {
  18. protected $join_timeout;
  19. protected $multi_handle;
  20. protected $options;
  21. protected $requests;
  22. public function __construct($options, $join_timeout = 5)
  23. {
  24. $this->options = $options;
  25. $this->multi_handle = curl_multi_init();
  26. $this->requests = array();
  27. $this->join_timeout = $join_timeout;
  28. register_shutdown_function(array($this, 'join'));
  29. }
  30. public function __destruct()
  31. {
  32. $this->join();
  33. }
  34. public function enqueue($url, $data = null, $headers = array())
  35. {
  36. $ch = curl_init();
  37. $new_headers = array();
  38. foreach ($headers as $key => $value) {
  39. array_push($new_headers, $key .': '. $value);
  40. }
  41. // XXX(dcramer): Prevent 100-continue response form server (Fixes GH-216)
  42. $new_headers[] = 'Expect:';
  43. curl_setopt($ch, CURLOPT_HTTPHEADER, $new_headers);
  44. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  45. curl_setopt($ch, CURLOPT_URL, $url);
  46. curl_setopt_array($ch, $this->options);
  47. if (isset($data)) {
  48. curl_setopt($ch, CURLOPT_POST, true);
  49. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  50. }
  51. curl_multi_add_handle($this->multi_handle, $ch);
  52. $fd = (int)$ch;
  53. $this->requests[$fd] = 1;
  54. $this->select();
  55. return $fd;
  56. }
  57. public function join($timeout = null)
  58. {
  59. if (!isset($timeout)) {
  60. $timeout = $this->join_timeout;
  61. }
  62. $start = time();
  63. do {
  64. $this->select();
  65. if (count($this->requests) === 0) {
  66. break;
  67. }
  68. usleep(10000);
  69. } while ($timeout !== 0 && time() - $start < $timeout);
  70. }
  71. /**
  72. * @doc http://php.net/manual/en/function.curl-multi-exec.php
  73. */
  74. protected function select()
  75. {
  76. do {
  77. $mrc = curl_multi_exec($this->multi_handle, $active);
  78. } while ($mrc == CURLM_CALL_MULTI_PERFORM);
  79. while ($active && $mrc == CURLM_OK) {
  80. if (curl_multi_select($this->multi_handle) !== -1) {
  81. do {
  82. $mrc = curl_multi_exec($this->multi_handle, $active);
  83. } while ($mrc == CURLM_CALL_MULTI_PERFORM);
  84. } else {
  85. return;
  86. }
  87. }
  88. while ($info = curl_multi_info_read($this->multi_handle)) {
  89. $ch = $info['handle'];
  90. $fd = (int)$ch;
  91. curl_multi_remove_handle($this->multi_handle, $ch);
  92. if (!isset($this->requests[$fd])) {
  93. return;
  94. }
  95. unset($this->requests[$fd]);
  96. }
  97. }
  98. }