WebDriverCurlService.php 4.73 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

namespace Drupal\FunctionalJavascriptTests;

use WebDriver\Service\CurlService;
use WebDriver\Exception\CurlExec;
use WebDriver\Exception as WebDriverException;

/**
 * Provides a curl service to interact with Selenium driver.
 *
 * Extends WebDriver\Service\CurlService to solve problem with race conditions,
 * when multiple processes requests.
 */
class WebDriverCurlService extends CurlService {

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  /**
   * The maximum number of times to try in the event of a stale element
   * reference error.
   *
   * @var int
   */
  private static $maxRetries = 10;

  /**
   * Sets the maximum number of retries.
   *
   * @param int $max_retries
   *   The maximum number of times to try in the event of a stale element
   *   reference error. This number must be greater than 10.
   */
  public static function setMaxRetries(int $max_retries) {
    static::$maxRetries = max($max_retries, static::$maxRetries);
  }

36
37
38
39
40
41
42
43
  /**
   * {@inheritdoc}
   */
  public function execute($requestMethod, $url, $parameters = NULL, $extraOptions = []) {
    $extraOptions += [
      CURLOPT_FAILONERROR => TRUE,
    ];
    $retries = 0;
44
    while ($retries < static::$maxRetries) {
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
      try {
        $customHeaders = [
          'Content-Type: application/json;charset=UTF-8',
          'Accept: application/json;charset=UTF-8',
        ];

        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);

        switch ($requestMethod) {
          case 'GET':
            break;

          case 'POST':
            if ($parameters && is_array($parameters)) {
              curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($parameters));
            }
            else {
              $customHeaders[] = 'Content-Length: 0';
64
65
66
67
68

              // Suppress "Transfer-Encoding: chunked" header automatically
              // added by cURL that causes a 400 bad request (bad
              // content-length).
              $customHeaders[] = 'Transfer-Encoding:';
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
            }

            // Suppress "Expect: 100-continue" header automatically added by
            // cURL that causes a 1 second delay if the remote server does not
            // support Expect.
            $customHeaders[] = 'Expect:';

            curl_setopt($curl, CURLOPT_POST, TRUE);
            break;

          case 'DELETE':
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
            break;

          case 'PUT':
            if ($parameters && is_array($parameters)) {
              curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($parameters));
            }
            else {
              $customHeaders[] = 'Content-Length: 0';
89
90
91
92
93

              // Suppress "Transfer-Encoding: chunked" header automatically
              // added by cURL that causes a 400 bad request (bad
              // content-length).
              $customHeaders[] = 'Transfer-Encoding:';
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
            }

            // Suppress "Expect: 100-continue" header automatically added by
            // cURL that causes a 1 second delay if the remote server does not
            // support Expect.
            $customHeaders[] = 'Expect:';

            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
            break;
        }

        foreach ($extraOptions as $option => $value) {
          curl_setopt($curl, $option, $value);
        }

        curl_setopt($curl, CURLOPT_HTTPHEADER, $customHeaders);

        $rawResult = trim(curl_exec($curl));

        $info = curl_getinfo($curl);
        $info['request_method'] = $requestMethod;

        if (array_key_exists(CURLOPT_FAILONERROR, $extraOptions) && $extraOptions[CURLOPT_FAILONERROR] && CURLE_GOT_NOTHING !== ($errno = curl_errno($curl)) && $error = curl_error($curl)) {
          curl_close($curl);

          throw WebDriverException::factory(WebDriverException::CURL_EXEC, sprintf("Curl error thrown for http %s to %s%s\n\n%s", $requestMethod, $url, $parameters && is_array($parameters) ? ' with params: ' . json_encode($parameters) : '', $error));
        }

        curl_close($curl);

        $result = json_decode($rawResult, TRUE);
        if (isset($result['status']) && $result['status'] === WebDriverException::STALE_ELEMENT_REFERENCE) {
          $retries++;
127
128
          // Wait a bit longer each time a stale reference error has occurred.
          usleep(100000 * $retries);
129
130
131
132
133
134
135
136
          continue;
        }
        return [$rawResult, $info];
      }
      catch (CurlExec $exception) {
        $retries++;
      }
    }
137
138
139
    if (empty($error)) {
      $error = "Retries: $retries and last result:\n" . ($rawResult ?? '');
    }
140
141
142
143
    throw WebDriverException::factory(WebDriverException::CURL_EXEC, sprintf("Curl error thrown for http %s to %s%s\n\n%s", $requestMethod, $url, $parameters && is_array($parameters) ? ' with params: ' . json_encode($parameters) : '', $error));
  }

}