CurlHandler.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. $this->registerShutdownFunction();
  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 registerShutdownFunction()
  58. {
  59. register_shutdown_function(array($this, 'join'));
  60. }
  61. public function join($timeout = null)
  62. {
  63. if (!isset($timeout)) {
  64. $timeout = $this->join_timeout;
  65. }
  66. $start = time();
  67. do {
  68. $this->select();
  69. if (count($this->requests) === 0) {
  70. break;
  71. }
  72. usleep(10000);
  73. } while ($timeout !== 0 && time() - $start < $timeout);
  74. }
  75. /**
  76. * @doc http://php.net/manual/en/function.curl-multi-exec.php
  77. */
  78. protected function select()
  79. {
  80. do {
  81. $mrc = curl_multi_exec($this->multi_handle, $active);
  82. } while ($mrc == CURLM_CALL_MULTI_PERFORM);
  83. while ($active && $mrc == CURLM_OK) {
  84. if (curl_multi_select($this->multi_handle) !== -1) {
  85. do {
  86. $mrc = curl_multi_exec($this->multi_handle, $active);
  87. } while ($mrc == CURLM_CALL_MULTI_PERFORM);
  88. } else {
  89. return;
  90. }
  91. }
  92. while ($info = curl_multi_info_read($this->multi_handle)) {
  93. $ch = $info['handle'];
  94. $fd = (int)$ch;
  95. curl_multi_remove_handle($this->multi_handle, $ch);
  96. if (!isset($this->requests[$fd])) {
  97. return;
  98. }
  99. unset($this->requests[$fd]);
  100. }
  101. }
  102. }