Test Failed
Push — master ( 4cd501...1b9ce5 )
by Stiofan
07:38
created

Google_HttpStreamIO   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 145
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 0
loc 145
rs 10
c 0
b 0
f 0
wmc 22
lcom 1
cbo 5

5 Methods

Rating   Name   Duplication   Size   Complexity  
A authenticatedRequest() 0 4 1
D makeRequest() 0 73 14
A setOptions() 0 2 1
A getHttpResponseCode() 0 12 3
A getHttpResponseHeaders() 0 14 3
1
<?php
2
/*
3
 * Copyright 2013 Google Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
/**
19
 * Http Streams based implementation of Google_IO.
20
 *
21
 * @author Stuart Langley <[email protected]>
22
 */
23
24
require_once 'Google_CacheParser.php';
25
26
class Google_HttpStreamIO extends Google_IO {
27
28
  private static $ENTITY_HTTP_METHODS = array("POST" => null, "PUT" => null);
29
30
  private static $DEFAULT_HTTP_CONTEXT = array(
31
    "follow_location" => 0,
32
    "ignore_errors" => 1,
33
  );
34
35
  private static $DEFAULT_SSL_CONTEXT = array(
36
    "verify_peer" => true,
37
  );
38
39
  /**
40
   * Perform an authenticated / signed apiHttpRequest.
41
   * This function takes the apiHttpRequest, calls apiAuth->sign on it
42
   * (which can modify the request in what ever way fits the auth mechanism)
43
   * and then calls Google_HttpStreamIO::makeRequest on the signed request
44
   *
45
   * @param Google_HttpRequest $request
46
   * @return Google_HttpRequest The resulting HTTP response including the
47
   * responseHttpCode, responseHeaders and responseBody.
48
   */
49
  public function authenticatedRequest(Google_HttpRequest $request) {
50
    $request = Google_Client::$auth->sign($request);
0 ignored issues
show
Bug introduced by
The property auth cannot be accessed from this context as it is declared private in class Google_Client.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
51
    return $this->makeRequest($request);
52
  }
53
54
  /**
55
   * Execute a apiHttpRequest
56
   *
57
   * @param Google_HttpRequest $request the http request to be executed
58
   * @return Google_HttpRequest http request with the response http code,
59
   * response headers and response body filled in
60
   * @throws Google_IOException on curl or IO error
61
   */
62
  public function makeRequest(Google_HttpRequest $request) {
63
    // First, check to see if we have a valid cached version.
64
    $cached = $this->getCachedRequest($request);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->getCachedRequest($request); of type Google_HttpRequest|boolean adds the type boolean to the return on line 67 which is incompatible with the return type declared by the abstract method Google_IO::makeRequest of type Google_HttpRequest.
Loading history...
65
    if ($cached !== false) {
66
      if (!$this->checkMustRevaliadateCachedRequest($cached, $request)) {
0 ignored issues
show
Bug introduced by
It seems like $cached defined by $this->getCachedRequest($request) on line 64 can also be of type boolean; however, Google_IO::checkMustRevaliadateCachedRequest() does only seem to accept object<Google_HttpRequest>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
67
        return $cached;
68
      }
69
    }
70
71
    $default_options = stream_context_get_options(stream_context_get_default());
72
73
    $requestHttpContext = array_key_exists('http', $default_options) ?
74
        $default_options['http'] : array();
75
    if (array_key_exists($request->getRequestMethod(),
76
          self::$ENTITY_HTTP_METHODS)) {
77
      $request = $this->processEntityRequest($request);
78
    }
79
80
    if ($request->getPostBody()) {
81
      $requestHttpContext["content"] = $request->getPostBody();
82
    }
83
84
    $requestHeaders = $request->getRequestHeaders();
85
    if ($requestHeaders && is_array($requestHeaders)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $requestHeaders of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
86
      $headers = "";
87
      foreach($requestHeaders as $k => $v) {
88
        $headers .= "$k: $v\n";
89
      }
90
      $requestHttpContext["header"] = $headers;
91
    }
92
93
    $requestHttpContext["method"] = $request->getRequestMethod();
94
    $requestHttpContext["user_agent"] = $request->getUserAgent();
95
96
    $requestSslContext = array_key_exists('ssl', $default_options) ?
97
        $default_options['ssl'] : array();
98
99
    if (!array_key_exists("cafile", $requestSslContext)) {
100
      $requestSslContext["cafile"] = dirname(__FILE__) . '/cacerts.pem';
101
    }
102
103
    $options = array("http" => array_merge(self::$DEFAULT_HTTP_CONTEXT,
104
                                                 $requestHttpContext),
105
                     "ssl" => array_merge(self::$DEFAULT_SSL_CONTEXT,
106
                                          $requestSslContext));
107
108
    $context = stream_context_create($options);
109
110
    $response_data = file_get_contents($request->getUrl(),
111
                                       false,
112
                                       $context);
113
114
    if (false === $response_data) {
115
      throw new Google_IOException("HTTP Error: Unable to connect");
116
    }
117
118
    $respHttpCode = $this->getHttpResponseCode($http_response_header);
119
    $responseHeaders = $this->getHttpResponseHeaders($http_response_header);
120
121
    if ($respHttpCode == 304 && $cached) {
122
      // If the server responded NOT_MODIFIED, return the cached request.
123
      $this->updateCachedRequest($cached, $responseHeaders);
0 ignored issues
show
Bug introduced by
It seems like $cached defined by $this->getCachedRequest($request) on line 64 can also be of type boolean; however, Google_IO::updateCachedRequest() does only seem to accept object<Google_HttpRequest>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
124
      return $cached;
125
    }
126
127
    $request->setResponseHttpCode($respHttpCode);
128
    $request->setResponseHeaders($responseHeaders);
129
    $request->setResponseBody($response_data);
130
    // Store the request in cache (the function checks to see if the request
131
    // can actually be cached)
132
    $this->setCachedRequest($request);
133
    return $request;
134
  }
135
136
  /**
137
   * Set options that update the transport implementation's behavior.
138
   * @param $options
139
   */
140
  public function setOptions($options) {
141
  }
142
143
  private function getHttpResponseCode($response_headers) {
144
    $header_count = count($response_headers);
145
146
    for ($i = 0; $i < $header_count; $i++) {
147
      $header = $response_headers[$i];
148
      if (strncasecmp("HTTP", $header, strlen("HTTP")) == 0) {
149
        $response = explode(' ', $header);
150
        return $response[1];
151
      }
152
    }
153
    return 'UNKNOWN';
154
  }
155
156
  private function getHttpResponseHeaders($response_headers) {
157
    $header_count = count($response_headers);
158
    $headers = array();
159
160
    for ($i = 0; $i < $header_count; $i++) {
161
      $header = $response_headers[$i];
162
      $header_parts = explode(':', $header);
163
      if (count($header_parts) == 2) {
164
        $headers[$header_parts[0]] = $header_parts[1];
165
      }
166
    }
167
168
    return $headers;
169
  }
170
}
171