GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 423fe8...f48289 )
by gyeong-won
15:56 queued 08:14
created
libs/PEAR.1.9.5/HTTP/Request.php 1 patch
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -18,28 +18,28 @@
 block discarded – undo
18 18
 	}
19 19
 
20 20
 	public function getResponseCode() {
21
-		if($this->response)
21
+		if ($this->response)
22 22
 		{
23 23
 			return $this->response->getStatus();
24 24
 		}
25 25
 	}
26 26
 
27 27
 	public function getResponseHeader() {
28
-		if($this->response)
28
+		if ($this->response)
29 29
 		{
30 30
 			return $this->response->getHeader();	
31 31
 		}
32 32
 	}
33 33
 
34 34
 	public function getResponseBody() {
35
-		if($this->response)
35
+		if ($this->response)
36 36
 		{
37 37
 			return $this->response->getBody();
38 38
 		}
39 39
 	}
40 40
 
41 41
 	public function getResponseCookies() {
42
-		if($this->response)
42
+		if ($this->response)
43 43
 		{
44 44
 			return $this->response->getCookies();
45 45
 		}
Please login to merge, or discard this patch.
libs/PEAR.1.9.5/HTTP/Request2.php 3 patches
Indentation   +977 added lines, -977 removed lines patch added patch discarded remove patch
@@ -41,990 +41,990 @@
 block discarded – undo
41 41
  */
42 42
 class HTTP_Request2 implements SplSubject
43 43
 {
44
-    /**#@+
44
+	/**#@+
45 45
      * Constants for HTTP request methods
46 46
      *
47 47
      * @link http://tools.ietf.org/html/rfc2616#section-5.1.1
48 48
      */
49
-    const METHOD_OPTIONS = 'OPTIONS';
50
-    const METHOD_GET     = 'GET';
51
-    const METHOD_HEAD    = 'HEAD';
52
-    const METHOD_POST    = 'POST';
53
-    const METHOD_PUT     = 'PUT';
54
-    const METHOD_DELETE  = 'DELETE';
55
-    const METHOD_TRACE   = 'TRACE';
56
-    const METHOD_CONNECT = 'CONNECT';
57
-    /**#@-*/
58
-
59
-    /**#@+
49
+	const METHOD_OPTIONS = 'OPTIONS';
50
+	const METHOD_GET     = 'GET';
51
+	const METHOD_HEAD    = 'HEAD';
52
+	const METHOD_POST    = 'POST';
53
+	const METHOD_PUT     = 'PUT';
54
+	const METHOD_DELETE  = 'DELETE';
55
+	const METHOD_TRACE   = 'TRACE';
56
+	const METHOD_CONNECT = 'CONNECT';
57
+	/**#@-*/
58
+
59
+	/**#@+
60 60
      * Constants for HTTP authentication schemes
61 61
      *
62 62
      * @link http://tools.ietf.org/html/rfc2617
63 63
      */
64
-    const AUTH_BASIC  = 'basic';
65
-    const AUTH_DIGEST = 'digest';
66
-    /**#@-*/
67
-
68
-    /**
69
-     * Regular expression used to check for invalid symbols in RFC 2616 tokens
70
-     * @link http://pear.php.net/bugs/bug.php?id=15630
71
-     */
72
-    const REGEXP_INVALID_TOKEN = '![\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]!';
73
-
74
-    /**
75
-     * Regular expression used to check for invalid symbols in cookie strings
76
-     * @link http://pear.php.net/bugs/bug.php?id=15630
77
-     * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html
78
-     */
79
-    const REGEXP_INVALID_COOKIE = '/[\s,;]/';
80
-
81
-    /**
82
-     * Fileinfo magic database resource
83
-     * @var  resource
84
-     * @see  detectMimeType()
85
-     */
86
-    private static $_fileinfoDb;
87
-
88
-    /**
89
-     * Observers attached to the request (instances of SplObserver)
90
-     * @var  array
91
-     */
92
-    protected $observers = array();
93
-
94
-    /**
95
-     * Request URL
96
-     * @var  Net_URL2
97
-     */
98
-    protected $url;
99
-
100
-    /**
101
-     * Request method
102
-     * @var  string
103
-     */
104
-    protected $method = self::METHOD_GET;
105
-
106
-    /**
107
-     * Authentication data
108
-     * @var  array
109
-     * @see  getAuth()
110
-     */
111
-    protected $auth;
112
-
113
-    /**
114
-     * Request headers
115
-     * @var  array
116
-     */
117
-    protected $headers = array();
118
-
119
-    /**
120
-     * Configuration parameters
121
-     * @var  array
122
-     * @see  setConfig()
123
-     */
124
-    protected $config = array(
125
-        'adapter'           => 'HTTP_Request2_Adapter_Socket',
126
-        'connect_timeout'   => 10,
127
-        'timeout'           => 0,
128
-        'use_brackets'      => true,
129
-        'protocol_version'  => '1.1',
130
-        'buffer_size'       => 16384,
131
-        'store_body'        => true,
132
-        'local_ip'          => null,
133
-
134
-        'proxy_host'        => '',
135
-        'proxy_port'        => '',
136
-        'proxy_user'        => '',
137
-        'proxy_password'    => '',
138
-        'proxy_auth_scheme' => self::AUTH_BASIC,
139
-        'proxy_type'        => 'http',
140
-
141
-        'ssl_verify_peer'   => true,
142
-        'ssl_verify_host'   => true,
143
-        'ssl_cafile'        => null,
144
-        'ssl_capath'        => null,
145
-        'ssl_local_cert'    => null,
146
-        'ssl_passphrase'    => null,
147
-
148
-        'digest_compat_ie'  => false,
149
-
150
-        'follow_redirects'  => false,
151
-        'max_redirects'     => 5,
152
-        'strict_redirects'  => false
153
-    );
154
-
155
-    /**
156
-     * Last event in request / response handling, intended for observers
157
-     * @var  array
158
-     * @see  getLastEvent()
159
-     */
160
-    protected $lastEvent = array(
161
-        'name' => 'start',
162
-        'data' => null
163
-    );
164
-
165
-    /**
166
-     * Request body
167
-     * @var  string|resource
168
-     * @see  setBody()
169
-     */
170
-    protected $body = '';
171
-
172
-    /**
173
-     * Array of POST parameters
174
-     * @var  array
175
-     */
176
-    protected $postParams = array();
177
-
178
-    /**
179
-     * Array of file uploads (for multipart/form-data POST requests)
180
-     * @var  array
181
-     */
182
-    protected $uploads = array();
183
-
184
-    /**
185
-     * Adapter used to perform actual HTTP request
186
-     * @var  HTTP_Request2_Adapter
187
-     */
188
-    protected $adapter;
189
-
190
-    /**
191
-     * Cookie jar to persist cookies between requests
192
-     * @var HTTP_Request2_CookieJar
193
-     */
194
-    protected $cookieJar = null;
195
-
196
-    /**
197
-     * Constructor. Can set request URL, method and configuration array.
198
-     *
199
-     * Also sets a default value for User-Agent header.
200
-     *
201
-     * @param string|Net_Url2 $url    Request URL
202
-     * @param string          $method Request method
203
-     * @param array           $config Configuration for this Request instance
204
-     */
205
-    public function __construct(
206
-        $url = null, $method = self::METHOD_GET, array $config = array()
207
-    ) {
208
-        $this->setConfig($config);
209
-        if (!empty($url)) {
210
-            $this->setUrl($url);
211
-        }
212
-        if (!empty($method)) {
213
-            $this->setMethod($method);
214
-        }
215
-        $this->setHeader(
216
-            'user-agent', 'HTTP_Request2/2.2.1 ' .
217
-            '(http://pear.php.net/package/http_request2) PHP/' . phpversion()
218
-        );
219
-    }
220
-
221
-    /**
222
-     * Sets the URL for this request
223
-     *
224
-     * If the URL has userinfo part (username & password) these will be removed
225
-     * and converted to auth data. If the URL does not have a path component,
226
-     * that will be set to '/'.
227
-     *
228
-     * @param string|Net_URL2 $url Request URL
229
-     *
230
-     * @return   HTTP_Request2
231
-     * @throws   HTTP_Request2_LogicException
232
-     */
233
-    public function setUrl($url)
234
-    {
235
-        if (is_string($url)) {
236
-            $url = new Net_URL2(
237
-                $url, array(Net_URL2::OPTION_USE_BRACKETS => $this->config['use_brackets'])
238
-            );
239
-        }
240
-        if (!$url instanceof Net_URL2) {
241
-            throw new HTTP_Request2_LogicException(
242
-                'Parameter is not a valid HTTP URL',
243
-                HTTP_Request2_Exception::INVALID_ARGUMENT
244
-            );
245
-        }
246
-        // URL contains username / password?
247
-        if ($url->getUserinfo()) {
248
-            $username = $url->getUser();
249
-            $password = $url->getPassword();
250
-            $this->setAuth(rawurldecode($username), $password? rawurldecode($password): '');
251
-            $url->setUserinfo('');
252
-        }
253
-        if ('' == $url->getPath()) {
254
-            $url->setPath('/');
255
-        }
256
-        $this->url = $url;
257
-
258
-        return $this;
259
-    }
260
-
261
-    /**
262
-     * Returns the request URL
263
-     *
264
-     * @return   Net_URL2
265
-     */
266
-    public function getUrl()
267
-    {
268
-        return $this->url;
269
-    }
270
-
271
-    /**
272
-     * Sets the request method
273
-     *
274
-     * @param string $method one of the methods defined in RFC 2616
275
-     *
276
-     * @return   HTTP_Request2
277
-     * @throws   HTTP_Request2_LogicException if the method name is invalid
278
-     */
279
-    public function setMethod($method)
280
-    {
281
-        // Method name should be a token: http://tools.ietf.org/html/rfc2616#section-5.1.1
282
-        if (preg_match(self::REGEXP_INVALID_TOKEN, $method)) {
283
-            throw new HTTP_Request2_LogicException(
284
-                "Invalid request method '{$method}'",
285
-                HTTP_Request2_Exception::INVALID_ARGUMENT
286
-            );
287
-        }
288
-        $this->method = $method;
289
-
290
-        return $this;
291
-    }
292
-
293
-    /**
294
-     * Returns the request method
295
-     *
296
-     * @return   string
297
-     */
298
-    public function getMethod()
299
-    {
300
-        return $this->method;
301
-    }
302
-
303
-    /**
304
-     * Sets the configuration parameter(s)
305
-     *
306
-     * The following parameters are available:
307
-     * <ul>
308
-     *   <li> 'adapter'           - adapter to use (string)</li>
309
-     *   <li> 'connect_timeout'   - Connection timeout in seconds (integer)</li>
310
-     *   <li> 'timeout'           - Total number of seconds a request can take.
311
-     *                              Use 0 for no limit, should be greater than
312
-     *                              'connect_timeout' if set (integer)</li>
313
-     *   <li> 'use_brackets'      - Whether to append [] to array variable names (bool)</li>
314
-     *   <li> 'protocol_version'  - HTTP Version to use, '1.0' or '1.1' (string)</li>
315
-     *   <li> 'buffer_size'       - Buffer size to use for reading and writing (int)</li>
316
-     *   <li> 'store_body'        - Whether to store response body in response object.
317
-     *                              Set to false if receiving a huge response and
318
-     *                              using an Observer to save it (boolean)</li>
319
-     *   <li> 'local_ip'          - Specifies the IP address that will be used for accessing
320
-     *                              the network (string)</li>
321
-     *   <li> 'proxy_type'        - Proxy type, 'http' or 'socks5' (string)</li>
322
-     *   <li> 'proxy_host'        - Proxy server host (string)</li>
323
-     *   <li> 'proxy_port'        - Proxy server port (integer)</li>
324
-     *   <li> 'proxy_user'        - Proxy auth username (string)</li>
325
-     *   <li> 'proxy_password'    - Proxy auth password (string)</li>
326
-     *   <li> 'proxy_auth_scheme' - Proxy auth scheme, one of HTTP_Request2::AUTH_* constants (string)</li>
327
-     *   <li> 'proxy'             - Shorthand for proxy_* parameters, proxy given as URL,
328
-     *                              e.g. 'socks5://localhost:1080/' (string)</li>
329
-     *   <li> 'ssl_verify_peer'   - Whether to verify peer's SSL certificate (bool)</li>
330
-     *   <li> 'ssl_verify_host'   - Whether to check that Common Name in SSL
331
-     *                              certificate matches host name (bool)</li>
332
-     *   <li> 'ssl_cafile'        - Cerificate Authority file to verify the peer
333
-     *                              with (use with 'ssl_verify_peer') (string)</li>
334
-     *   <li> 'ssl_capath'        - Directory holding multiple Certificate
335
-     *                              Authority files (string)</li>
336
-     *   <li> 'ssl_local_cert'    - Name of a file containing local cerificate (string)</li>
337
-     *   <li> 'ssl_passphrase'    - Passphrase with which local certificate
338
-     *                              was encoded (string)</li>
339
-     *   <li> 'digest_compat_ie'  - Whether to imitate behaviour of MSIE 5 and 6
340
-     *                              in using URL without query string in digest
341
-     *                              authentication (boolean)</li>
342
-     *   <li> 'follow_redirects'  - Whether to automatically follow HTTP Redirects (boolean)</li>
343
-     *   <li> 'max_redirects'     - Maximum number of redirects to follow (integer)</li>
344
-     *   <li> 'strict_redirects'  - Whether to keep request method on redirects via status 301 and
345
-     *                              302 (true, needed for compatibility with RFC 2616)
346
-     *                              or switch to GET (false, needed for compatibility with most
347
-     *                              browsers) (boolean)</li>
348
-     * </ul>
349
-     *
350
-     * @param string|array $nameOrConfig configuration parameter name or array
351
-     *                                   ('parameter name' => 'parameter value')
352
-     * @param mixed        $value        parameter value if $nameOrConfig is not an array
353
-     *
354
-     * @return   HTTP_Request2
355
-     * @throws   HTTP_Request2_LogicException If the parameter is unknown
356
-     */
357
-    public function setConfig($nameOrConfig, $value = null)
358
-    {
359
-        if (is_array($nameOrConfig)) {
360
-            foreach ($nameOrConfig as $name => $value) {
361
-                $this->setConfig($name, $value);
362
-            }
363
-
364
-        } elseif ('proxy' == $nameOrConfig) {
365
-            $url = new Net_URL2($value);
366
-            $this->setConfig(array(
367
-                'proxy_type'     => $url->getScheme(),
368
-                'proxy_host'     => $url->getHost(),
369
-                'proxy_port'     => $url->getPort(),
370
-                'proxy_user'     => rawurldecode($url->getUser()),
371
-                'proxy_password' => rawurldecode($url->getPassword())
372
-            ));
373
-
374
-        } else {
375
-            if (!array_key_exists($nameOrConfig, $this->config)) {
376
-                throw new HTTP_Request2_LogicException(
377
-                    "Unknown configuration parameter '{$nameOrConfig}'",
378
-                    HTTP_Request2_Exception::INVALID_ARGUMENT
379
-                );
380
-            }
381
-            $this->config[$nameOrConfig] = $value;
382
-        }
383
-
384
-        return $this;
385
-    }
386
-
387
-    /**
388
-     * Returns the value(s) of the configuration parameter(s)
389
-     *
390
-     * @param string $name parameter name
391
-     *
392
-     * @return   mixed   value of $name parameter, array of all configuration
393
-     *                   parameters if $name is not given
394
-     * @throws   HTTP_Request2_LogicException If the parameter is unknown
395
-     */
396
-    public function getConfig($name = null)
397
-    {
398
-        if (null === $name) {
399
-            return $this->config;
400
-        } elseif (!array_key_exists($name, $this->config)) {
401
-            throw new HTTP_Request2_LogicException(
402
-                "Unknown configuration parameter '{$name}'",
403
-                HTTP_Request2_Exception::INVALID_ARGUMENT
404
-            );
405
-        }
406
-        return $this->config[$name];
407
-    }
408
-
409
-    /**
410
-     * Sets the autentification data
411
-     *
412
-     * @param string $user     user name
413
-     * @param string $password password
414
-     * @param string $scheme   authentication scheme
415
-     *
416
-     * @return   HTTP_Request2
417
-     */
418
-    public function setAuth($user, $password = '', $scheme = self::AUTH_BASIC)
419
-    {
420
-        if (empty($user)) {
421
-            $this->auth = null;
422
-        } else {
423
-            $this->auth = array(
424
-                'user'     => (string)$user,
425
-                'password' => (string)$password,
426
-                'scheme'   => $scheme
427
-            );
428
-        }
429
-
430
-        return $this;
431
-    }
432
-
433
-    /**
434
-     * Returns the authentication data
435
-     *
436
-     * The array has the keys 'user', 'password' and 'scheme', where 'scheme'
437
-     * is one of the HTTP_Request2::AUTH_* constants.
438
-     *
439
-     * @return   array
440
-     */
441
-    public function getAuth()
442
-    {
443
-        return $this->auth;
444
-    }
445
-
446
-    /**
447
-     * Sets request header(s)
448
-     *
449
-     * The first parameter may be either a full header string 'header: value' or
450
-     * header name. In the former case $value parameter is ignored, in the latter
451
-     * the header's value will either be set to $value or the header will be
452
-     * removed if $value is null. The first parameter can also be an array of
453
-     * headers, in that case method will be called recursively.
454
-     *
455
-     * Note that headers are treated case insensitively as per RFC 2616.
456
-     *
457
-     * <code>
458
-     * $req->setHeader('Foo: Bar'); // sets the value of 'Foo' header to 'Bar'
459
-     * $req->setHeader('FoO', 'Baz'); // sets the value of 'Foo' header to 'Baz'
460
-     * $req->setHeader(array('foo' => 'Quux')); // sets the value of 'Foo' header to 'Quux'
461
-     * $req->setHeader('FOO'); // removes 'Foo' header from request
462
-     * </code>
463
-     *
464
-     * @param string|array      $name    header name, header string ('Header: value')
465
-     *                                   or an array of headers
466
-     * @param string|array|null $value   header value if $name is not an array,
467
-     *                                   header will be removed if value is null
468
-     * @param bool              $replace whether to replace previous header with the
469
-     *                                   same name or append to its value
470
-     *
471
-     * @return   HTTP_Request2
472
-     * @throws   HTTP_Request2_LogicException
473
-     */
474
-    public function setHeader($name, $value = null, $replace = true)
475
-    {
476
-        if (is_array($name)) {
477
-            foreach ($name as $k => $v) {
478
-                if (is_string($k)) {
479
-                    $this->setHeader($k, $v, $replace);
480
-                } else {
481
-                    $this->setHeader($v, null, $replace);
482
-                }
483
-            }
484
-        } else {
485
-            if (null === $value && strpos($name, ':')) {
486
-                list($name, $value) = array_map('trim', explode(':', $name, 2));
487
-            }
488
-            // Header name should be a token: http://tools.ietf.org/html/rfc2616#section-4.2
489
-            if (preg_match(self::REGEXP_INVALID_TOKEN, $name)) {
490
-                throw new HTTP_Request2_LogicException(
491
-                    "Invalid header name '{$name}'",
492
-                    HTTP_Request2_Exception::INVALID_ARGUMENT
493
-                );
494
-            }
495
-            // Header names are case insensitive anyway
496
-            $name = strtolower($name);
497
-            if (null === $value) {
498
-                unset($this->headers[$name]);
499
-
500
-            } else {
501
-                if (is_array($value)) {
502
-                    $value = implode(', ', array_map('trim', $value));
503
-                } elseif (is_string($value)) {
504
-                    $value = trim($value);
505
-                }
506
-                if (!isset($this->headers[$name]) || $replace) {
507
-                    $this->headers[$name] = $value;
508
-                } else {
509
-                    $this->headers[$name] .= ', ' . $value;
510
-                }
511
-            }
512
-        }
513
-
514
-        return $this;
515
-    }
516
-
517
-    /**
518
-     * Returns the request headers
519
-     *
520
-     * The array is of the form ('header name' => 'header value'), header names
521
-     * are lowercased
522
-     *
523
-     * @return   array
524
-     */
525
-    public function getHeaders()
526
-    {
527
-        return $this->headers;
528
-    }
529
-
530
-    /**
531
-     * Adds a cookie to the request
532
-     *
533
-     * If the request does not have a CookieJar object set, this method simply
534
-     * appends a cookie to "Cookie:" header.
535
-     *
536
-     * If a CookieJar object is available, the cookie is stored in that object.
537
-     * Data from request URL will be used for setting its 'domain' and 'path'
538
-     * parameters, 'expires' and 'secure' will be set to null and false,
539
-     * respectively. If you need further control, use CookieJar's methods.
540
-     *
541
-     * @param string $name  cookie name
542
-     * @param string $value cookie value
543
-     *
544
-     * @return   HTTP_Request2
545
-     * @throws   HTTP_Request2_LogicException
546
-     * @see      setCookieJar()
547
-     */
548
-    public function addCookie($name, $value)
549
-    {
550
-        if (!empty($this->cookieJar)) {
551
-            $this->cookieJar->store(
552
-                array('name' => $name, 'value' => $value), $this->url
553
-            );
554
-
555
-        } else {
556
-            $cookie = $name . '=' . $value;
557
-            if (preg_match(self::REGEXP_INVALID_COOKIE, $cookie)) {
558
-                throw new HTTP_Request2_LogicException(
559
-                    "Invalid cookie: '{$cookie}'",
560
-                    HTTP_Request2_Exception::INVALID_ARGUMENT
561
-                );
562
-            }
563
-            $cookies = empty($this->headers['cookie'])? '': $this->headers['cookie'] . '; ';
564
-            $this->setHeader('cookie', $cookies . $cookie);
565
-        }
566
-
567
-        return $this;
568
-    }
569
-
570
-    /**
571
-     * Sets the request body
572
-     *
573
-     * If you provide file pointer rather than file name, it should support
574
-     * fstat() and rewind() operations.
575
-     *
576
-     * @param string|resource|HTTP_Request2_MultipartBody $body       Either a
577
-     *               string with the body or filename containing body or
578
-     *               pointer to an open file or object with multipart body data
579
-     * @param bool                                        $isFilename Whether
580
-     *               first parameter is a filename
581
-     *
582
-     * @return   HTTP_Request2
583
-     * @throws   HTTP_Request2_LogicException
584
-     */
585
-    public function setBody($body, $isFilename = false)
586
-    {
587
-        if (!$isFilename && !is_resource($body)) {
588
-            if (!$body instanceof HTTP_Request2_MultipartBody) {
589
-                $this->body = (string)$body;
590
-            } else {
591
-                $this->body = $body;
592
-            }
593
-        } else {
594
-            $fileData = $this->fopenWrapper($body, empty($this->headers['content-type']));
595
-            $this->body = $fileData['fp'];
596
-            if (empty($this->headers['content-type'])) {
597
-                $this->setHeader('content-type', $fileData['type']);
598
-            }
599
-        }
600
-        $this->postParams = $this->uploads = array();
601
-
602
-        return $this;
603
-    }
604
-
605
-    /**
606
-     * Returns the request body
607
-     *
608
-     * @return   string|resource|HTTP_Request2_MultipartBody
609
-     */
610
-    public function getBody()
611
-    {
612
-        if (self::METHOD_POST == $this->method
613
-            && (!empty($this->postParams) || !empty($this->uploads))
614
-        ) {
615
-            if (0 === strpos($this->headers['content-type'], 'application/x-www-form-urlencoded')) {
616
-                $body = http_build_query($this->postParams, '', '&');
617
-                if (!$this->getConfig('use_brackets')) {
618
-                    $body = preg_replace('/%5B\d+%5D=/', '=', $body);
619
-                }
620
-                // support RFC 3986 by not encoding '~' symbol (request #15368)
621
-                return str_replace('%7E', '~', $body);
622
-
623
-            } elseif (0 === strpos($this->headers['content-type'], 'multipart/form-data')) {
624
-                require_once 'HTTP/Request2/MultipartBody.php';
625
-                return new HTTP_Request2_MultipartBody(
626
-                    $this->postParams, $this->uploads, $this->getConfig('use_brackets')
627
-                );
628
-            }
629
-        }
630
-        return $this->body;
631
-    }
632
-
633
-    /**
634
-     * Adds a file to form-based file upload
635
-     *
636
-     * Used to emulate file upload via a HTML form. The method also sets
637
-     * Content-Type of HTTP request to 'multipart/form-data'.
638
-     *
639
-     * If you just want to send the contents of a file as the body of HTTP
640
-     * request you should use setBody() method.
641
-     *
642
-     * If you provide file pointers rather than file names, they should support
643
-     * fstat() and rewind() operations.
644
-     *
645
-     * @param string                $fieldName    name of file-upload field
646
-     * @param string|resource|array $filename     full name of local file,
647
-     *               pointer to open file or an array of files
648
-     * @param string                $sendFilename filename to send in the request
649
-     * @param string                $contentType  content-type of file being uploaded
650
-     *
651
-     * @return   HTTP_Request2
652
-     * @throws   HTTP_Request2_LogicException
653
-     */
654
-    public function addUpload(
655
-        $fieldName, $filename, $sendFilename = null, $contentType = null
656
-    ) {
657
-        if (!is_array($filename)) {
658
-            $fileData = $this->fopenWrapper($filename, empty($contentType));
659
-            $this->uploads[$fieldName] = array(
660
-                'fp'        => $fileData['fp'],
661
-                'filename'  => !empty($sendFilename)? $sendFilename
662
-                                :(is_string($filename)? basename($filename): 'anonymous.blob') ,
663
-                'size'      => $fileData['size'],
664
-                'type'      => empty($contentType)? $fileData['type']: $contentType
665
-            );
666
-        } else {
667
-            $fps = $names = $sizes = $types = array();
668
-            foreach ($filename as $f) {
669
-                if (!is_array($f)) {
670
-                    $f = array($f);
671
-                }
672
-                $fileData = $this->fopenWrapper($f[0], empty($f[2]));
673
-                $fps[]   = $fileData['fp'];
674
-                $names[] = !empty($f[1])? $f[1]
675
-                            :(is_string($f[0])? basename($f[0]): 'anonymous.blob');
676
-                $sizes[] = $fileData['size'];
677
-                $types[] = empty($f[2])? $fileData['type']: $f[2];
678
-            }
679
-            $this->uploads[$fieldName] = array(
680
-                'fp' => $fps, 'filename' => $names, 'size' => $sizes, 'type' => $types
681
-            );
682
-        }
683
-        if (empty($this->headers['content-type'])
684
-            || 'application/x-www-form-urlencoded' == $this->headers['content-type']
685
-        ) {
686
-            $this->setHeader('content-type', 'multipart/form-data');
687
-        }
688
-
689
-        return $this;
690
-    }
691
-
692
-    /**
693
-     * Adds POST parameter(s) to the request.
694
-     *
695
-     * @param string|array $name  parameter name or array ('name' => 'value')
696
-     * @param mixed        $value parameter value (can be an array)
697
-     *
698
-     * @return   HTTP_Request2
699
-     */
700
-    public function addPostParameter($name, $value = null)
701
-    {
702
-        if (!is_array($name)) {
703
-            $this->postParams[$name] = $value;
704
-        } else {
705
-            foreach ($name as $k => $v) {
706
-                $this->addPostParameter($k, $v);
707
-            }
708
-        }
709
-        if (empty($this->headers['content-type'])) {
710
-            $this->setHeader('content-type', 'application/x-www-form-urlencoded');
711
-        }
712
-
713
-        return $this;
714
-    }
715
-
716
-    /**
717
-     * Attaches a new observer
718
-     *
719
-     * @param SplObserver $observer any object implementing SplObserver
720
-     */
721
-    public function attach(SplObserver $observer)
722
-    {
723
-        foreach ($this->observers as $attached) {
724
-            if ($attached === $observer) {
725
-                return;
726
-            }
727
-        }
728
-        $this->observers[] = $observer;
729
-    }
730
-
731
-    /**
732
-     * Detaches an existing observer
733
-     *
734
-     * @param SplObserver $observer any object implementing SplObserver
735
-     */
736
-    public function detach(SplObserver $observer)
737
-    {
738
-        foreach ($this->observers as $key => $attached) {
739
-            if ($attached === $observer) {
740
-                unset($this->observers[$key]);
741
-                return;
742
-            }
743
-        }
744
-    }
745
-
746
-    /**
747
-     * Notifies all observers
748
-     */
749
-    public function notify()
750
-    {
751
-        foreach ($this->observers as $observer) {
752
-            $observer->update($this);
753
-        }
754
-    }
755
-
756
-    /**
757
-     * Sets the last event
758
-     *
759
-     * Adapters should use this method to set the current state of the request
760
-     * and notify the observers.
761
-     *
762
-     * @param string $name event name
763
-     * @param mixed  $data event data
764
-     */
765
-    public function setLastEvent($name, $data = null)
766
-    {
767
-        $this->lastEvent = array(
768
-            'name' => $name,
769
-            'data' => $data
770
-        );
771
-        $this->notify();
772
-    }
773
-
774
-    /**
775
-     * Returns the last event
776
-     *
777
-     * Observers should use this method to access the last change in request.
778
-     * The following event names are possible:
779
-     * <ul>
780
-     *   <li>'connect'                 - after connection to remote server,
781
-     *                                   data is the destination (string)</li>
782
-     *   <li>'disconnect'              - after disconnection from server</li>
783
-     *   <li>'sentHeaders'             - after sending the request headers,
784
-     *                                   data is the headers sent (string)</li>
785
-     *   <li>'sentBodyPart'            - after sending a part of the request body,
786
-     *                                   data is the length of that part (int)</li>
787
-     *   <li>'sentBody'                - after sending the whole request body,
788
-     *                                   data is request body length (int)</li>
789
-     *   <li>'receivedHeaders'         - after receiving the response headers,
790
-     *                                   data is HTTP_Request2_Response object</li>
791
-     *   <li>'receivedBodyPart'        - after receiving a part of the response
792
-     *                                   body, data is that part (string)</li>
793
-     *   <li>'receivedEncodedBodyPart' - as 'receivedBodyPart', but data is still
794
-     *                                   encoded by Content-Encoding</li>
795
-     *   <li>'receivedBody'            - after receiving the complete response
796
-     *                                   body, data is HTTP_Request2_Response object</li>
797
-     * </ul>
798
-     * Different adapters may not send all the event types. Mock adapter does
799
-     * not send any events to the observers.
800
-     *
801
-     * @return   array   The array has two keys: 'name' and 'data'
802
-     */
803
-    public function getLastEvent()
804
-    {
805
-        return $this->lastEvent;
806
-    }
807
-
808
-    /**
809
-     * Sets the adapter used to actually perform the request
810
-     *
811
-     * You can pass either an instance of a class implementing HTTP_Request2_Adapter
812
-     * or a class name. The method will only try to include a file if the class
813
-     * name starts with HTTP_Request2_Adapter_, it will also try to prepend this
814
-     * prefix to the class name if it doesn't contain any underscores, so that
815
-     * <code>
816
-     * $request->setAdapter('curl');
817
-     * </code>
818
-     * will work.
819
-     *
820
-     * @param string|HTTP_Request2_Adapter $adapter Adapter to use
821
-     *
822
-     * @return   HTTP_Request2
823
-     * @throws   HTTP_Request2_LogicException
824
-     */
825
-    public function setAdapter($adapter)
826
-    {
827
-        if (is_string($adapter)) {
828
-            if (!class_exists($adapter, false)) {
829
-                if (false === strpos($adapter, '_')) {
830
-                    $adapter = 'HTTP_Request2_Adapter_' . ucfirst($adapter);
831
-                }
832
-                if (!class_exists($adapter, false)
833
-                    && preg_match('/^HTTP_Request2_Adapter_([a-zA-Z0-9]+)$/', $adapter)
834
-                ) {
835
-                    include_once str_replace('_', DIRECTORY_SEPARATOR, $adapter) . '.php';
836
-                }
837
-                if (!class_exists($adapter, false)) {
838
-                    throw new HTTP_Request2_LogicException(
839
-                        "Class {$adapter} not found",
840
-                        HTTP_Request2_Exception::MISSING_VALUE
841
-                    );
842
-                }
843
-            }
844
-            $adapter = new $adapter;
845
-        }
846
-        if (!$adapter instanceof HTTP_Request2_Adapter) {
847
-            throw new HTTP_Request2_LogicException(
848
-                'Parameter is not a HTTP request adapter',
849
-                HTTP_Request2_Exception::INVALID_ARGUMENT
850
-            );
851
-        }
852
-        $this->adapter = $adapter;
853
-
854
-        return $this;
855
-    }
856
-
857
-    /**
858
-     * Sets the cookie jar
859
-     *
860
-     * A cookie jar is used to maintain cookies across HTTP requests and
861
-     * responses. Cookies from jar will be automatically added to the request
862
-     * headers based on request URL.
863
-     *
864
-     * @param HTTP_Request2_CookieJar|bool $jar Existing CookieJar object, true to
865
-     *                                          create a new one, false to remove
866
-     *
867
-     * @return HTTP_Request2
868
-     * @throws HTTP_Request2_LogicException
869
-     */
870
-    public function setCookieJar($jar = true)
871
-    {
872
-        if (!class_exists('HTTP_Request2_CookieJar', false)) {
873
-            require_once 'HTTP/Request2/CookieJar.php';
874
-        }
875
-
876
-        if ($jar instanceof HTTP_Request2_CookieJar) {
877
-            $this->cookieJar = $jar;
878
-        } elseif (true === $jar) {
879
-            $this->cookieJar = new HTTP_Request2_CookieJar();
880
-        } elseif (!$jar) {
881
-            $this->cookieJar = null;
882
-        } else {
883
-            throw new HTTP_Request2_LogicException(
884
-                'Invalid parameter passed to setCookieJar()',
885
-                HTTP_Request2_Exception::INVALID_ARGUMENT
886
-            );
887
-        }
888
-
889
-        return $this;
890
-    }
891
-
892
-    /**
893
-     * Returns current CookieJar object or null if none
894
-     *
895
-     * @return HTTP_Request2_CookieJar|null
896
-     */
897
-    public function getCookieJar()
898
-    {
899
-        return $this->cookieJar;
900
-    }
901
-
902
-    /**
903
-     * Sends the request and returns the response
904
-     *
905
-     * @throws   HTTP_Request2_Exception
906
-     * @return   HTTP_Request2_Response
907
-     */
908
-    public function send()
909
-    {
910
-        // Sanity check for URL
911
-        if (!$this->url instanceof Net_URL2
912
-            || !$this->url->isAbsolute()
913
-            || !in_array(strtolower($this->url->getScheme()), array('https', 'http'))
914
-        ) {
915
-            throw new HTTP_Request2_LogicException(
916
-                'HTTP_Request2 needs an absolute HTTP(S) request URL, '
917
-                . ($this->url instanceof Net_URL2
918
-                   ? "'" . $this->url->__toString() . "'" : 'none')
919
-                . ' given',
920
-                HTTP_Request2_Exception::INVALID_ARGUMENT
921
-            );
922
-        }
923
-        if (empty($this->adapter)) {
924
-            $this->setAdapter($this->getConfig('adapter'));
925
-        }
926
-        // magic_quotes_runtime may break file uploads and chunked response
927
-        // processing; see bug #4543. Don't use ini_get() here; see bug #16440.
928
-        if ($magicQuotes = get_magic_quotes_runtime()) {
929
-            set_magic_quotes_runtime(false);
930
-        }
931
-        // force using single byte encoding if mbstring extension overloads
932
-        // strlen() and substr(); see bug #1781, bug #10605
933
-        if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
934
-            $oldEncoding = mb_internal_encoding();
935
-            mb_internal_encoding('8bit');
936
-        }
937
-
938
-        try {
939
-            $response = $this->adapter->sendRequest($this);
940
-        } catch (Exception $e) {
941
-        }
942
-        // cleanup in either case (poor man's "finally" clause)
943
-        if ($magicQuotes) {
944
-            set_magic_quotes_runtime(true);
945
-        }
946
-        if (!empty($oldEncoding)) {
947
-            mb_internal_encoding($oldEncoding);
948
-        }
949
-        // rethrow the exception
950
-        if (!empty($e)) {
951
-            throw $e;
952
-        }
953
-        return $response;
954
-    }
955
-
956
-    /**
957
-     * Wrapper around fopen()/fstat() used by setBody() and addUpload()
958
-     *
959
-     * @param string|resource $file       file name or pointer to open file
960
-     * @param bool            $detectType whether to try autodetecting MIME
961
-     *                        type of file, will only work if $file is a
962
-     *                        filename, not pointer
963
-     *
964
-     * @return array array('fp' => file pointer, 'size' => file size, 'type' => MIME type)
965
-     * @throws HTTP_Request2_LogicException
966
-     */
967
-    protected function fopenWrapper($file, $detectType = false)
968
-    {
969
-        if (!is_string($file) && !is_resource($file)) {
970
-            throw new HTTP_Request2_LogicException(
971
-                "Filename or file pointer resource expected",
972
-                HTTP_Request2_Exception::INVALID_ARGUMENT
973
-            );
974
-        }
975
-        $fileData = array(
976
-            'fp'   => is_string($file)? null: $file,
977
-            'type' => 'application/octet-stream',
978
-            'size' => 0
979
-        );
980
-        if (is_string($file)) {
981
-            if (!($fileData['fp'] = @fopen($file, 'rb'))) {
982
-                $error = error_get_last();
983
-                throw new HTTP_Request2_LogicException(
984
-                    $error['message'], HTTP_Request2_Exception::READ_ERROR
985
-                );
986
-            }
987
-            if ($detectType) {
988
-                $fileData['type'] = self::detectMimeType($file);
989
-            }
990
-        }
991
-        if (!($stat = fstat($fileData['fp']))) {
992
-            throw new HTTP_Request2_LogicException(
993
-                "fstat() call failed", HTTP_Request2_Exception::READ_ERROR
994
-            );
995
-        }
996
-        $fileData['size'] = $stat['size'];
997
-
998
-        return $fileData;
999
-    }
1000
-
1001
-    /**
1002
-     * Tries to detect MIME type of a file
1003
-     *
1004
-     * The method will try to use fileinfo extension if it is available,
1005
-     * deprecated mime_content_type() function in the other case. If neither
1006
-     * works, default 'application/octet-stream' MIME type is returned
1007
-     *
1008
-     * @param string $filename file name
1009
-     *
1010
-     * @return   string  file MIME type
1011
-     */
1012
-    protected static function detectMimeType($filename)
1013
-    {
1014
-        // finfo extension from PECL available
1015
-        if (function_exists('finfo_open')) {
1016
-            if (!isset(self::$_fileinfoDb)) {
1017
-                self::$_fileinfoDb = @finfo_open(FILEINFO_MIME);
1018
-            }
1019
-            if (self::$_fileinfoDb) {
1020
-                $info = finfo_file(self::$_fileinfoDb, $filename);
1021
-            }
1022
-        }
1023
-        // (deprecated) mime_content_type function available
1024
-        if (empty($info) && function_exists('mime_content_type')) {
1025
-            return mime_content_type($filename);
1026
-        }
1027
-        return empty($info)? 'application/octet-stream': $info;
1028
-    }
64
+	const AUTH_BASIC  = 'basic';
65
+	const AUTH_DIGEST = 'digest';
66
+	/**#@-*/
67
+
68
+	/**
69
+	 * Regular expression used to check for invalid symbols in RFC 2616 tokens
70
+	 * @link http://pear.php.net/bugs/bug.php?id=15630
71
+	 */
72
+	const REGEXP_INVALID_TOKEN = '![\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]!';
73
+
74
+	/**
75
+	 * Regular expression used to check for invalid symbols in cookie strings
76
+	 * @link http://pear.php.net/bugs/bug.php?id=15630
77
+	 * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html
78
+	 */
79
+	const REGEXP_INVALID_COOKIE = '/[\s,;]/';
80
+
81
+	/**
82
+	 * Fileinfo magic database resource
83
+	 * @var  resource
84
+	 * @see  detectMimeType()
85
+	 */
86
+	private static $_fileinfoDb;
87
+
88
+	/**
89
+	 * Observers attached to the request (instances of SplObserver)
90
+	 * @var  array
91
+	 */
92
+	protected $observers = array();
93
+
94
+	/**
95
+	 * Request URL
96
+	 * @var  Net_URL2
97
+	 */
98
+	protected $url;
99
+
100
+	/**
101
+	 * Request method
102
+	 * @var  string
103
+	 */
104
+	protected $method = self::METHOD_GET;
105
+
106
+	/**
107
+	 * Authentication data
108
+	 * @var  array
109
+	 * @see  getAuth()
110
+	 */
111
+	protected $auth;
112
+
113
+	/**
114
+	 * Request headers
115
+	 * @var  array
116
+	 */
117
+	protected $headers = array();
118
+
119
+	/**
120
+	 * Configuration parameters
121
+	 * @var  array
122
+	 * @see  setConfig()
123
+	 */
124
+	protected $config = array(
125
+		'adapter'           => 'HTTP_Request2_Adapter_Socket',
126
+		'connect_timeout'   => 10,
127
+		'timeout'           => 0,
128
+		'use_brackets'      => true,
129
+		'protocol_version'  => '1.1',
130
+		'buffer_size'       => 16384,
131
+		'store_body'        => true,
132
+		'local_ip'          => null,
133
+
134
+		'proxy_host'        => '',
135
+		'proxy_port'        => '',
136
+		'proxy_user'        => '',
137
+		'proxy_password'    => '',
138
+		'proxy_auth_scheme' => self::AUTH_BASIC,
139
+		'proxy_type'        => 'http',
140
+
141
+		'ssl_verify_peer'   => true,
142
+		'ssl_verify_host'   => true,
143
+		'ssl_cafile'        => null,
144
+		'ssl_capath'        => null,
145
+		'ssl_local_cert'    => null,
146
+		'ssl_passphrase'    => null,
147
+
148
+		'digest_compat_ie'  => false,
149
+
150
+		'follow_redirects'  => false,
151
+		'max_redirects'     => 5,
152
+		'strict_redirects'  => false
153
+	);
154
+
155
+	/**
156
+	 * Last event in request / response handling, intended for observers
157
+	 * @var  array
158
+	 * @see  getLastEvent()
159
+	 */
160
+	protected $lastEvent = array(
161
+		'name' => 'start',
162
+		'data' => null
163
+	);
164
+
165
+	/**
166
+	 * Request body
167
+	 * @var  string|resource
168
+	 * @see  setBody()
169
+	 */
170
+	protected $body = '';
171
+
172
+	/**
173
+	 * Array of POST parameters
174
+	 * @var  array
175
+	 */
176
+	protected $postParams = array();
177
+
178
+	/**
179
+	 * Array of file uploads (for multipart/form-data POST requests)
180
+	 * @var  array
181
+	 */
182
+	protected $uploads = array();
183
+
184
+	/**
185
+	 * Adapter used to perform actual HTTP request
186
+	 * @var  HTTP_Request2_Adapter
187
+	 */
188
+	protected $adapter;
189
+
190
+	/**
191
+	 * Cookie jar to persist cookies between requests
192
+	 * @var HTTP_Request2_CookieJar
193
+	 */
194
+	protected $cookieJar = null;
195
+
196
+	/**
197
+	 * Constructor. Can set request URL, method and configuration array.
198
+	 *
199
+	 * Also sets a default value for User-Agent header.
200
+	 *
201
+	 * @param string|Net_Url2 $url    Request URL
202
+	 * @param string          $method Request method
203
+	 * @param array           $config Configuration for this Request instance
204
+	 */
205
+	public function __construct(
206
+		$url = null, $method = self::METHOD_GET, array $config = array()
207
+	) {
208
+		$this->setConfig($config);
209
+		if (!empty($url)) {
210
+			$this->setUrl($url);
211
+		}
212
+		if (!empty($method)) {
213
+			$this->setMethod($method);
214
+		}
215
+		$this->setHeader(
216
+			'user-agent', 'HTTP_Request2/2.2.1 ' .
217
+			'(http://pear.php.net/package/http_request2) PHP/' . phpversion()
218
+		);
219
+	}
220
+
221
+	/**
222
+	 * Sets the URL for this request
223
+	 *
224
+	 * If the URL has userinfo part (username & password) these will be removed
225
+	 * and converted to auth data. If the URL does not have a path component,
226
+	 * that will be set to '/'.
227
+	 *
228
+	 * @param string|Net_URL2 $url Request URL
229
+	 *
230
+	 * @return   HTTP_Request2
231
+	 * @throws   HTTP_Request2_LogicException
232
+	 */
233
+	public function setUrl($url)
234
+	{
235
+		if (is_string($url)) {
236
+			$url = new Net_URL2(
237
+				$url, array(Net_URL2::OPTION_USE_BRACKETS => $this->config['use_brackets'])
238
+			);
239
+		}
240
+		if (!$url instanceof Net_URL2) {
241
+			throw new HTTP_Request2_LogicException(
242
+				'Parameter is not a valid HTTP URL',
243
+				HTTP_Request2_Exception::INVALID_ARGUMENT
244
+			);
245
+		}
246
+		// URL contains username / password?
247
+		if ($url->getUserinfo()) {
248
+			$username = $url->getUser();
249
+			$password = $url->getPassword();
250
+			$this->setAuth(rawurldecode($username), $password? rawurldecode($password): '');
251
+			$url->setUserinfo('');
252
+		}
253
+		if ('' == $url->getPath()) {
254
+			$url->setPath('/');
255
+		}
256
+		$this->url = $url;
257
+
258
+		return $this;
259
+	}
260
+
261
+	/**
262
+	 * Returns the request URL
263
+	 *
264
+	 * @return   Net_URL2
265
+	 */
266
+	public function getUrl()
267
+	{
268
+		return $this->url;
269
+	}
270
+
271
+	/**
272
+	 * Sets the request method
273
+	 *
274
+	 * @param string $method one of the methods defined in RFC 2616
275
+	 *
276
+	 * @return   HTTP_Request2
277
+	 * @throws   HTTP_Request2_LogicException if the method name is invalid
278
+	 */
279
+	public function setMethod($method)
280
+	{
281
+		// Method name should be a token: http://tools.ietf.org/html/rfc2616#section-5.1.1
282
+		if (preg_match(self::REGEXP_INVALID_TOKEN, $method)) {
283
+			throw new HTTP_Request2_LogicException(
284
+				"Invalid request method '{$method}'",
285
+				HTTP_Request2_Exception::INVALID_ARGUMENT
286
+			);
287
+		}
288
+		$this->method = $method;
289
+
290
+		return $this;
291
+	}
292
+
293
+	/**
294
+	 * Returns the request method
295
+	 *
296
+	 * @return   string
297
+	 */
298
+	public function getMethod()
299
+	{
300
+		return $this->method;
301
+	}
302
+
303
+	/**
304
+	 * Sets the configuration parameter(s)
305
+	 *
306
+	 * The following parameters are available:
307
+	 * <ul>
308
+	 *   <li> 'adapter'           - adapter to use (string)</li>
309
+	 *   <li> 'connect_timeout'   - Connection timeout in seconds (integer)</li>
310
+	 *   <li> 'timeout'           - Total number of seconds a request can take.
311
+	 *                              Use 0 for no limit, should be greater than
312
+	 *                              'connect_timeout' if set (integer)</li>
313
+	 *   <li> 'use_brackets'      - Whether to append [] to array variable names (bool)</li>
314
+	 *   <li> 'protocol_version'  - HTTP Version to use, '1.0' or '1.1' (string)</li>
315
+	 *   <li> 'buffer_size'       - Buffer size to use for reading and writing (int)</li>
316
+	 *   <li> 'store_body'        - Whether to store response body in response object.
317
+	 *                              Set to false if receiving a huge response and
318
+	 *                              using an Observer to save it (boolean)</li>
319
+	 *   <li> 'local_ip'          - Specifies the IP address that will be used for accessing
320
+	 *                              the network (string)</li>
321
+	 *   <li> 'proxy_type'        - Proxy type, 'http' or 'socks5' (string)</li>
322
+	 *   <li> 'proxy_host'        - Proxy server host (string)</li>
323
+	 *   <li> 'proxy_port'        - Proxy server port (integer)</li>
324
+	 *   <li> 'proxy_user'        - Proxy auth username (string)</li>
325
+	 *   <li> 'proxy_password'    - Proxy auth password (string)</li>
326
+	 *   <li> 'proxy_auth_scheme' - Proxy auth scheme, one of HTTP_Request2::AUTH_* constants (string)</li>
327
+	 *   <li> 'proxy'             - Shorthand for proxy_* parameters, proxy given as URL,
328
+	 *                              e.g. 'socks5://localhost:1080/' (string)</li>
329
+	 *   <li> 'ssl_verify_peer'   - Whether to verify peer's SSL certificate (bool)</li>
330
+	 *   <li> 'ssl_verify_host'   - Whether to check that Common Name in SSL
331
+	 *                              certificate matches host name (bool)</li>
332
+	 *   <li> 'ssl_cafile'        - Cerificate Authority file to verify the peer
333
+	 *                              with (use with 'ssl_verify_peer') (string)</li>
334
+	 *   <li> 'ssl_capath'        - Directory holding multiple Certificate
335
+	 *                              Authority files (string)</li>
336
+	 *   <li> 'ssl_local_cert'    - Name of a file containing local cerificate (string)</li>
337
+	 *   <li> 'ssl_passphrase'    - Passphrase with which local certificate
338
+	 *                              was encoded (string)</li>
339
+	 *   <li> 'digest_compat_ie'  - Whether to imitate behaviour of MSIE 5 and 6
340
+	 *                              in using URL without query string in digest
341
+	 *                              authentication (boolean)</li>
342
+	 *   <li> 'follow_redirects'  - Whether to automatically follow HTTP Redirects (boolean)</li>
343
+	 *   <li> 'max_redirects'     - Maximum number of redirects to follow (integer)</li>
344
+	 *   <li> 'strict_redirects'  - Whether to keep request method on redirects via status 301 and
345
+	 *                              302 (true, needed for compatibility with RFC 2616)
346
+	 *                              or switch to GET (false, needed for compatibility with most
347
+	 *                              browsers) (boolean)</li>
348
+	 * </ul>
349
+	 *
350
+	 * @param string|array $nameOrConfig configuration parameter name or array
351
+	 *                                   ('parameter name' => 'parameter value')
352
+	 * @param mixed        $value        parameter value if $nameOrConfig is not an array
353
+	 *
354
+	 * @return   HTTP_Request2
355
+	 * @throws   HTTP_Request2_LogicException If the parameter is unknown
356
+	 */
357
+	public function setConfig($nameOrConfig, $value = null)
358
+	{
359
+		if (is_array($nameOrConfig)) {
360
+			foreach ($nameOrConfig as $name => $value) {
361
+				$this->setConfig($name, $value);
362
+			}
363
+
364
+		} elseif ('proxy' == $nameOrConfig) {
365
+			$url = new Net_URL2($value);
366
+			$this->setConfig(array(
367
+				'proxy_type'     => $url->getScheme(),
368
+				'proxy_host'     => $url->getHost(),
369
+				'proxy_port'     => $url->getPort(),
370
+				'proxy_user'     => rawurldecode($url->getUser()),
371
+				'proxy_password' => rawurldecode($url->getPassword())
372
+			));
373
+
374
+		} else {
375
+			if (!array_key_exists($nameOrConfig, $this->config)) {
376
+				throw new HTTP_Request2_LogicException(
377
+					"Unknown configuration parameter '{$nameOrConfig}'",
378
+					HTTP_Request2_Exception::INVALID_ARGUMENT
379
+				);
380
+			}
381
+			$this->config[$nameOrConfig] = $value;
382
+		}
383
+
384
+		return $this;
385
+	}
386
+
387
+	/**
388
+	 * Returns the value(s) of the configuration parameter(s)
389
+	 *
390
+	 * @param string $name parameter name
391
+	 *
392
+	 * @return   mixed   value of $name parameter, array of all configuration
393
+	 *                   parameters if $name is not given
394
+	 * @throws   HTTP_Request2_LogicException If the parameter is unknown
395
+	 */
396
+	public function getConfig($name = null)
397
+	{
398
+		if (null === $name) {
399
+			return $this->config;
400
+		} elseif (!array_key_exists($name, $this->config)) {
401
+			throw new HTTP_Request2_LogicException(
402
+				"Unknown configuration parameter '{$name}'",
403
+				HTTP_Request2_Exception::INVALID_ARGUMENT
404
+			);
405
+		}
406
+		return $this->config[$name];
407
+	}
408
+
409
+	/**
410
+	 * Sets the autentification data
411
+	 *
412
+	 * @param string $user     user name
413
+	 * @param string $password password
414
+	 * @param string $scheme   authentication scheme
415
+	 *
416
+	 * @return   HTTP_Request2
417
+	 */
418
+	public function setAuth($user, $password = '', $scheme = self::AUTH_BASIC)
419
+	{
420
+		if (empty($user)) {
421
+			$this->auth = null;
422
+		} else {
423
+			$this->auth = array(
424
+				'user'     => (string)$user,
425
+				'password' => (string)$password,
426
+				'scheme'   => $scheme
427
+			);
428
+		}
429
+
430
+		return $this;
431
+	}
432
+
433
+	/**
434
+	 * Returns the authentication data
435
+	 *
436
+	 * The array has the keys 'user', 'password' and 'scheme', where 'scheme'
437
+	 * is one of the HTTP_Request2::AUTH_* constants.
438
+	 *
439
+	 * @return   array
440
+	 */
441
+	public function getAuth()
442
+	{
443
+		return $this->auth;
444
+	}
445
+
446
+	/**
447
+	 * Sets request header(s)
448
+	 *
449
+	 * The first parameter may be either a full header string 'header: value' or
450
+	 * header name. In the former case $value parameter is ignored, in the latter
451
+	 * the header's value will either be set to $value or the header will be
452
+	 * removed if $value is null. The first parameter can also be an array of
453
+	 * headers, in that case method will be called recursively.
454
+	 *
455
+	 * Note that headers are treated case insensitively as per RFC 2616.
456
+	 *
457
+	 * <code>
458
+	 * $req->setHeader('Foo: Bar'); // sets the value of 'Foo' header to 'Bar'
459
+	 * $req->setHeader('FoO', 'Baz'); // sets the value of 'Foo' header to 'Baz'
460
+	 * $req->setHeader(array('foo' => 'Quux')); // sets the value of 'Foo' header to 'Quux'
461
+	 * $req->setHeader('FOO'); // removes 'Foo' header from request
462
+	 * </code>
463
+	 *
464
+	 * @param string|array      $name    header name, header string ('Header: value')
465
+	 *                                   or an array of headers
466
+	 * @param string|array|null $value   header value if $name is not an array,
467
+	 *                                   header will be removed if value is null
468
+	 * @param bool              $replace whether to replace previous header with the
469
+	 *                                   same name or append to its value
470
+	 *
471
+	 * @return   HTTP_Request2
472
+	 * @throws   HTTP_Request2_LogicException
473
+	 */
474
+	public function setHeader($name, $value = null, $replace = true)
475
+	{
476
+		if (is_array($name)) {
477
+			foreach ($name as $k => $v) {
478
+				if (is_string($k)) {
479
+					$this->setHeader($k, $v, $replace);
480
+				} else {
481
+					$this->setHeader($v, null, $replace);
482
+				}
483
+			}
484
+		} else {
485
+			if (null === $value && strpos($name, ':')) {
486
+				list($name, $value) = array_map('trim', explode(':', $name, 2));
487
+			}
488
+			// Header name should be a token: http://tools.ietf.org/html/rfc2616#section-4.2
489
+			if (preg_match(self::REGEXP_INVALID_TOKEN, $name)) {
490
+				throw new HTTP_Request2_LogicException(
491
+					"Invalid header name '{$name}'",
492
+					HTTP_Request2_Exception::INVALID_ARGUMENT
493
+				);
494
+			}
495
+			// Header names are case insensitive anyway
496
+			$name = strtolower($name);
497
+			if (null === $value) {
498
+				unset($this->headers[$name]);
499
+
500
+			} else {
501
+				if (is_array($value)) {
502
+					$value = implode(', ', array_map('trim', $value));
503
+				} elseif (is_string($value)) {
504
+					$value = trim($value);
505
+				}
506
+				if (!isset($this->headers[$name]) || $replace) {
507
+					$this->headers[$name] = $value;
508
+				} else {
509
+					$this->headers[$name] .= ', ' . $value;
510
+				}
511
+			}
512
+		}
513
+
514
+		return $this;
515
+	}
516
+
517
+	/**
518
+	 * Returns the request headers
519
+	 *
520
+	 * The array is of the form ('header name' => 'header value'), header names
521
+	 * are lowercased
522
+	 *
523
+	 * @return   array
524
+	 */
525
+	public function getHeaders()
526
+	{
527
+		return $this->headers;
528
+	}
529
+
530
+	/**
531
+	 * Adds a cookie to the request
532
+	 *
533
+	 * If the request does not have a CookieJar object set, this method simply
534
+	 * appends a cookie to "Cookie:" header.
535
+	 *
536
+	 * If a CookieJar object is available, the cookie is stored in that object.
537
+	 * Data from request URL will be used for setting its 'domain' and 'path'
538
+	 * parameters, 'expires' and 'secure' will be set to null and false,
539
+	 * respectively. If you need further control, use CookieJar's methods.
540
+	 *
541
+	 * @param string $name  cookie name
542
+	 * @param string $value cookie value
543
+	 *
544
+	 * @return   HTTP_Request2
545
+	 * @throws   HTTP_Request2_LogicException
546
+	 * @see      setCookieJar()
547
+	 */
548
+	public function addCookie($name, $value)
549
+	{
550
+		if (!empty($this->cookieJar)) {
551
+			$this->cookieJar->store(
552
+				array('name' => $name, 'value' => $value), $this->url
553
+			);
554
+
555
+		} else {
556
+			$cookie = $name . '=' . $value;
557
+			if (preg_match(self::REGEXP_INVALID_COOKIE, $cookie)) {
558
+				throw new HTTP_Request2_LogicException(
559
+					"Invalid cookie: '{$cookie}'",
560
+					HTTP_Request2_Exception::INVALID_ARGUMENT
561
+				);
562
+			}
563
+			$cookies = empty($this->headers['cookie'])? '': $this->headers['cookie'] . '; ';
564
+			$this->setHeader('cookie', $cookies . $cookie);
565
+		}
566
+
567
+		return $this;
568
+	}
569
+
570
+	/**
571
+	 * Sets the request body
572
+	 *
573
+	 * If you provide file pointer rather than file name, it should support
574
+	 * fstat() and rewind() operations.
575
+	 *
576
+	 * @param string|resource|HTTP_Request2_MultipartBody $body       Either a
577
+	 *               string with the body or filename containing body or
578
+	 *               pointer to an open file or object with multipart body data
579
+	 * @param bool                                        $isFilename Whether
580
+	 *               first parameter is a filename
581
+	 *
582
+	 * @return   HTTP_Request2
583
+	 * @throws   HTTP_Request2_LogicException
584
+	 */
585
+	public function setBody($body, $isFilename = false)
586
+	{
587
+		if (!$isFilename && !is_resource($body)) {
588
+			if (!$body instanceof HTTP_Request2_MultipartBody) {
589
+				$this->body = (string)$body;
590
+			} else {
591
+				$this->body = $body;
592
+			}
593
+		} else {
594
+			$fileData = $this->fopenWrapper($body, empty($this->headers['content-type']));
595
+			$this->body = $fileData['fp'];
596
+			if (empty($this->headers['content-type'])) {
597
+				$this->setHeader('content-type', $fileData['type']);
598
+			}
599
+		}
600
+		$this->postParams = $this->uploads = array();
601
+
602
+		return $this;
603
+	}
604
+
605
+	/**
606
+	 * Returns the request body
607
+	 *
608
+	 * @return   string|resource|HTTP_Request2_MultipartBody
609
+	 */
610
+	public function getBody()
611
+	{
612
+		if (self::METHOD_POST == $this->method
613
+			&& (!empty($this->postParams) || !empty($this->uploads))
614
+		) {
615
+			if (0 === strpos($this->headers['content-type'], 'application/x-www-form-urlencoded')) {
616
+				$body = http_build_query($this->postParams, '', '&');
617
+				if (!$this->getConfig('use_brackets')) {
618
+					$body = preg_replace('/%5B\d+%5D=/', '=', $body);
619
+				}
620
+				// support RFC 3986 by not encoding '~' symbol (request #15368)
621
+				return str_replace('%7E', '~', $body);
622
+
623
+			} elseif (0 === strpos($this->headers['content-type'], 'multipart/form-data')) {
624
+				require_once 'HTTP/Request2/MultipartBody.php';
625
+				return new HTTP_Request2_MultipartBody(
626
+					$this->postParams, $this->uploads, $this->getConfig('use_brackets')
627
+				);
628
+			}
629
+		}
630
+		return $this->body;
631
+	}
632
+
633
+	/**
634
+	 * Adds a file to form-based file upload
635
+	 *
636
+	 * Used to emulate file upload via a HTML form. The method also sets
637
+	 * Content-Type of HTTP request to 'multipart/form-data'.
638
+	 *
639
+	 * If you just want to send the contents of a file as the body of HTTP
640
+	 * request you should use setBody() method.
641
+	 *
642
+	 * If you provide file pointers rather than file names, they should support
643
+	 * fstat() and rewind() operations.
644
+	 *
645
+	 * @param string                $fieldName    name of file-upload field
646
+	 * @param string|resource|array $filename     full name of local file,
647
+	 *               pointer to open file or an array of files
648
+	 * @param string                $sendFilename filename to send in the request
649
+	 * @param string                $contentType  content-type of file being uploaded
650
+	 *
651
+	 * @return   HTTP_Request2
652
+	 * @throws   HTTP_Request2_LogicException
653
+	 */
654
+	public function addUpload(
655
+		$fieldName, $filename, $sendFilename = null, $contentType = null
656
+	) {
657
+		if (!is_array($filename)) {
658
+			$fileData = $this->fopenWrapper($filename, empty($contentType));
659
+			$this->uploads[$fieldName] = array(
660
+				'fp'        => $fileData['fp'],
661
+				'filename'  => !empty($sendFilename)? $sendFilename
662
+								:(is_string($filename)? basename($filename): 'anonymous.blob') ,
663
+				'size'      => $fileData['size'],
664
+				'type'      => empty($contentType)? $fileData['type']: $contentType
665
+			);
666
+		} else {
667
+			$fps = $names = $sizes = $types = array();
668
+			foreach ($filename as $f) {
669
+				if (!is_array($f)) {
670
+					$f = array($f);
671
+				}
672
+				$fileData = $this->fopenWrapper($f[0], empty($f[2]));
673
+				$fps[]   = $fileData['fp'];
674
+				$names[] = !empty($f[1])? $f[1]
675
+							:(is_string($f[0])? basename($f[0]): 'anonymous.blob');
676
+				$sizes[] = $fileData['size'];
677
+				$types[] = empty($f[2])? $fileData['type']: $f[2];
678
+			}
679
+			$this->uploads[$fieldName] = array(
680
+				'fp' => $fps, 'filename' => $names, 'size' => $sizes, 'type' => $types
681
+			);
682
+		}
683
+		if (empty($this->headers['content-type'])
684
+			|| 'application/x-www-form-urlencoded' == $this->headers['content-type']
685
+		) {
686
+			$this->setHeader('content-type', 'multipart/form-data');
687
+		}
688
+
689
+		return $this;
690
+	}
691
+
692
+	/**
693
+	 * Adds POST parameter(s) to the request.
694
+	 *
695
+	 * @param string|array $name  parameter name or array ('name' => 'value')
696
+	 * @param mixed        $value parameter value (can be an array)
697
+	 *
698
+	 * @return   HTTP_Request2
699
+	 */
700
+	public function addPostParameter($name, $value = null)
701
+	{
702
+		if (!is_array($name)) {
703
+			$this->postParams[$name] = $value;
704
+		} else {
705
+			foreach ($name as $k => $v) {
706
+				$this->addPostParameter($k, $v);
707
+			}
708
+		}
709
+		if (empty($this->headers['content-type'])) {
710
+			$this->setHeader('content-type', 'application/x-www-form-urlencoded');
711
+		}
712
+
713
+		return $this;
714
+	}
715
+
716
+	/**
717
+	 * Attaches a new observer
718
+	 *
719
+	 * @param SplObserver $observer any object implementing SplObserver
720
+	 */
721
+	public function attach(SplObserver $observer)
722
+	{
723
+		foreach ($this->observers as $attached) {
724
+			if ($attached === $observer) {
725
+				return;
726
+			}
727
+		}
728
+		$this->observers[] = $observer;
729
+	}
730
+
731
+	/**
732
+	 * Detaches an existing observer
733
+	 *
734
+	 * @param SplObserver $observer any object implementing SplObserver
735
+	 */
736
+	public function detach(SplObserver $observer)
737
+	{
738
+		foreach ($this->observers as $key => $attached) {
739
+			if ($attached === $observer) {
740
+				unset($this->observers[$key]);
741
+				return;
742
+			}
743
+		}
744
+	}
745
+
746
+	/**
747
+	 * Notifies all observers
748
+	 */
749
+	public function notify()
750
+	{
751
+		foreach ($this->observers as $observer) {
752
+			$observer->update($this);
753
+		}
754
+	}
755
+
756
+	/**
757
+	 * Sets the last event
758
+	 *
759
+	 * Adapters should use this method to set the current state of the request
760
+	 * and notify the observers.
761
+	 *
762
+	 * @param string $name event name
763
+	 * @param mixed  $data event data
764
+	 */
765
+	public function setLastEvent($name, $data = null)
766
+	{
767
+		$this->lastEvent = array(
768
+			'name' => $name,
769
+			'data' => $data
770
+		);
771
+		$this->notify();
772
+	}
773
+
774
+	/**
775
+	 * Returns the last event
776
+	 *
777
+	 * Observers should use this method to access the last change in request.
778
+	 * The following event names are possible:
779
+	 * <ul>
780
+	 *   <li>'connect'                 - after connection to remote server,
781
+	 *                                   data is the destination (string)</li>
782
+	 *   <li>'disconnect'              - after disconnection from server</li>
783
+	 *   <li>'sentHeaders'             - after sending the request headers,
784
+	 *                                   data is the headers sent (string)</li>
785
+	 *   <li>'sentBodyPart'            - after sending a part of the request body,
786
+	 *                                   data is the length of that part (int)</li>
787
+	 *   <li>'sentBody'                - after sending the whole request body,
788
+	 *                                   data is request body length (int)</li>
789
+	 *   <li>'receivedHeaders'         - after receiving the response headers,
790
+	 *                                   data is HTTP_Request2_Response object</li>
791
+	 *   <li>'receivedBodyPart'        - after receiving a part of the response
792
+	 *                                   body, data is that part (string)</li>
793
+	 *   <li>'receivedEncodedBodyPart' - as 'receivedBodyPart', but data is still
794
+	 *                                   encoded by Content-Encoding</li>
795
+	 *   <li>'receivedBody'            - after receiving the complete response
796
+	 *                                   body, data is HTTP_Request2_Response object</li>
797
+	 * </ul>
798
+	 * Different adapters may not send all the event types. Mock adapter does
799
+	 * not send any events to the observers.
800
+	 *
801
+	 * @return   array   The array has two keys: 'name' and 'data'
802
+	 */
803
+	public function getLastEvent()
804
+	{
805
+		return $this->lastEvent;
806
+	}
807
+
808
+	/**
809
+	 * Sets the adapter used to actually perform the request
810
+	 *
811
+	 * You can pass either an instance of a class implementing HTTP_Request2_Adapter
812
+	 * or a class name. The method will only try to include a file if the class
813
+	 * name starts with HTTP_Request2_Adapter_, it will also try to prepend this
814
+	 * prefix to the class name if it doesn't contain any underscores, so that
815
+	 * <code>
816
+	 * $request->setAdapter('curl');
817
+	 * </code>
818
+	 * will work.
819
+	 *
820
+	 * @param string|HTTP_Request2_Adapter $adapter Adapter to use
821
+	 *
822
+	 * @return   HTTP_Request2
823
+	 * @throws   HTTP_Request2_LogicException
824
+	 */
825
+	public function setAdapter($adapter)
826
+	{
827
+		if (is_string($adapter)) {
828
+			if (!class_exists($adapter, false)) {
829
+				if (false === strpos($adapter, '_')) {
830
+					$adapter = 'HTTP_Request2_Adapter_' . ucfirst($adapter);
831
+				}
832
+				if (!class_exists($adapter, false)
833
+					&& preg_match('/^HTTP_Request2_Adapter_([a-zA-Z0-9]+)$/', $adapter)
834
+				) {
835
+					include_once str_replace('_', DIRECTORY_SEPARATOR, $adapter) . '.php';
836
+				}
837
+				if (!class_exists($adapter, false)) {
838
+					throw new HTTP_Request2_LogicException(
839
+						"Class {$adapter} not found",
840
+						HTTP_Request2_Exception::MISSING_VALUE
841
+					);
842
+				}
843
+			}
844
+			$adapter = new $adapter;
845
+		}
846
+		if (!$adapter instanceof HTTP_Request2_Adapter) {
847
+			throw new HTTP_Request2_LogicException(
848
+				'Parameter is not a HTTP request adapter',
849
+				HTTP_Request2_Exception::INVALID_ARGUMENT
850
+			);
851
+		}
852
+		$this->adapter = $adapter;
853
+
854
+		return $this;
855
+	}
856
+
857
+	/**
858
+	 * Sets the cookie jar
859
+	 *
860
+	 * A cookie jar is used to maintain cookies across HTTP requests and
861
+	 * responses. Cookies from jar will be automatically added to the request
862
+	 * headers based on request URL.
863
+	 *
864
+	 * @param HTTP_Request2_CookieJar|bool $jar Existing CookieJar object, true to
865
+	 *                                          create a new one, false to remove
866
+	 *
867
+	 * @return HTTP_Request2
868
+	 * @throws HTTP_Request2_LogicException
869
+	 */
870
+	public function setCookieJar($jar = true)
871
+	{
872
+		if (!class_exists('HTTP_Request2_CookieJar', false)) {
873
+			require_once 'HTTP/Request2/CookieJar.php';
874
+		}
875
+
876
+		if ($jar instanceof HTTP_Request2_CookieJar) {
877
+			$this->cookieJar = $jar;
878
+		} elseif (true === $jar) {
879
+			$this->cookieJar = new HTTP_Request2_CookieJar();
880
+		} elseif (!$jar) {
881
+			$this->cookieJar = null;
882
+		} else {
883
+			throw new HTTP_Request2_LogicException(
884
+				'Invalid parameter passed to setCookieJar()',
885
+				HTTP_Request2_Exception::INVALID_ARGUMENT
886
+			);
887
+		}
888
+
889
+		return $this;
890
+	}
891
+
892
+	/**
893
+	 * Returns current CookieJar object or null if none
894
+	 *
895
+	 * @return HTTP_Request2_CookieJar|null
896
+	 */
897
+	public function getCookieJar()
898
+	{
899
+		return $this->cookieJar;
900
+	}
901
+
902
+	/**
903
+	 * Sends the request and returns the response
904
+	 *
905
+	 * @throws   HTTP_Request2_Exception
906
+	 * @return   HTTP_Request2_Response
907
+	 */
908
+	public function send()
909
+	{
910
+		// Sanity check for URL
911
+		if (!$this->url instanceof Net_URL2
912
+			|| !$this->url->isAbsolute()
913
+			|| !in_array(strtolower($this->url->getScheme()), array('https', 'http'))
914
+		) {
915
+			throw new HTTP_Request2_LogicException(
916
+				'HTTP_Request2 needs an absolute HTTP(S) request URL, '
917
+				. ($this->url instanceof Net_URL2
918
+				   ? "'" . $this->url->__toString() . "'" : 'none')
919
+				. ' given',
920
+				HTTP_Request2_Exception::INVALID_ARGUMENT
921
+			);
922
+		}
923
+		if (empty($this->adapter)) {
924
+			$this->setAdapter($this->getConfig('adapter'));
925
+		}
926
+		// magic_quotes_runtime may break file uploads and chunked response
927
+		// processing; see bug #4543. Don't use ini_get() here; see bug #16440.
928
+		if ($magicQuotes = get_magic_quotes_runtime()) {
929
+			set_magic_quotes_runtime(false);
930
+		}
931
+		// force using single byte encoding if mbstring extension overloads
932
+		// strlen() and substr(); see bug #1781, bug #10605
933
+		if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
934
+			$oldEncoding = mb_internal_encoding();
935
+			mb_internal_encoding('8bit');
936
+		}
937
+
938
+		try {
939
+			$response = $this->adapter->sendRequest($this);
940
+		} catch (Exception $e) {
941
+		}
942
+		// cleanup in either case (poor man's "finally" clause)
943
+		if ($magicQuotes) {
944
+			set_magic_quotes_runtime(true);
945
+		}
946
+		if (!empty($oldEncoding)) {
947
+			mb_internal_encoding($oldEncoding);
948
+		}
949
+		// rethrow the exception
950
+		if (!empty($e)) {
951
+			throw $e;
952
+		}
953
+		return $response;
954
+	}
955
+
956
+	/**
957
+	 * Wrapper around fopen()/fstat() used by setBody() and addUpload()
958
+	 *
959
+	 * @param string|resource $file       file name or pointer to open file
960
+	 * @param bool            $detectType whether to try autodetecting MIME
961
+	 *                        type of file, will only work if $file is a
962
+	 *                        filename, not pointer
963
+	 *
964
+	 * @return array array('fp' => file pointer, 'size' => file size, 'type' => MIME type)
965
+	 * @throws HTTP_Request2_LogicException
966
+	 */
967
+	protected function fopenWrapper($file, $detectType = false)
968
+	{
969
+		if (!is_string($file) && !is_resource($file)) {
970
+			throw new HTTP_Request2_LogicException(
971
+				"Filename or file pointer resource expected",
972
+				HTTP_Request2_Exception::INVALID_ARGUMENT
973
+			);
974
+		}
975
+		$fileData = array(
976
+			'fp'   => is_string($file)? null: $file,
977
+			'type' => 'application/octet-stream',
978
+			'size' => 0
979
+		);
980
+		if (is_string($file)) {
981
+			if (!($fileData['fp'] = @fopen($file, 'rb'))) {
982
+				$error = error_get_last();
983
+				throw new HTTP_Request2_LogicException(
984
+					$error['message'], HTTP_Request2_Exception::READ_ERROR
985
+				);
986
+			}
987
+			if ($detectType) {
988
+				$fileData['type'] = self::detectMimeType($file);
989
+			}
990
+		}
991
+		if (!($stat = fstat($fileData['fp']))) {
992
+			throw new HTTP_Request2_LogicException(
993
+				"fstat() call failed", HTTP_Request2_Exception::READ_ERROR
994
+			);
995
+		}
996
+		$fileData['size'] = $stat['size'];
997
+
998
+		return $fileData;
999
+	}
1000
+
1001
+	/**
1002
+	 * Tries to detect MIME type of a file
1003
+	 *
1004
+	 * The method will try to use fileinfo extension if it is available,
1005
+	 * deprecated mime_content_type() function in the other case. If neither
1006
+	 * works, default 'application/octet-stream' MIME type is returned
1007
+	 *
1008
+	 * @param string $filename file name
1009
+	 *
1010
+	 * @return   string  file MIME type
1011
+	 */
1012
+	protected static function detectMimeType($filename)
1013
+	{
1014
+		// finfo extension from PECL available
1015
+		if (function_exists('finfo_open')) {
1016
+			if (!isset(self::$_fileinfoDb)) {
1017
+				self::$_fileinfoDb = @finfo_open(FILEINFO_MIME);
1018
+			}
1019
+			if (self::$_fileinfoDb) {
1020
+				$info = finfo_file(self::$_fileinfoDb, $filename);
1021
+			}
1022
+		}
1023
+		// (deprecated) mime_content_type function available
1024
+		if (empty($info) && function_exists('mime_content_type')) {
1025
+			return mime_content_type($filename);
1026
+		}
1027
+		return empty($info)? 'application/octet-stream': $info;
1028
+	}
1029 1029
 }
1030 1030
 ?>
Please login to merge, or discard this patch.
Spacing   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -213,8 +213,8 @@  discard block
 block discarded – undo
213 213
             $this->setMethod($method);
214 214
         }
215 215
         $this->setHeader(
216
-            'user-agent', 'HTTP_Request2/2.2.1 ' .
217
-            '(http://pear.php.net/package/http_request2) PHP/' . phpversion()
216
+            'user-agent', 'HTTP_Request2/2.2.1 '.
217
+            '(http://pear.php.net/package/http_request2) PHP/'.phpversion()
218 218
         );
219 219
     }
220 220
 
@@ -247,7 +247,7 @@  discard block
 block discarded – undo
247 247
         if ($url->getUserinfo()) {
248 248
             $username = $url->getUser();
249 249
             $password = $url->getPassword();
250
-            $this->setAuth(rawurldecode($username), $password? rawurldecode($password): '');
250
+            $this->setAuth(rawurldecode($username), $password ? rawurldecode($password) : '');
251 251
             $url->setUserinfo('');
252 252
         }
253 253
         if ('' == $url->getPath()) {
@@ -421,8 +421,8 @@  discard block
 block discarded – undo
421 421
             $this->auth = null;
422 422
         } else {
423 423
             $this->auth = array(
424
-                'user'     => (string)$user,
425
-                'password' => (string)$password,
424
+                'user'     => (string) $user,
425
+                'password' => (string) $password,
426 426
                 'scheme'   => $scheme
427 427
             );
428 428
         }
@@ -506,7 +506,7 @@  discard block
 block discarded – undo
506 506
                 if (!isset($this->headers[$name]) || $replace) {
507 507
                     $this->headers[$name] = $value;
508 508
                 } else {
509
-                    $this->headers[$name] .= ', ' . $value;
509
+                    $this->headers[$name] .= ', '.$value;
510 510
                 }
511 511
             }
512 512
         }
@@ -553,15 +553,15 @@  discard block
 block discarded – undo
553 553
             );
554 554
 
555 555
         } else {
556
-            $cookie = $name . '=' . $value;
556
+            $cookie = $name.'='.$value;
557 557
             if (preg_match(self::REGEXP_INVALID_COOKIE, $cookie)) {
558 558
                 throw new HTTP_Request2_LogicException(
559 559
                     "Invalid cookie: '{$cookie}'",
560 560
                     HTTP_Request2_Exception::INVALID_ARGUMENT
561 561
                 );
562 562
             }
563
-            $cookies = empty($this->headers['cookie'])? '': $this->headers['cookie'] . '; ';
564
-            $this->setHeader('cookie', $cookies . $cookie);
563
+            $cookies = empty($this->headers['cookie']) ? '' : $this->headers['cookie'].'; ';
564
+            $this->setHeader('cookie', $cookies.$cookie);
565 565
         }
566 566
 
567 567
         return $this;
@@ -586,7 +586,7 @@  discard block
 block discarded – undo
586 586
     {
587 587
         if (!$isFilename && !is_resource($body)) {
588 588
             if (!$body instanceof HTTP_Request2_MultipartBody) {
589
-                $this->body = (string)$body;
589
+                $this->body = (string) $body;
590 590
             } else {
591 591
                 $this->body = $body;
592 592
             }
@@ -658,10 +658,10 @@  discard block
 block discarded – undo
658 658
             $fileData = $this->fopenWrapper($filename, empty($contentType));
659 659
             $this->uploads[$fieldName] = array(
660 660
                 'fp'        => $fileData['fp'],
661
-                'filename'  => !empty($sendFilename)? $sendFilename
662
-                                :(is_string($filename)? basename($filename): 'anonymous.blob') ,
661
+                'filename'  => !empty($sendFilename) ? $sendFilename
662
+                                :(is_string($filename) ? basename($filename) : 'anonymous.blob'),
663 663
                 'size'      => $fileData['size'],
664
-                'type'      => empty($contentType)? $fileData['type']: $contentType
664
+                'type'      => empty($contentType) ? $fileData['type'] : $contentType
665 665
             );
666 666
         } else {
667 667
             $fps = $names = $sizes = $types = array();
@@ -671,10 +671,10 @@  discard block
 block discarded – undo
671 671
                 }
672 672
                 $fileData = $this->fopenWrapper($f[0], empty($f[2]));
673 673
                 $fps[]   = $fileData['fp'];
674
-                $names[] = !empty($f[1])? $f[1]
675
-                            :(is_string($f[0])? basename($f[0]): 'anonymous.blob');
674
+                $names[] = !empty($f[1]) ? $f[1]
675
+                            :(is_string($f[0]) ? basename($f[0]) : 'anonymous.blob');
676 676
                 $sizes[] = $fileData['size'];
677
-                $types[] = empty($f[2])? $fileData['type']: $f[2];
677
+                $types[] = empty($f[2]) ? $fileData['type'] : $f[2];
678 678
             }
679 679
             $this->uploads[$fieldName] = array(
680 680
                 'fp' => $fps, 'filename' => $names, 'size' => $sizes, 'type' => $types
@@ -827,12 +827,12 @@  discard block
 block discarded – undo
827 827
         if (is_string($adapter)) {
828 828
             if (!class_exists($adapter, false)) {
829 829
                 if (false === strpos($adapter, '_')) {
830
-                    $adapter = 'HTTP_Request2_Adapter_' . ucfirst($adapter);
830
+                    $adapter = 'HTTP_Request2_Adapter_'.ucfirst($adapter);
831 831
                 }
832 832
                 if (!class_exists($adapter, false)
833 833
                     && preg_match('/^HTTP_Request2_Adapter_([a-zA-Z0-9]+)$/', $adapter)
834 834
                 ) {
835
-                    include_once str_replace('_', DIRECTORY_SEPARATOR, $adapter) . '.php';
835
+                    include_once str_replace('_', DIRECTORY_SEPARATOR, $adapter).'.php';
836 836
                 }
837 837
                 if (!class_exists($adapter, false)) {
838 838
                     throw new HTTP_Request2_LogicException(
@@ -915,7 +915,7 @@  discard block
 block discarded – undo
915 915
             throw new HTTP_Request2_LogicException(
916 916
                 'HTTP_Request2 needs an absolute HTTP(S) request URL, '
917 917
                 . ($this->url instanceof Net_URL2
918
-                   ? "'" . $this->url->__toString() . "'" : 'none')
918
+                   ? "'".$this->url->__toString()."'" : 'none')
919 919
                 . ' given',
920 920
                 HTTP_Request2_Exception::INVALID_ARGUMENT
921 921
             );
@@ -973,7 +973,7 @@  discard block
 block discarded – undo
973 973
             );
974 974
         }
975 975
         $fileData = array(
976
-            'fp'   => is_string($file)? null: $file,
976
+            'fp'   => is_string($file) ? null : $file,
977 977
             'type' => 'application/octet-stream',
978 978
             'size' => 0
979 979
         );
@@ -1024,7 +1024,7 @@  discard block
 block discarded – undo
1024 1024
         if (empty($info) && function_exists('mime_content_type')) {
1025 1025
             return mime_content_type($filename);
1026 1026
         }
1027
-        return empty($info)? 'application/octet-stream': $info;
1027
+        return empty($info) ? 'application/octet-stream' : $info;
1028 1028
     }
1029 1029
 }
1030 1030
 ?>
Please login to merge, or discard this patch.
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -261,7 +261,7 @@  discard block
 block discarded – undo
261 261
     /**
262 262
      * Returns the request URL
263 263
      *
264
-     * @return   Net_URL2
264
+     * @return   string
265 265
      */
266 266
     public function getUrl()
267 267
     {
@@ -573,7 +573,7 @@  discard block
 block discarded – undo
573 573
      * If you provide file pointer rather than file name, it should support
574 574
      * fstat() and rewind() operations.
575 575
      *
576
-     * @param string|resource|HTTP_Request2_MultipartBody $body       Either a
576
+     * @param string $body       Either a
577 577
      *               string with the body or filename containing body or
578 578
      *               pointer to an open file or object with multipart body data
579 579
      * @param bool                                        $isFilename Whether
Please login to merge, or discard this patch.
libs/PEAR.1.9.5/HTTP/Request2/Adapter/Curl.php 3 patches
Switch Indentation   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -268,29 +268,29 @@  discard block
 block discarded – undo
268 268
 
269 269
         // set HTTP version
270 270
         switch ($this->request->getConfig('protocol_version')) {
271
-        case '1.0':
272
-            curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
273
-            break;
274
-        case '1.1':
275
-            curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
271
+        	case '1.0':
272
+            	curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
273
+            	break;
274
+        	case '1.1':
275
+            	curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
276 276
         }
277 277
 
278 278
         // set request method
279 279
         switch ($this->request->getMethod()) {
280
-        case HTTP_Request2::METHOD_GET:
281
-            curl_setopt($ch, CURLOPT_HTTPGET, true);
282
-            break;
283
-        case HTTP_Request2::METHOD_POST:
284
-            curl_setopt($ch, CURLOPT_POST, true);
285
-            break;
286
-        case HTTP_Request2::METHOD_HEAD:
287
-            curl_setopt($ch, CURLOPT_NOBODY, true);
288
-            break;
289
-        case HTTP_Request2::METHOD_PUT:
290
-            curl_setopt($ch, CURLOPT_UPLOAD, true);
291
-            break;
292
-        default:
293
-            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());
280
+        	case HTTP_Request2::METHOD_GET:
281
+            	curl_setopt($ch, CURLOPT_HTTPGET, true);
282
+            	break;
283
+        	case HTTP_Request2::METHOD_POST:
284
+            	curl_setopt($ch, CURLOPT_POST, true);
285
+            	break;
286
+        	case HTTP_Request2::METHOD_HEAD:
287
+            	curl_setopt($ch, CURLOPT_NOBODY, true);
288
+            	break;
289
+        	case HTTP_Request2::METHOD_PUT:
290
+            	curl_setopt($ch, CURLOPT_UPLOAD, true);
291
+            	break;
292
+        	default:
293
+            	curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());
294 294
         }
295 295
 
296 296
         // set proxy, if needed
@@ -307,25 +307,25 @@  discard block
 block discarded – undo
307 307
                     $user . ':' . $this->request->getConfig('proxy_password')
308 308
                 );
309 309
                 switch ($this->request->getConfig('proxy_auth_scheme')) {
310
-                case HTTP_Request2::AUTH_BASIC:
311
-                    curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
312
-                    break;
313
-                case HTTP_Request2::AUTH_DIGEST:
314
-                    curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
310
+                	case HTTP_Request2::AUTH_BASIC:
311
+                    	curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
312
+                    	break;
313
+                	case HTTP_Request2::AUTH_DIGEST:
314
+                    	curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
315 315
                 }
316 316
             }
317 317
             if ($type = $this->request->getConfig('proxy_type')) {
318 318
                 switch ($type) {
319
-                case 'http':
320
-                    curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
321
-                    break;
322
-                case 'socks5':
323
-                    curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
324
-                    break;
325
-                default:
326
-                    throw new HTTP_Request2_NotImplementedException(
327
-                        "Proxy type '{$type}' is not supported"
328
-                    );
319
+                	case 'http':
320
+                    	curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
321
+                    	break;
322
+                	case 'socks5':
323
+                    	curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
324
+                    	break;
325
+                	default:
326
+                    	throw new HTTP_Request2_NotImplementedException(
327
+                        	"Proxy type '{$type}' is not supported"
328
+                    	);
329 329
                 }
330 330
             }
331 331
         }
@@ -334,11 +334,11 @@  discard block
 block discarded – undo
334 334
         if ($auth = $this->request->getAuth()) {
335 335
             curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']);
336 336
             switch ($auth['scheme']) {
337
-            case HTTP_Request2::AUTH_BASIC:
338
-                curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
339
-                break;
340
-            case HTTP_Request2::AUTH_DIGEST:
341
-                curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
337
+            	case HTTP_Request2::AUTH_BASIC:
338
+                	curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
339
+                	break;
340
+            	case HTTP_Request2::AUTH_DIGEST:
341
+                	curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
342 342
             }
343 343
         }
344 344
 
Please login to merge, or discard this patch.
Indentation   +528 added lines, -528 removed lines patch added patch discarded remove patch
@@ -35,533 +35,533 @@
 block discarded – undo
35 35
  */
36 36
 class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
37 37
 {
38
-    /**
39
-     * Mapping of header names to cURL options
40
-     * @var  array
41
-     */
42
-    protected static $headerMap = array(
43
-        'accept-encoding' => CURLOPT_ENCODING,
44
-        'cookie'          => CURLOPT_COOKIE,
45
-        'referer'         => CURLOPT_REFERER,
46
-        'user-agent'      => CURLOPT_USERAGENT
47
-    );
48
-
49
-    /**
50
-     * Mapping of SSL context options to cURL options
51
-     * @var  array
52
-     */
53
-    protected static $sslContextMap = array(
54
-        'ssl_verify_peer' => CURLOPT_SSL_VERIFYPEER,
55
-        'ssl_cafile'      => CURLOPT_CAINFO,
56
-        'ssl_capath'      => CURLOPT_CAPATH,
57
-        'ssl_local_cert'  => CURLOPT_SSLCERT,
58
-        'ssl_passphrase'  => CURLOPT_SSLCERTPASSWD
59
-    );
60
-
61
-    /**
62
-     * Mapping of CURLE_* constants to Exception subclasses and error codes
63
-     * @var  array
64
-     */
65
-    protected static $errorMap = array(
66
-        CURLE_UNSUPPORTED_PROTOCOL  => array('HTTP_Request2_MessageException',
67
-                                             HTTP_Request2_Exception::NON_HTTP_REDIRECT),
68
-        CURLE_COULDNT_RESOLVE_PROXY => array('HTTP_Request2_ConnectionException'),
69
-        CURLE_COULDNT_RESOLVE_HOST  => array('HTTP_Request2_ConnectionException'),
70
-        CURLE_COULDNT_CONNECT       => array('HTTP_Request2_ConnectionException'),
71
-        // error returned from write callback
72
-        CURLE_WRITE_ERROR           => array('HTTP_Request2_MessageException',
73
-                                             HTTP_Request2_Exception::NON_HTTP_REDIRECT),
74
-        CURLE_OPERATION_TIMEOUTED   => array('HTTP_Request2_MessageException',
75
-                                             HTTP_Request2_Exception::TIMEOUT),
76
-        CURLE_HTTP_RANGE_ERROR      => array('HTTP_Request2_MessageException'),
77
-        CURLE_SSL_CONNECT_ERROR     => array('HTTP_Request2_ConnectionException'),
78
-        CURLE_LIBRARY_NOT_FOUND     => array('HTTP_Request2_LogicException',
79
-                                             HTTP_Request2_Exception::MISCONFIGURATION),
80
-        CURLE_FUNCTION_NOT_FOUND    => array('HTTP_Request2_LogicException',
81
-                                             HTTP_Request2_Exception::MISCONFIGURATION),
82
-        CURLE_ABORTED_BY_CALLBACK   => array('HTTP_Request2_MessageException',
83
-                                             HTTP_Request2_Exception::NON_HTTP_REDIRECT),
84
-        CURLE_TOO_MANY_REDIRECTS    => array('HTTP_Request2_MessageException',
85
-                                             HTTP_Request2_Exception::TOO_MANY_REDIRECTS),
86
-        CURLE_SSL_PEER_CERTIFICATE  => array('HTTP_Request2_ConnectionException'),
87
-        CURLE_GOT_NOTHING           => array('HTTP_Request2_MessageException'),
88
-        CURLE_SSL_ENGINE_NOTFOUND   => array('HTTP_Request2_LogicException',
89
-                                             HTTP_Request2_Exception::MISCONFIGURATION),
90
-        CURLE_SSL_ENGINE_SETFAILED  => array('HTTP_Request2_LogicException',
91
-                                             HTTP_Request2_Exception::MISCONFIGURATION),
92
-        CURLE_SEND_ERROR            => array('HTTP_Request2_MessageException'),
93
-        CURLE_RECV_ERROR            => array('HTTP_Request2_MessageException'),
94
-        CURLE_SSL_CERTPROBLEM       => array('HTTP_Request2_LogicException',
95
-                                             HTTP_Request2_Exception::INVALID_ARGUMENT),
96
-        CURLE_SSL_CIPHER            => array('HTTP_Request2_ConnectionException'),
97
-        CURLE_SSL_CACERT            => array('HTTP_Request2_ConnectionException'),
98
-        CURLE_BAD_CONTENT_ENCODING  => array('HTTP_Request2_MessageException'),
99
-    );
100
-
101
-    /**
102
-     * Response being received
103
-     * @var  HTTP_Request2_Response
104
-     */
105
-    protected $response;
106
-
107
-    /**
108
-     * Whether 'sentHeaders' event was sent to observers
109
-     * @var  boolean
110
-     */
111
-    protected $eventSentHeaders = false;
112
-
113
-    /**
114
-     * Whether 'receivedHeaders' event was sent to observers
115
-     * @var boolean
116
-     */
117
-    protected $eventReceivedHeaders = false;
118
-
119
-    /**
120
-     * Position within request body
121
-     * @var  integer
122
-     * @see  callbackReadBody()
123
-     */
124
-    protected $position = 0;
125
-
126
-    /**
127
-     * Information about last transfer, as returned by curl_getinfo()
128
-     * @var  array
129
-     */
130
-    protected $lastInfo;
131
-
132
-    /**
133
-     * Creates a subclass of HTTP_Request2_Exception from curl error data
134
-     *
135
-     * @param resource $ch curl handle
136
-     *
137
-     * @return HTTP_Request2_Exception
138
-     */
139
-    protected static function wrapCurlError($ch)
140
-    {
141
-        $nativeCode = curl_errno($ch);
142
-        $message    = 'Curl error: ' . curl_error($ch);
143
-        if (!isset(self::$errorMap[$nativeCode])) {
144
-            return new HTTP_Request2_Exception($message, 0, $nativeCode);
145
-        } else {
146
-            $class = self::$errorMap[$nativeCode][0];
147
-            $code  = empty(self::$errorMap[$nativeCode][1])
148
-                     ? 0 : self::$errorMap[$nativeCode][1];
149
-            return new $class($message, $code, $nativeCode);
150
-        }
151
-    }
152
-
153
-    /**
154
-     * Sends request to the remote server and returns its response
155
-     *
156
-     * @param HTTP_Request2 $request HTTP request message
157
-     *
158
-     * @return   HTTP_Request2_Response
159
-     * @throws   HTTP_Request2_Exception
160
-     */
161
-    public function sendRequest(HTTP_Request2 $request)
162
-    {
163
-        if (!extension_loaded('curl')) {
164
-            throw new HTTP_Request2_LogicException(
165
-                'cURL extension not available', HTTP_Request2_Exception::MISCONFIGURATION
166
-            );
167
-        }
168
-
169
-        $this->request              = $request;
170
-        $this->response             = null;
171
-        $this->position             = 0;
172
-        $this->eventSentHeaders     = false;
173
-        $this->eventReceivedHeaders = false;
174
-
175
-        try {
176
-            if (false === curl_exec($ch = $this->createCurlHandle())) {
177
-                $e = self::wrapCurlError($ch);
178
-            }
179
-        } catch (Exception $e) {
180
-        }
181
-        if (isset($ch)) {
182
-            $this->lastInfo = curl_getinfo($ch);
183
-            curl_close($ch);
184
-        }
185
-
186
-        $response = $this->response;
187
-        unset($this->request, $this->requestBody, $this->response);
188
-
189
-        if (!empty($e)) {
190
-            throw $e;
191
-        }
192
-
193
-        if ($jar = $request->getCookieJar()) {
194
-            $jar->addCookiesFromResponse($response, $request->getUrl());
195
-        }
196
-
197
-        if (0 < $this->lastInfo['size_download']) {
198
-            $request->setLastEvent('receivedBody', $response);
199
-        }
200
-        return $response;
201
-    }
202
-
203
-    /**
204
-     * Returns information about last transfer
205
-     *
206
-     * @return   array   associative array as returned by curl_getinfo()
207
-     */
208
-    public function getInfo()
209
-    {
210
-        return $this->lastInfo;
211
-    }
212
-
213
-    /**
214
-     * Creates a new cURL handle and populates it with data from the request
215
-     *
216
-     * @return   resource    a cURL handle, as created by curl_init()
217
-     * @throws   HTTP_Request2_LogicException
218
-     * @throws   HTTP_Request2_NotImplementedException
219
-     */
220
-    protected function createCurlHandle()
221
-    {
222
-        $ch = curl_init();
223
-
224
-        curl_setopt_array($ch, array(
225
-            // setup write callbacks
226
-            CURLOPT_HEADERFUNCTION => array($this, 'callbackWriteHeader'),
227
-            CURLOPT_WRITEFUNCTION  => array($this, 'callbackWriteBody'),
228
-            // buffer size
229
-            CURLOPT_BUFFERSIZE     => $this->request->getConfig('buffer_size'),
230
-            // connection timeout
231
-            CURLOPT_CONNECTTIMEOUT => $this->request->getConfig('connect_timeout'),
232
-            // save full outgoing headers, in case someone is interested
233
-            CURLINFO_HEADER_OUT    => true,
234
-            // request url
235
-            CURLOPT_URL            => $this->request->getUrl()->getUrl()
236
-        ));
237
-
238
-        // set up redirects
239
-        if (!$this->request->getConfig('follow_redirects')) {
240
-            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
241
-        } else {
242
-            if (!@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true)) {
243
-                throw new HTTP_Request2_LogicException(
244
-                    'Redirect support in curl is unavailable due to open_basedir or safe_mode setting',
245
-                    HTTP_Request2_Exception::MISCONFIGURATION
246
-                );
247
-            }
248
-            curl_setopt($ch, CURLOPT_MAXREDIRS, $this->request->getConfig('max_redirects'));
249
-            // limit redirects to http(s), works in 5.2.10+
250
-            if (defined('CURLOPT_REDIR_PROTOCOLS')) {
251
-                curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
252
-            }
253
-            // works in 5.3.2+, http://bugs.php.net/bug.php?id=49571
254
-            if ($this->request->getConfig('strict_redirects') && defined('CURLOPT_POSTREDIR')) {
255
-                curl_setopt($ch, CURLOPT_POSTREDIR, 3);
256
-            }
257
-        }
258
-
259
-        // set local IP via CURLOPT_INTERFACE (request #19515)
260
-        if ($ip = $this->request->getConfig('local_ip')) {
261
-            curl_setopt($ch, CURLOPT_INTERFACE, $ip);
262
-        }
263
-
264
-        // request timeout
265
-        if ($timeout = $this->request->getConfig('timeout')) {
266
-            curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
267
-        }
268
-
269
-        // set HTTP version
270
-        switch ($this->request->getConfig('protocol_version')) {
271
-        case '1.0':
272
-            curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
273
-            break;
274
-        case '1.1':
275
-            curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
276
-        }
277
-
278
-        // set request method
279
-        switch ($this->request->getMethod()) {
280
-        case HTTP_Request2::METHOD_GET:
281
-            curl_setopt($ch, CURLOPT_HTTPGET, true);
282
-            break;
283
-        case HTTP_Request2::METHOD_POST:
284
-            curl_setopt($ch, CURLOPT_POST, true);
285
-            break;
286
-        case HTTP_Request2::METHOD_HEAD:
287
-            curl_setopt($ch, CURLOPT_NOBODY, true);
288
-            break;
289
-        case HTTP_Request2::METHOD_PUT:
290
-            curl_setopt($ch, CURLOPT_UPLOAD, true);
291
-            break;
292
-        default:
293
-            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());
294
-        }
295
-
296
-        // set proxy, if needed
297
-        if ($host = $this->request->getConfig('proxy_host')) {
298
-            if (!($port = $this->request->getConfig('proxy_port'))) {
299
-                throw new HTTP_Request2_LogicException(
300
-                    'Proxy port not provided', HTTP_Request2_Exception::MISSING_VALUE
301
-                );
302
-            }
303
-            curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port);
304
-            if ($user = $this->request->getConfig('proxy_user')) {
305
-                curl_setopt(
306
-                    $ch, CURLOPT_PROXYUSERPWD,
307
-                    $user . ':' . $this->request->getConfig('proxy_password')
308
-                );
309
-                switch ($this->request->getConfig('proxy_auth_scheme')) {
310
-                case HTTP_Request2::AUTH_BASIC:
311
-                    curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
312
-                    break;
313
-                case HTTP_Request2::AUTH_DIGEST:
314
-                    curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
315
-                }
316
-            }
317
-            if ($type = $this->request->getConfig('proxy_type')) {
318
-                switch ($type) {
319
-                case 'http':
320
-                    curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
321
-                    break;
322
-                case 'socks5':
323
-                    curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
324
-                    break;
325
-                default:
326
-                    throw new HTTP_Request2_NotImplementedException(
327
-                        "Proxy type '{$type}' is not supported"
328
-                    );
329
-                }
330
-            }
331
-        }
332
-
333
-        // set authentication data
334
-        if ($auth = $this->request->getAuth()) {
335
-            curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']);
336
-            switch ($auth['scheme']) {
337
-            case HTTP_Request2::AUTH_BASIC:
338
-                curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
339
-                break;
340
-            case HTTP_Request2::AUTH_DIGEST:
341
-                curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
342
-            }
343
-        }
344
-
345
-        // set SSL options
346
-        foreach ($this->request->getConfig() as $name => $value) {
347
-            if ('ssl_verify_host' == $name && null !== $value) {
348
-                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $value? 2: 0);
349
-            } elseif (isset(self::$sslContextMap[$name]) && null !== $value) {
350
-                curl_setopt($ch, self::$sslContextMap[$name], $value);
351
-            }
352
-        }
353
-
354
-        $headers = $this->request->getHeaders();
355
-        // make cURL automagically send proper header
356
-        if (!isset($headers['accept-encoding'])) {
357
-            $headers['accept-encoding'] = '';
358
-        }
359
-
360
-        if (($jar = $this->request->getCookieJar())
361
-            && ($cookies = $jar->getMatching($this->request->getUrl(), true))
362
-        ) {
363
-            $headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
364
-        }
365
-
366
-        // set headers having special cURL keys
367
-        foreach (self::$headerMap as $name => $option) {
368
-            if (isset($headers[$name])) {
369
-                curl_setopt($ch, $option, $headers[$name]);
370
-                unset($headers[$name]);
371
-            }
372
-        }
373
-
374
-        $this->calculateRequestLength($headers);
375
-        if (isset($headers['content-length']) || isset($headers['transfer-encoding'])) {
376
-            $this->workaroundPhpBug47204($ch, $headers);
377
-        }
378
-
379
-        // set headers not having special keys
380
-        $headersFmt = array();
381
-        foreach ($headers as $name => $value) {
382
-            $canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
383
-            $headersFmt[]  = $canonicalName . ': ' . $value;
384
-        }
385
-        curl_setopt($ch, CURLOPT_HTTPHEADER, $headersFmt);
386
-
387
-        return $ch;
388
-    }
389
-
390
-    /**
391
-     * Workaround for PHP bug #47204 that prevents rewinding request body
392
-     *
393
-     * The workaround consists of reading the entire request body into memory
394
-     * and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large
395
-     * file uploads, use Socket adapter instead.
396
-     *
397
-     * @param resource $ch       cURL handle
398
-     * @param array    &$headers Request headers
399
-     */
400
-    protected function workaroundPhpBug47204($ch, &$headers)
401
-    {
402
-        // no redirects, no digest auth -> probably no rewind needed
403
-        if (!$this->request->getConfig('follow_redirects')
404
-            && (!($auth = $this->request->getAuth())
405
-                || HTTP_Request2::AUTH_DIGEST != $auth['scheme'])
406
-        ) {
407
-            curl_setopt($ch, CURLOPT_READFUNCTION, array($this, 'callbackReadBody'));
408
-
409
-        } else {
410
-            // rewind may be needed, read the whole body into memory
411
-            if ($this->requestBody instanceof HTTP_Request2_MultipartBody) {
412
-                $this->requestBody = $this->requestBody->__toString();
413
-
414
-            } elseif (is_resource($this->requestBody)) {
415
-                $fp = $this->requestBody;
416
-                $this->requestBody = '';
417
-                while (!feof($fp)) {
418
-                    $this->requestBody .= fread($fp, 16384);
419
-                }
420
-            }
421
-            // curl hangs up if content-length is present
422
-            unset($headers['content-length']);
423
-            curl_setopt($ch, CURLOPT_POSTFIELDS, $this->requestBody);
424
-        }
425
-    }
426
-
427
-    /**
428
-     * Callback function called by cURL for reading the request body
429
-     *
430
-     * @param resource $ch     cURL handle
431
-     * @param resource $fd     file descriptor (not used)
432
-     * @param integer  $length maximum length of data to return
433
-     *
434
-     * @return   string      part of the request body, up to $length bytes
435
-     */
436
-    protected function callbackReadBody($ch, $fd, $length)
437
-    {
438
-        if (!$this->eventSentHeaders) {
439
-            $this->request->setLastEvent(
440
-                'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)
441
-            );
442
-            $this->eventSentHeaders = true;
443
-        }
444
-        if (in_array($this->request->getMethod(), self::$bodyDisallowed)
445
-            || 0 == $this->contentLength || $this->position >= $this->contentLength
446
-        ) {
447
-            return '';
448
-        }
449
-        if (is_string($this->requestBody)) {
450
-            $string = substr($this->requestBody, $this->position, $length);
451
-        } elseif (is_resource($this->requestBody)) {
452
-            $string = fread($this->requestBody, $length);
453
-        } else {
454
-            $string = $this->requestBody->read($length);
455
-        }
456
-        $this->request->setLastEvent('sentBodyPart', strlen($string));
457
-        $this->position += strlen($string);
458
-        return $string;
459
-    }
460
-
461
-    /**
462
-     * Callback function called by cURL for saving the response headers
463
-     *
464
-     * @param resource $ch     cURL handle
465
-     * @param string   $string response header (with trailing CRLF)
466
-     *
467
-     * @return   integer     number of bytes saved
468
-     * @see      HTTP_Request2_Response::parseHeaderLine()
469
-     */
470
-    protected function callbackWriteHeader($ch, $string)
471
-    {
472
-        // we may receive a second set of headers if doing e.g. digest auth
473
-        if ($this->eventReceivedHeaders || !$this->eventSentHeaders) {
474
-            // don't bother with 100-Continue responses (bug #15785)
475
-            if (!$this->eventSentHeaders
476
-                || $this->response->getStatus() >= 200
477
-            ) {
478
-                $this->request->setLastEvent(
479
-                    'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)
480
-                );
481
-            }
482
-            $upload = curl_getinfo($ch, CURLINFO_SIZE_UPLOAD);
483
-            // if body wasn't read by a callback, send event with total body size
484
-            if ($upload > $this->position) {
485
-                $this->request->setLastEvent(
486
-                    'sentBodyPart', $upload - $this->position
487
-                );
488
-                $this->position = $upload;
489
-            }
490
-            if ($upload && (!$this->eventSentHeaders
491
-                            || $this->response->getStatus() >= 200)
492
-            ) {
493
-                $this->request->setLastEvent('sentBody', $upload);
494
-            }
495
-            $this->eventSentHeaders = true;
496
-            // we'll need a new response object
497
-            if ($this->eventReceivedHeaders) {
498
-                $this->eventReceivedHeaders = false;
499
-                $this->response             = null;
500
-            }
501
-        }
502
-        if (empty($this->response)) {
503
-            $this->response = new HTTP_Request2_Response(
504
-                $string, false, curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)
505
-            );
506
-        } else {
507
-            $this->response->parseHeaderLine($string);
508
-            if ('' == trim($string)) {
509
-                // don't bother with 100-Continue responses (bug #15785)
510
-                if (200 <= $this->response->getStatus()) {
511
-                    $this->request->setLastEvent('receivedHeaders', $this->response);
512
-                }
513
-
514
-                if ($this->request->getConfig('follow_redirects') && $this->response->isRedirect()) {
515
-                    $redirectUrl = new Net_URL2($this->response->getHeader('location'));
516
-
517
-                    // for versions lower than 5.2.10, check the redirection URL protocol
518
-                    if (!defined('CURLOPT_REDIR_PROTOCOLS') && $redirectUrl->isAbsolute()
519
-                        && !in_array($redirectUrl->getScheme(), array('http', 'https'))
520
-                    ) {
521
-                        return -1;
522
-                    }
523
-
524
-                    if ($jar = $this->request->getCookieJar()) {
525
-                        $jar->addCookiesFromResponse($this->response, $this->request->getUrl());
526
-                        if (!$redirectUrl->isAbsolute()) {
527
-                            $redirectUrl = $this->request->getUrl()->resolve($redirectUrl);
528
-                        }
529
-                        if ($cookies = $jar->getMatching($redirectUrl, true)) {
530
-                            curl_setopt($ch, CURLOPT_COOKIE, $cookies);
531
-                        }
532
-                    }
533
-                }
534
-                $this->eventReceivedHeaders = true;
535
-            }
536
-        }
537
-        return strlen($string);
538
-    }
539
-
540
-    /**
541
-     * Callback function called by cURL for saving the response body
542
-     *
543
-     * @param resource $ch     cURL handle (not used)
544
-     * @param string   $string part of the response body
545
-     *
546
-     * @return   integer     number of bytes saved
547
-     * @throws   HTTP_Request2_MessageException
548
-     * @see      HTTP_Request2_Response::appendBody()
549
-     */
550
-    protected function callbackWriteBody($ch, $string)
551
-    {
552
-        // cURL calls WRITEFUNCTION callback without calling HEADERFUNCTION if
553
-        // response doesn't start with proper HTTP status line (see bug #15716)
554
-        if (empty($this->response)) {
555
-            throw new HTTP_Request2_MessageException(
556
-                "Malformed response: {$string}",
557
-                HTTP_Request2_Exception::MALFORMED_RESPONSE
558
-            );
559
-        }
560
-        if ($this->request->getConfig('store_body')) {
561
-            $this->response->appendBody($string);
562
-        }
563
-        $this->request->setLastEvent('receivedBodyPart', $string);
564
-        return strlen($string);
565
-    }
38
+	/**
39
+	 * Mapping of header names to cURL options
40
+	 * @var  array
41
+	 */
42
+	protected static $headerMap = array(
43
+		'accept-encoding' => CURLOPT_ENCODING,
44
+		'cookie'          => CURLOPT_COOKIE,
45
+		'referer'         => CURLOPT_REFERER,
46
+		'user-agent'      => CURLOPT_USERAGENT
47
+	);
48
+
49
+	/**
50
+	 * Mapping of SSL context options to cURL options
51
+	 * @var  array
52
+	 */
53
+	protected static $sslContextMap = array(
54
+		'ssl_verify_peer' => CURLOPT_SSL_VERIFYPEER,
55
+		'ssl_cafile'      => CURLOPT_CAINFO,
56
+		'ssl_capath'      => CURLOPT_CAPATH,
57
+		'ssl_local_cert'  => CURLOPT_SSLCERT,
58
+		'ssl_passphrase'  => CURLOPT_SSLCERTPASSWD
59
+	);
60
+
61
+	/**
62
+	 * Mapping of CURLE_* constants to Exception subclasses and error codes
63
+	 * @var  array
64
+	 */
65
+	protected static $errorMap = array(
66
+		CURLE_UNSUPPORTED_PROTOCOL  => array('HTTP_Request2_MessageException',
67
+											 HTTP_Request2_Exception::NON_HTTP_REDIRECT),
68
+		CURLE_COULDNT_RESOLVE_PROXY => array('HTTP_Request2_ConnectionException'),
69
+		CURLE_COULDNT_RESOLVE_HOST  => array('HTTP_Request2_ConnectionException'),
70
+		CURLE_COULDNT_CONNECT       => array('HTTP_Request2_ConnectionException'),
71
+		// error returned from write callback
72
+		CURLE_WRITE_ERROR           => array('HTTP_Request2_MessageException',
73
+											 HTTP_Request2_Exception::NON_HTTP_REDIRECT),
74
+		CURLE_OPERATION_TIMEOUTED   => array('HTTP_Request2_MessageException',
75
+											 HTTP_Request2_Exception::TIMEOUT),
76
+		CURLE_HTTP_RANGE_ERROR      => array('HTTP_Request2_MessageException'),
77
+		CURLE_SSL_CONNECT_ERROR     => array('HTTP_Request2_ConnectionException'),
78
+		CURLE_LIBRARY_NOT_FOUND     => array('HTTP_Request2_LogicException',
79
+											 HTTP_Request2_Exception::MISCONFIGURATION),
80
+		CURLE_FUNCTION_NOT_FOUND    => array('HTTP_Request2_LogicException',
81
+											 HTTP_Request2_Exception::MISCONFIGURATION),
82
+		CURLE_ABORTED_BY_CALLBACK   => array('HTTP_Request2_MessageException',
83
+											 HTTP_Request2_Exception::NON_HTTP_REDIRECT),
84
+		CURLE_TOO_MANY_REDIRECTS    => array('HTTP_Request2_MessageException',
85
+											 HTTP_Request2_Exception::TOO_MANY_REDIRECTS),
86
+		CURLE_SSL_PEER_CERTIFICATE  => array('HTTP_Request2_ConnectionException'),
87
+		CURLE_GOT_NOTHING           => array('HTTP_Request2_MessageException'),
88
+		CURLE_SSL_ENGINE_NOTFOUND   => array('HTTP_Request2_LogicException',
89
+											 HTTP_Request2_Exception::MISCONFIGURATION),
90
+		CURLE_SSL_ENGINE_SETFAILED  => array('HTTP_Request2_LogicException',
91
+											 HTTP_Request2_Exception::MISCONFIGURATION),
92
+		CURLE_SEND_ERROR            => array('HTTP_Request2_MessageException'),
93
+		CURLE_RECV_ERROR            => array('HTTP_Request2_MessageException'),
94
+		CURLE_SSL_CERTPROBLEM       => array('HTTP_Request2_LogicException',
95
+											 HTTP_Request2_Exception::INVALID_ARGUMENT),
96
+		CURLE_SSL_CIPHER            => array('HTTP_Request2_ConnectionException'),
97
+		CURLE_SSL_CACERT            => array('HTTP_Request2_ConnectionException'),
98
+		CURLE_BAD_CONTENT_ENCODING  => array('HTTP_Request2_MessageException'),
99
+	);
100
+
101
+	/**
102
+	 * Response being received
103
+	 * @var  HTTP_Request2_Response
104
+	 */
105
+	protected $response;
106
+
107
+	/**
108
+	 * Whether 'sentHeaders' event was sent to observers
109
+	 * @var  boolean
110
+	 */
111
+	protected $eventSentHeaders = false;
112
+
113
+	/**
114
+	 * Whether 'receivedHeaders' event was sent to observers
115
+	 * @var boolean
116
+	 */
117
+	protected $eventReceivedHeaders = false;
118
+
119
+	/**
120
+	 * Position within request body
121
+	 * @var  integer
122
+	 * @see  callbackReadBody()
123
+	 */
124
+	protected $position = 0;
125
+
126
+	/**
127
+	 * Information about last transfer, as returned by curl_getinfo()
128
+	 * @var  array
129
+	 */
130
+	protected $lastInfo;
131
+
132
+	/**
133
+	 * Creates a subclass of HTTP_Request2_Exception from curl error data
134
+	 *
135
+	 * @param resource $ch curl handle
136
+	 *
137
+	 * @return HTTP_Request2_Exception
138
+	 */
139
+	protected static function wrapCurlError($ch)
140
+	{
141
+		$nativeCode = curl_errno($ch);
142
+		$message    = 'Curl error: ' . curl_error($ch);
143
+		if (!isset(self::$errorMap[$nativeCode])) {
144
+			return new HTTP_Request2_Exception($message, 0, $nativeCode);
145
+		} else {
146
+			$class = self::$errorMap[$nativeCode][0];
147
+			$code  = empty(self::$errorMap[$nativeCode][1])
148
+					 ? 0 : self::$errorMap[$nativeCode][1];
149
+			return new $class($message, $code, $nativeCode);
150
+		}
151
+	}
152
+
153
+	/**
154
+	 * Sends request to the remote server and returns its response
155
+	 *
156
+	 * @param HTTP_Request2 $request HTTP request message
157
+	 *
158
+	 * @return   HTTP_Request2_Response
159
+	 * @throws   HTTP_Request2_Exception
160
+	 */
161
+	public function sendRequest(HTTP_Request2 $request)
162
+	{
163
+		if (!extension_loaded('curl')) {
164
+			throw new HTTP_Request2_LogicException(
165
+				'cURL extension not available', HTTP_Request2_Exception::MISCONFIGURATION
166
+			);
167
+		}
168
+
169
+		$this->request              = $request;
170
+		$this->response             = null;
171
+		$this->position             = 0;
172
+		$this->eventSentHeaders     = false;
173
+		$this->eventReceivedHeaders = false;
174
+
175
+		try {
176
+			if (false === curl_exec($ch = $this->createCurlHandle())) {
177
+				$e = self::wrapCurlError($ch);
178
+			}
179
+		} catch (Exception $e) {
180
+		}
181
+		if (isset($ch)) {
182
+			$this->lastInfo = curl_getinfo($ch);
183
+			curl_close($ch);
184
+		}
185
+
186
+		$response = $this->response;
187
+		unset($this->request, $this->requestBody, $this->response);
188
+
189
+		if (!empty($e)) {
190
+			throw $e;
191
+		}
192
+
193
+		if ($jar = $request->getCookieJar()) {
194
+			$jar->addCookiesFromResponse($response, $request->getUrl());
195
+		}
196
+
197
+		if (0 < $this->lastInfo['size_download']) {
198
+			$request->setLastEvent('receivedBody', $response);
199
+		}
200
+		return $response;
201
+	}
202
+
203
+	/**
204
+	 * Returns information about last transfer
205
+	 *
206
+	 * @return   array   associative array as returned by curl_getinfo()
207
+	 */
208
+	public function getInfo()
209
+	{
210
+		return $this->lastInfo;
211
+	}
212
+
213
+	/**
214
+	 * Creates a new cURL handle and populates it with data from the request
215
+	 *
216
+	 * @return   resource    a cURL handle, as created by curl_init()
217
+	 * @throws   HTTP_Request2_LogicException
218
+	 * @throws   HTTP_Request2_NotImplementedException
219
+	 */
220
+	protected function createCurlHandle()
221
+	{
222
+		$ch = curl_init();
223
+
224
+		curl_setopt_array($ch, array(
225
+			// setup write callbacks
226
+			CURLOPT_HEADERFUNCTION => array($this, 'callbackWriteHeader'),
227
+			CURLOPT_WRITEFUNCTION  => array($this, 'callbackWriteBody'),
228
+			// buffer size
229
+			CURLOPT_BUFFERSIZE     => $this->request->getConfig('buffer_size'),
230
+			// connection timeout
231
+			CURLOPT_CONNECTTIMEOUT => $this->request->getConfig('connect_timeout'),
232
+			// save full outgoing headers, in case someone is interested
233
+			CURLINFO_HEADER_OUT    => true,
234
+			// request url
235
+			CURLOPT_URL            => $this->request->getUrl()->getUrl()
236
+		));
237
+
238
+		// set up redirects
239
+		if (!$this->request->getConfig('follow_redirects')) {
240
+			curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
241
+		} else {
242
+			if (!@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true)) {
243
+				throw new HTTP_Request2_LogicException(
244
+					'Redirect support in curl is unavailable due to open_basedir or safe_mode setting',
245
+					HTTP_Request2_Exception::MISCONFIGURATION
246
+				);
247
+			}
248
+			curl_setopt($ch, CURLOPT_MAXREDIRS, $this->request->getConfig('max_redirects'));
249
+			// limit redirects to http(s), works in 5.2.10+
250
+			if (defined('CURLOPT_REDIR_PROTOCOLS')) {
251
+				curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
252
+			}
253
+			// works in 5.3.2+, http://bugs.php.net/bug.php?id=49571
254
+			if ($this->request->getConfig('strict_redirects') && defined('CURLOPT_POSTREDIR')) {
255
+				curl_setopt($ch, CURLOPT_POSTREDIR, 3);
256
+			}
257
+		}
258
+
259
+		// set local IP via CURLOPT_INTERFACE (request #19515)
260
+		if ($ip = $this->request->getConfig('local_ip')) {
261
+			curl_setopt($ch, CURLOPT_INTERFACE, $ip);
262
+		}
263
+
264
+		// request timeout
265
+		if ($timeout = $this->request->getConfig('timeout')) {
266
+			curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
267
+		}
268
+
269
+		// set HTTP version
270
+		switch ($this->request->getConfig('protocol_version')) {
271
+		case '1.0':
272
+			curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
273
+			break;
274
+		case '1.1':
275
+			curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
276
+		}
277
+
278
+		// set request method
279
+		switch ($this->request->getMethod()) {
280
+		case HTTP_Request2::METHOD_GET:
281
+			curl_setopt($ch, CURLOPT_HTTPGET, true);
282
+			break;
283
+		case HTTP_Request2::METHOD_POST:
284
+			curl_setopt($ch, CURLOPT_POST, true);
285
+			break;
286
+		case HTTP_Request2::METHOD_HEAD:
287
+			curl_setopt($ch, CURLOPT_NOBODY, true);
288
+			break;
289
+		case HTTP_Request2::METHOD_PUT:
290
+			curl_setopt($ch, CURLOPT_UPLOAD, true);
291
+			break;
292
+		default:
293
+			curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());
294
+		}
295
+
296
+		// set proxy, if needed
297
+		if ($host = $this->request->getConfig('proxy_host')) {
298
+			if (!($port = $this->request->getConfig('proxy_port'))) {
299
+				throw new HTTP_Request2_LogicException(
300
+					'Proxy port not provided', HTTP_Request2_Exception::MISSING_VALUE
301
+				);
302
+			}
303
+			curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port);
304
+			if ($user = $this->request->getConfig('proxy_user')) {
305
+				curl_setopt(
306
+					$ch, CURLOPT_PROXYUSERPWD,
307
+					$user . ':' . $this->request->getConfig('proxy_password')
308
+				);
309
+				switch ($this->request->getConfig('proxy_auth_scheme')) {
310
+				case HTTP_Request2::AUTH_BASIC:
311
+					curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
312
+					break;
313
+				case HTTP_Request2::AUTH_DIGEST:
314
+					curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
315
+				}
316
+			}
317
+			if ($type = $this->request->getConfig('proxy_type')) {
318
+				switch ($type) {
319
+				case 'http':
320
+					curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
321
+					break;
322
+				case 'socks5':
323
+					curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
324
+					break;
325
+				default:
326
+					throw new HTTP_Request2_NotImplementedException(
327
+						"Proxy type '{$type}' is not supported"
328
+					);
329
+				}
330
+			}
331
+		}
332
+
333
+		// set authentication data
334
+		if ($auth = $this->request->getAuth()) {
335
+			curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']);
336
+			switch ($auth['scheme']) {
337
+			case HTTP_Request2::AUTH_BASIC:
338
+				curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
339
+				break;
340
+			case HTTP_Request2::AUTH_DIGEST:
341
+				curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
342
+			}
343
+		}
344
+
345
+		// set SSL options
346
+		foreach ($this->request->getConfig() as $name => $value) {
347
+			if ('ssl_verify_host' == $name && null !== $value) {
348
+				curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $value? 2: 0);
349
+			} elseif (isset(self::$sslContextMap[$name]) && null !== $value) {
350
+				curl_setopt($ch, self::$sslContextMap[$name], $value);
351
+			}
352
+		}
353
+
354
+		$headers = $this->request->getHeaders();
355
+		// make cURL automagically send proper header
356
+		if (!isset($headers['accept-encoding'])) {
357
+			$headers['accept-encoding'] = '';
358
+		}
359
+
360
+		if (($jar = $this->request->getCookieJar())
361
+			&& ($cookies = $jar->getMatching($this->request->getUrl(), true))
362
+		) {
363
+			$headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
364
+		}
365
+
366
+		// set headers having special cURL keys
367
+		foreach (self::$headerMap as $name => $option) {
368
+			if (isset($headers[$name])) {
369
+				curl_setopt($ch, $option, $headers[$name]);
370
+				unset($headers[$name]);
371
+			}
372
+		}
373
+
374
+		$this->calculateRequestLength($headers);
375
+		if (isset($headers['content-length']) || isset($headers['transfer-encoding'])) {
376
+			$this->workaroundPhpBug47204($ch, $headers);
377
+		}
378
+
379
+		// set headers not having special keys
380
+		$headersFmt = array();
381
+		foreach ($headers as $name => $value) {
382
+			$canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
383
+			$headersFmt[]  = $canonicalName . ': ' . $value;
384
+		}
385
+		curl_setopt($ch, CURLOPT_HTTPHEADER, $headersFmt);
386
+
387
+		return $ch;
388
+	}
389
+
390
+	/**
391
+	 * Workaround for PHP bug #47204 that prevents rewinding request body
392
+	 *
393
+	 * The workaround consists of reading the entire request body into memory
394
+	 * and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large
395
+	 * file uploads, use Socket adapter instead.
396
+	 *
397
+	 * @param resource $ch       cURL handle
398
+	 * @param array    &$headers Request headers
399
+	 */
400
+	protected function workaroundPhpBug47204($ch, &$headers)
401
+	{
402
+		// no redirects, no digest auth -> probably no rewind needed
403
+		if (!$this->request->getConfig('follow_redirects')
404
+			&& (!($auth = $this->request->getAuth())
405
+				|| HTTP_Request2::AUTH_DIGEST != $auth['scheme'])
406
+		) {
407
+			curl_setopt($ch, CURLOPT_READFUNCTION, array($this, 'callbackReadBody'));
408
+
409
+		} else {
410
+			// rewind may be needed, read the whole body into memory
411
+			if ($this->requestBody instanceof HTTP_Request2_MultipartBody) {
412
+				$this->requestBody = $this->requestBody->__toString();
413
+
414
+			} elseif (is_resource($this->requestBody)) {
415
+				$fp = $this->requestBody;
416
+				$this->requestBody = '';
417
+				while (!feof($fp)) {
418
+					$this->requestBody .= fread($fp, 16384);
419
+				}
420
+			}
421
+			// curl hangs up if content-length is present
422
+			unset($headers['content-length']);
423
+			curl_setopt($ch, CURLOPT_POSTFIELDS, $this->requestBody);
424
+		}
425
+	}
426
+
427
+	/**
428
+	 * Callback function called by cURL for reading the request body
429
+	 *
430
+	 * @param resource $ch     cURL handle
431
+	 * @param resource $fd     file descriptor (not used)
432
+	 * @param integer  $length maximum length of data to return
433
+	 *
434
+	 * @return   string      part of the request body, up to $length bytes
435
+	 */
436
+	protected function callbackReadBody($ch, $fd, $length)
437
+	{
438
+		if (!$this->eventSentHeaders) {
439
+			$this->request->setLastEvent(
440
+				'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)
441
+			);
442
+			$this->eventSentHeaders = true;
443
+		}
444
+		if (in_array($this->request->getMethod(), self::$bodyDisallowed)
445
+			|| 0 == $this->contentLength || $this->position >= $this->contentLength
446
+		) {
447
+			return '';
448
+		}
449
+		if (is_string($this->requestBody)) {
450
+			$string = substr($this->requestBody, $this->position, $length);
451
+		} elseif (is_resource($this->requestBody)) {
452
+			$string = fread($this->requestBody, $length);
453
+		} else {
454
+			$string = $this->requestBody->read($length);
455
+		}
456
+		$this->request->setLastEvent('sentBodyPart', strlen($string));
457
+		$this->position += strlen($string);
458
+		return $string;
459
+	}
460
+
461
+	/**
462
+	 * Callback function called by cURL for saving the response headers
463
+	 *
464
+	 * @param resource $ch     cURL handle
465
+	 * @param string   $string response header (with trailing CRLF)
466
+	 *
467
+	 * @return   integer     number of bytes saved
468
+	 * @see      HTTP_Request2_Response::parseHeaderLine()
469
+	 */
470
+	protected function callbackWriteHeader($ch, $string)
471
+	{
472
+		// we may receive a second set of headers if doing e.g. digest auth
473
+		if ($this->eventReceivedHeaders || !$this->eventSentHeaders) {
474
+			// don't bother with 100-Continue responses (bug #15785)
475
+			if (!$this->eventSentHeaders
476
+				|| $this->response->getStatus() >= 200
477
+			) {
478
+				$this->request->setLastEvent(
479
+					'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)
480
+				);
481
+			}
482
+			$upload = curl_getinfo($ch, CURLINFO_SIZE_UPLOAD);
483
+			// if body wasn't read by a callback, send event with total body size
484
+			if ($upload > $this->position) {
485
+				$this->request->setLastEvent(
486
+					'sentBodyPart', $upload - $this->position
487
+				);
488
+				$this->position = $upload;
489
+			}
490
+			if ($upload && (!$this->eventSentHeaders
491
+							|| $this->response->getStatus() >= 200)
492
+			) {
493
+				$this->request->setLastEvent('sentBody', $upload);
494
+			}
495
+			$this->eventSentHeaders = true;
496
+			// we'll need a new response object
497
+			if ($this->eventReceivedHeaders) {
498
+				$this->eventReceivedHeaders = false;
499
+				$this->response             = null;
500
+			}
501
+		}
502
+		if (empty($this->response)) {
503
+			$this->response = new HTTP_Request2_Response(
504
+				$string, false, curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)
505
+			);
506
+		} else {
507
+			$this->response->parseHeaderLine($string);
508
+			if ('' == trim($string)) {
509
+				// don't bother with 100-Continue responses (bug #15785)
510
+				if (200 <= $this->response->getStatus()) {
511
+					$this->request->setLastEvent('receivedHeaders', $this->response);
512
+				}
513
+
514
+				if ($this->request->getConfig('follow_redirects') && $this->response->isRedirect()) {
515
+					$redirectUrl = new Net_URL2($this->response->getHeader('location'));
516
+
517
+					// for versions lower than 5.2.10, check the redirection URL protocol
518
+					if (!defined('CURLOPT_REDIR_PROTOCOLS') && $redirectUrl->isAbsolute()
519
+						&& !in_array($redirectUrl->getScheme(), array('http', 'https'))
520
+					) {
521
+						return -1;
522
+					}
523
+
524
+					if ($jar = $this->request->getCookieJar()) {
525
+						$jar->addCookiesFromResponse($this->response, $this->request->getUrl());
526
+						if (!$redirectUrl->isAbsolute()) {
527
+							$redirectUrl = $this->request->getUrl()->resolve($redirectUrl);
528
+						}
529
+						if ($cookies = $jar->getMatching($redirectUrl, true)) {
530
+							curl_setopt($ch, CURLOPT_COOKIE, $cookies);
531
+						}
532
+					}
533
+				}
534
+				$this->eventReceivedHeaders = true;
535
+			}
536
+		}
537
+		return strlen($string);
538
+	}
539
+
540
+	/**
541
+	 * Callback function called by cURL for saving the response body
542
+	 *
543
+	 * @param resource $ch     cURL handle (not used)
544
+	 * @param string   $string part of the response body
545
+	 *
546
+	 * @return   integer     number of bytes saved
547
+	 * @throws   HTTP_Request2_MessageException
548
+	 * @see      HTTP_Request2_Response::appendBody()
549
+	 */
550
+	protected function callbackWriteBody($ch, $string)
551
+	{
552
+		// cURL calls WRITEFUNCTION callback without calling HEADERFUNCTION if
553
+		// response doesn't start with proper HTTP status line (see bug #15716)
554
+		if (empty($this->response)) {
555
+			throw new HTTP_Request2_MessageException(
556
+				"Malformed response: {$string}",
557
+				HTTP_Request2_Exception::MALFORMED_RESPONSE
558
+			);
559
+		}
560
+		if ($this->request->getConfig('store_body')) {
561
+			$this->response->appendBody($string);
562
+		}
563
+		$this->request->setLastEvent('receivedBodyPart', $string);
564
+		return strlen($string);
565
+	}
566 566
 }
567 567
 ?>
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -139,7 +139,7 @@  discard block
 block discarded – undo
139 139
     protected static function wrapCurlError($ch)
140 140
     {
141 141
         $nativeCode = curl_errno($ch);
142
-        $message    = 'Curl error: ' . curl_error($ch);
142
+        $message    = 'Curl error: '.curl_error($ch);
143 143
         if (!isset(self::$errorMap[$nativeCode])) {
144 144
             return new HTTP_Request2_Exception($message, 0, $nativeCode);
145 145
         } else {
@@ -300,11 +300,11 @@  discard block
 block discarded – undo
300 300
                     'Proxy port not provided', HTTP_Request2_Exception::MISSING_VALUE
301 301
                 );
302 302
             }
303
-            curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port);
303
+            curl_setopt($ch, CURLOPT_PROXY, $host.':'.$port);
304 304
             if ($user = $this->request->getConfig('proxy_user')) {
305 305
                 curl_setopt(
306 306
                     $ch, CURLOPT_PROXYUSERPWD,
307
-                    $user . ':' . $this->request->getConfig('proxy_password')
307
+                    $user.':'.$this->request->getConfig('proxy_password')
308 308
                 );
309 309
                 switch ($this->request->getConfig('proxy_auth_scheme')) {
310 310
                 case HTTP_Request2::AUTH_BASIC:
@@ -332,7 +332,7 @@  discard block
 block discarded – undo
332 332
 
333 333
         // set authentication data
334 334
         if ($auth = $this->request->getAuth()) {
335
-            curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']);
335
+            curl_setopt($ch, CURLOPT_USERPWD, $auth['user'].':'.$auth['password']);
336 336
             switch ($auth['scheme']) {
337 337
             case HTTP_Request2::AUTH_BASIC:
338 338
                 curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
         // set SSL options
346 346
         foreach ($this->request->getConfig() as $name => $value) {
347 347
             if ('ssl_verify_host' == $name && null !== $value) {
348
-                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $value? 2: 0);
348
+                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $value ? 2 : 0);
349 349
             } elseif (isset(self::$sslContextMap[$name]) && null !== $value) {
350 350
                 curl_setopt($ch, self::$sslContextMap[$name], $value);
351 351
             }
@@ -360,7 +360,7 @@  discard block
 block discarded – undo
360 360
         if (($jar = $this->request->getCookieJar())
361 361
             && ($cookies = $jar->getMatching($this->request->getUrl(), true))
362 362
         ) {
363
-            $headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
363
+            $headers['cookie'] = (empty($headers['cookie']) ? '' : $headers['cookie'].'; ').$cookies;
364 364
         }
365 365
 
366 366
         // set headers having special cURL keys
@@ -380,7 +380,7 @@  discard block
 block discarded – undo
380 380
         $headersFmt = array();
381 381
         foreach ($headers as $name => $value) {
382 382
             $canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
383
-            $headersFmt[]  = $canonicalName . ': ' . $value;
383
+            $headersFmt[]  = $canonicalName.': '.$value;
384 384
         }
385 385
         curl_setopt($ch, CURLOPT_HTTPHEADER, $headersFmt);
386 386
 
Please login to merge, or discard this patch.
libs/PEAR.1.9.5/HTTP/Request2/Adapter/Mock.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -70,7 +70,7 @@
 block discarded – undo
70 70
      */
71 71
     public function sendRequest(HTTP_Request2 $request)
72 72
     {
73
-        $requestUrl = (string)$request->getUrl();
73
+        $requestUrl = (string) $request->getUrl();
74 74
         $response   = null;
75 75
         foreach ($this->responses as $k => $v) {
76 76
             if (!$v[1] || $requestUrl == $v[1]) {
Please login to merge, or discard this patch.
Indentation   +106 added lines, -106 removed lines patch added patch discarded remove patch
@@ -49,118 +49,118 @@
 block discarded – undo
49 49
  */
50 50
 class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter
51 51
 {
52
-    /**
53
-     * A queue of responses to be returned by sendRequest()
54
-     * @var  array
55
-     */
56
-    protected $responses = array();
52
+	/**
53
+	 * A queue of responses to be returned by sendRequest()
54
+	 * @var  array
55
+	 */
56
+	protected $responses = array();
57 57
 
58
-    /**
59
-     * Returns the next response from the queue built by addResponse()
60
-     *
61
-     * Only responses without explicit URLs or with URLs equal to request URL
62
-     * will be considered. If matching response is not found or the queue is
63
-     * empty then default empty response with status 400 will be returned,
64
-     * if an Exception object was added to the queue it will be thrown.
65
-     *
66
-     * @param HTTP_Request2 $request HTTP request message
67
-     *
68
-     * @return   HTTP_Request2_Response
69
-     * @throws   Exception
70
-     */
71
-    public function sendRequest(HTTP_Request2 $request)
72
-    {
73
-        $requestUrl = (string)$request->getUrl();
74
-        $response   = null;
75
-        foreach ($this->responses as $k => $v) {
76
-            if (!$v[1] || $requestUrl == $v[1]) {
77
-                $response = $v[0];
78
-                array_splice($this->responses, $k, 1);
79
-                break;
80
-            }
81
-        }
82
-        if (!$response) {
83
-            return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n");
58
+	/**
59
+	 * Returns the next response from the queue built by addResponse()
60
+	 *
61
+	 * Only responses without explicit URLs or with URLs equal to request URL
62
+	 * will be considered. If matching response is not found or the queue is
63
+	 * empty then default empty response with status 400 will be returned,
64
+	 * if an Exception object was added to the queue it will be thrown.
65
+	 *
66
+	 * @param HTTP_Request2 $request HTTP request message
67
+	 *
68
+	 * @return   HTTP_Request2_Response
69
+	 * @throws   Exception
70
+	 */
71
+	public function sendRequest(HTTP_Request2 $request)
72
+	{
73
+		$requestUrl = (string)$request->getUrl();
74
+		$response   = null;
75
+		foreach ($this->responses as $k => $v) {
76
+			if (!$v[1] || $requestUrl == $v[1]) {
77
+				$response = $v[0];
78
+				array_splice($this->responses, $k, 1);
79
+				break;
80
+			}
81
+		}
82
+		if (!$response) {
83
+			return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n");
84 84
 
85
-        } elseif ($response instanceof HTTP_Request2_Response) {
86
-            return $response;
85
+		} elseif ($response instanceof HTTP_Request2_Response) {
86
+			return $response;
87 87
 
88
-        } else {
89
-            // rethrow the exception
90
-            $class   = get_class($response);
91
-            $message = $response->getMessage();
92
-            $code    = $response->getCode();
93
-            throw new $class($message, $code);
94
-        }
95
-    }
88
+		} else {
89
+			// rethrow the exception
90
+			$class   = get_class($response);
91
+			$message = $response->getMessage();
92
+			$code    = $response->getCode();
93
+			throw new $class($message, $code);
94
+		}
95
+	}
96 96
 
97
-    /**
98
-     * Adds response to the queue
99
-     *
100
-     * @param mixed  $response either a string, a pointer to an open file,
101
-     *                         an instance of HTTP_Request2_Response or Exception
102
-     * @param string $url      A request URL this response should be valid for
103
-     *                         (see {@link http://pear.php.net/bugs/bug.php?id=19276})
104
-     *
105
-     * @throws   HTTP_Request2_Exception
106
-     */
107
-    public function addResponse($response, $url = null)
108
-    {
109
-        if (is_string($response)) {
110
-            $response = self::createResponseFromString($response);
111
-        } elseif (is_resource($response)) {
112
-            $response = self::createResponseFromFile($response);
113
-        } elseif (!$response instanceof HTTP_Request2_Response &&
114
-                  !$response instanceof Exception
115
-        ) {
116
-            throw new HTTP_Request2_Exception('Parameter is not a valid response');
117
-        }
118
-        $this->responses[] = array($response, $url);
119
-    }
97
+	/**
98
+	 * Adds response to the queue
99
+	 *
100
+	 * @param mixed  $response either a string, a pointer to an open file,
101
+	 *                         an instance of HTTP_Request2_Response or Exception
102
+	 * @param string $url      A request URL this response should be valid for
103
+	 *                         (see {@link http://pear.php.net/bugs/bug.php?id=19276})
104
+	 *
105
+	 * @throws   HTTP_Request2_Exception
106
+	 */
107
+	public function addResponse($response, $url = null)
108
+	{
109
+		if (is_string($response)) {
110
+			$response = self::createResponseFromString($response);
111
+		} elseif (is_resource($response)) {
112
+			$response = self::createResponseFromFile($response);
113
+		} elseif (!$response instanceof HTTP_Request2_Response &&
114
+				  !$response instanceof Exception
115
+		) {
116
+			throw new HTTP_Request2_Exception('Parameter is not a valid response');
117
+		}
118
+		$this->responses[] = array($response, $url);
119
+	}
120 120
 
121
-    /**
122
-     * Creates a new HTTP_Request2_Response object from a string
123
-     *
124
-     * @param string $str string containing HTTP response message
125
-     *
126
-     * @return   HTTP_Request2_Response
127
-     * @throws   HTTP_Request2_Exception
128
-     */
129
-    public static function createResponseFromString($str)
130
-    {
131
-        $parts       = preg_split('!(\r?\n){2}!m', $str, 2);
132
-        $headerLines = explode("\n", $parts[0]);
133
-        $response    = new HTTP_Request2_Response(array_shift($headerLines));
134
-        foreach ($headerLines as $headerLine) {
135
-            $response->parseHeaderLine($headerLine);
136
-        }
137
-        $response->parseHeaderLine('');
138
-        if (isset($parts[1])) {
139
-            $response->appendBody($parts[1]);
140
-        }
141
-        return $response;
142
-    }
121
+	/**
122
+	 * Creates a new HTTP_Request2_Response object from a string
123
+	 *
124
+	 * @param string $str string containing HTTP response message
125
+	 *
126
+	 * @return   HTTP_Request2_Response
127
+	 * @throws   HTTP_Request2_Exception
128
+	 */
129
+	public static function createResponseFromString($str)
130
+	{
131
+		$parts       = preg_split('!(\r?\n){2}!m', $str, 2);
132
+		$headerLines = explode("\n", $parts[0]);
133
+		$response    = new HTTP_Request2_Response(array_shift($headerLines));
134
+		foreach ($headerLines as $headerLine) {
135
+			$response->parseHeaderLine($headerLine);
136
+		}
137
+		$response->parseHeaderLine('');
138
+		if (isset($parts[1])) {
139
+			$response->appendBody($parts[1]);
140
+		}
141
+		return $response;
142
+	}
143 143
 
144
-    /**
145
-     * Creates a new HTTP_Request2_Response object from a file
146
-     *
147
-     * @param resource $fp file pointer returned by fopen()
148
-     *
149
-     * @return   HTTP_Request2_Response
150
-     * @throws   HTTP_Request2_Exception
151
-     */
152
-    public static function createResponseFromFile($fp)
153
-    {
154
-        $response = new HTTP_Request2_Response(fgets($fp));
155
-        do {
156
-            $headerLine = fgets($fp);
157
-            $response->parseHeaderLine($headerLine);
158
-        } while ('' != trim($headerLine));
144
+	/**
145
+	 * Creates a new HTTP_Request2_Response object from a file
146
+	 *
147
+	 * @param resource $fp file pointer returned by fopen()
148
+	 *
149
+	 * @return   HTTP_Request2_Response
150
+	 * @throws   HTTP_Request2_Exception
151
+	 */
152
+	public static function createResponseFromFile($fp)
153
+	{
154
+		$response = new HTTP_Request2_Response(fgets($fp));
155
+		do {
156
+			$headerLine = fgets($fp);
157
+			$response->parseHeaderLine($headerLine);
158
+		} while ('' != trim($headerLine));
159 159
 
160
-        while (!feof($fp)) {
161
-            $response->appendBody(fread($fp, 8192));
162
-        }
163
-        return $response;
164
-    }
160
+		while (!feof($fp)) {
161
+			$response->appendBody(fread($fp, 8192));
162
+		}
163
+		return $response;
164
+	}
165 165
 }
166 166
 ?>
167 167
\ No newline at end of file
Please login to merge, or discard this patch.
libs/PEAR.1.9.5/HTTP/Request2/Adapter/Socket.php 3 patches
Switch Indentation   +52 added lines, -52 removed lines patch added patch discarded remove patch
@@ -732,34 +732,34 @@  discard block
 block discarded – undo
732 732
             return;
733 733
         }
734 734
         switch ($auth['scheme']) {
735
-        case HTTP_Request2::AUTH_BASIC:
736
-            $headers['authorization'] = 'Basic ' . base64_encode(
737
-                $auth['user'] . ':' . $auth['password']
738
-            );
739
-            break;
740
-
741
-        case HTTP_Request2::AUTH_DIGEST:
742
-            unset($this->serverChallenge);
743
-            $fullUrl = ('/' == $requestUrl[0])?
744
-                       $this->request->getUrl()->getScheme() . '://' .
745
-                        $requestHost . $requestUrl:
746
-                       $requestUrl;
747
-            foreach (array_keys(self::$challenges) as $key) {
748
-                if ($key == substr($fullUrl, 0, strlen($key))) {
749
-                    $headers['authorization'] = $this->createDigestResponse(
750
-                        $auth['user'], $auth['password'],
751
-                        $requestUrl, self::$challenges[$key]
752
-                    );
753
-                    $this->serverChallenge =& self::$challenges[$key];
754
-                    break;
755
-                }
756
-            }
757
-            break;
758
-
759
-        default:
760
-            throw new HTTP_Request2_NotImplementedException(
761
-                "Unknown HTTP authentication scheme '{$auth['scheme']}'"
762
-            );
735
+        	case HTTP_Request2::AUTH_BASIC:
736
+            	$headers['authorization'] = 'Basic ' . base64_encode(
737
+                	$auth['user'] . ':' . $auth['password']
738
+            	);
739
+            	break;
740
+
741
+        	case HTTP_Request2::AUTH_DIGEST:
742
+            	unset($this->serverChallenge);
743
+            	$fullUrl = ('/' == $requestUrl[0])?
744
+                       	$this->request->getUrl()->getScheme() . '://' .
745
+                        	$requestHost . $requestUrl:
746
+                       	$requestUrl;
747
+            	foreach (array_keys(self::$challenges) as $key) {
748
+                	if ($key == substr($fullUrl, 0, strlen($key))) {
749
+                    	$headers['authorization'] = $this->createDigestResponse(
750
+                        	$auth['user'], $auth['password'],
751
+                        	$requestUrl, self::$challenges[$key]
752
+                    	);
753
+                    	$this->serverChallenge =& self::$challenges[$key];
754
+                    	break;
755
+                	}
756
+            	}
757
+            	break;
758
+
759
+        	default:
760
+            	throw new HTTP_Request2_NotImplementedException(
761
+                	"Unknown HTTP authentication scheme '{$auth['scheme']}'"
762
+            	);
763 763
         }
764 764
     }
765 765
 
@@ -783,30 +783,30 @@  discard block
 block discarded – undo
783 783
 
784 784
         $password = $this->request->getConfig('proxy_password');
785 785
         switch ($this->request->getConfig('proxy_auth_scheme')) {
786
-        case HTTP_Request2::AUTH_BASIC:
787
-            $headers['proxy-authorization'] = 'Basic ' . base64_encode(
788
-                $user . ':' . $password
789
-            );
790
-            break;
791
-
792
-        case HTTP_Request2::AUTH_DIGEST:
793
-            unset($this->proxyChallenge);
794
-            $proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') .
795
-                        ':' . $this->request->getConfig('proxy_port');
796
-            if (!empty(self::$challenges[$proxyUrl])) {
797
-                $headers['proxy-authorization'] = $this->createDigestResponse(
798
-                    $user, $password,
799
-                    $requestUrl, self::$challenges[$proxyUrl]
800
-                );
801
-                $this->proxyChallenge =& self::$challenges[$proxyUrl];
802
-            }
803
-            break;
804
-
805
-        default:
806
-            throw new HTTP_Request2_NotImplementedException(
807
-                "Unknown HTTP authentication scheme '" .
808
-                $this->request->getConfig('proxy_auth_scheme') . "'"
809
-            );
786
+        	case HTTP_Request2::AUTH_BASIC:
787
+            	$headers['proxy-authorization'] = 'Basic ' . base64_encode(
788
+                	$user . ':' . $password
789
+            	);
790
+            	break;
791
+
792
+        	case HTTP_Request2::AUTH_DIGEST:
793
+            	unset($this->proxyChallenge);
794
+            	$proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') .
795
+                        	':' . $this->request->getConfig('proxy_port');
796
+            	if (!empty(self::$challenges[$proxyUrl])) {
797
+                	$headers['proxy-authorization'] = $this->createDigestResponse(
798
+                    	$user, $password,
799
+                    	$requestUrl, self::$challenges[$proxyUrl]
800
+                	);
801
+                	$this->proxyChallenge =& self::$challenges[$proxyUrl];
802
+            	}
803
+            	break;
804
+
805
+        	default:
806
+            	throw new HTTP_Request2_NotImplementedException(
807
+                	"Unknown HTTP authentication scheme '" .
808
+                	$this->request->getConfig('proxy_auth_scheme') . "'"
809
+            	);
810 810
         }
811 811
     }
812 812
 
Please login to merge, or discard this patch.
Indentation   +1077 added lines, -1077 removed lines patch added patch discarded remove patch
@@ -39,1083 +39,1083 @@
 block discarded – undo
39 39
  */
40 40
 class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
41 41
 {
42
-    /**
43
-     * Regular expression for 'token' rule from RFC 2616
44
-     */
45
-    const REGEXP_TOKEN = '[^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+';
46
-
47
-    /**
48
-     * Regular expression for 'quoted-string' rule from RFC 2616
49
-     */
50
-    const REGEXP_QUOTED_STRING = '"(?>[^"\\\\]+|\\\\.)*"';
51
-
52
-    /**
53
-     * Connected sockets, needed for Keep-Alive support
54
-     * @var  array
55
-     * @see  connect()
56
-     */
57
-    protected static $sockets = array();
58
-
59
-    /**
60
-     * Data for digest authentication scheme
61
-     *
62
-     * The keys for the array are URL prefixes.
63
-     *
64
-     * The values are associative arrays with data (realm, nonce, nonce-count,
65
-     * opaque...) needed for digest authentication. Stored here to prevent making
66
-     * duplicate requests to digest-protected resources after we have already
67
-     * received the challenge.
68
-     *
69
-     * @var  array
70
-     */
71
-    protected static $challenges = array();
72
-
73
-    /**
74
-     * Connected socket
75
-     * @var  HTTP_Request2_SocketWrapper
76
-     * @see  connect()
77
-     */
78
-    protected $socket;
79
-
80
-    /**
81
-     * Challenge used for server digest authentication
82
-     * @var  array
83
-     */
84
-    protected $serverChallenge;
85
-
86
-    /**
87
-     * Challenge used for proxy digest authentication
88
-     * @var  array
89
-     */
90
-    protected $proxyChallenge;
91
-
92
-    /**
93
-     * Remaining length of the current chunk, when reading chunked response
94
-     * @var  integer
95
-     * @see  readChunked()
96
-     */
97
-    protected $chunkLength = 0;
98
-
99
-    /**
100
-     * Remaining amount of redirections to follow
101
-     *
102
-     * Starts at 'max_redirects' configuration parameter and is reduced on each
103
-     * subsequent redirect. An Exception will be thrown once it reaches zero.
104
-     *
105
-     * @var  integer
106
-     */
107
-    protected $redirectCountdown = null;
108
-
109
-    /**
110
-     * Whether to wait for "100 Continue" response before sending request body
111
-     * @var bool
112
-     */
113
-    protected $expect100Continue = false;
114
-
115
-    /**
116
-     * Sends request to the remote server and returns its response
117
-     *
118
-     * @param HTTP_Request2 $request HTTP request message
119
-     *
120
-     * @return   HTTP_Request2_Response
121
-     * @throws   HTTP_Request2_Exception
122
-     */
123
-    public function sendRequest(HTTP_Request2 $request)
124
-    {
125
-        $this->request = $request;
126
-
127
-        try {
128
-            $keepAlive = $this->connect();
129
-            $headers   = $this->prepareHeaders();
130
-            $this->socket->write($headers);
131
-            // provide request headers to the observer, see request #7633
132
-            $this->request->setLastEvent('sentHeaders', $headers);
133
-
134
-            if (!$this->expect100Continue) {
135
-                $this->writeBody();
136
-                $response = $this->readResponse();
137
-
138
-            } else {
139
-                $response = $this->readResponse();
140
-                if (!$response || 100 == $response->getStatus()) {
141
-                    $this->expect100Continue = false;
142
-                    // either got "100 Continue" or timed out -> send body
143
-                    $this->writeBody();
144
-                    $response = $this->readResponse();
145
-                }
146
-            }
147
-
148
-
149
-            if ($jar = $request->getCookieJar()) {
150
-                $jar->addCookiesFromResponse($response, $request->getUrl());
151
-            }
152
-
153
-            if (!$this->canKeepAlive($keepAlive, $response)) {
154
-                $this->disconnect();
155
-            }
156
-
157
-            if ($this->shouldUseProxyDigestAuth($response)) {
158
-                return $this->sendRequest($request);
159
-            }
160
-            if ($this->shouldUseServerDigestAuth($response)) {
161
-                return $this->sendRequest($request);
162
-            }
163
-            if ($authInfo = $response->getHeader('authentication-info')) {
164
-                $this->updateChallenge($this->serverChallenge, $authInfo);
165
-            }
166
-            if ($proxyInfo = $response->getHeader('proxy-authentication-info')) {
167
-                $this->updateChallenge($this->proxyChallenge, $proxyInfo);
168
-            }
169
-
170
-        } catch (Exception $e) {
171
-            $this->disconnect();
172
-        }
173
-
174
-        unset($this->request, $this->requestBody);
175
-
176
-        if (!empty($e)) {
177
-            $this->redirectCountdown = null;
178
-            throw $e;
179
-        }
180
-
181
-        if (!$request->getConfig('follow_redirects') || !$response->isRedirect()) {
182
-            $this->redirectCountdown = null;
183
-            return $response;
184
-        } else {
185
-            return $this->handleRedirect($request, $response);
186
-        }
187
-    }
188
-
189
-    /**
190
-     * Connects to the remote server
191
-     *
192
-     * @return   bool    whether the connection can be persistent
193
-     * @throws   HTTP_Request2_Exception
194
-     */
195
-    protected function connect()
196
-    {
197
-        $secure  = 0 == strcasecmp($this->request->getUrl()->getScheme(), 'https');
198
-        $tunnel  = HTTP_Request2::METHOD_CONNECT == $this->request->getMethod();
199
-        $headers = $this->request->getHeaders();
200
-        $reqHost = $this->request->getUrl()->getHost();
201
-        if (!($reqPort = $this->request->getUrl()->getPort())) {
202
-            $reqPort = $secure? 443: 80;
203
-        }
204
-
205
-        $httpProxy = $socksProxy = false;
206
-        if (!($host = $this->request->getConfig('proxy_host'))) {
207
-            $host = $reqHost;
208
-            $port = $reqPort;
209
-        } else {
210
-            if (!($port = $this->request->getConfig('proxy_port'))) {
211
-                throw new HTTP_Request2_LogicException(
212
-                    'Proxy port not provided',
213
-                    HTTP_Request2_Exception::MISSING_VALUE
214
-                );
215
-            }
216
-            if ('http' == ($type = $this->request->getConfig('proxy_type'))) {
217
-                $httpProxy = true;
218
-            } elseif ('socks5' == $type) {
219
-                $socksProxy = true;
220
-            } else {
221
-                throw new HTTP_Request2_NotImplementedException(
222
-                    "Proxy type '{$type}' is not supported"
223
-                );
224
-            }
225
-        }
226
-
227
-        if ($tunnel && !$httpProxy) {
228
-            throw new HTTP_Request2_LogicException(
229
-                "Trying to perform CONNECT request without proxy",
230
-                HTTP_Request2_Exception::MISSING_VALUE
231
-            );
232
-        }
233
-        if ($secure && !in_array('ssl', stream_get_transports())) {
234
-            throw new HTTP_Request2_LogicException(
235
-                'Need OpenSSL support for https:// requests',
236
-                HTTP_Request2_Exception::MISCONFIGURATION
237
-            );
238
-        }
239
-
240
-        // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
241
-        // connection token to a proxy server...
242
-        if ($httpProxy && !$secure && !empty($headers['connection'])
243
-            && 'Keep-Alive' == $headers['connection']
244
-        ) {
245
-            $this->request->setHeader('connection');
246
-        }
247
-
248
-        $keepAlive = ('1.1' == $this->request->getConfig('protocol_version') &&
249
-                      empty($headers['connection'])) ||
250
-                     (!empty($headers['connection']) &&
251
-                      'Keep-Alive' == $headers['connection']);
252
-
253
-        $options = array();
254
-        if ($ip = $this->request->getConfig('local_ip')) {
255
-            $options['socket'] = array(
256
-                'bindto' => (false === strpos($ip, ':') ? $ip : '[' . $ip . ']') . ':0'
257
-            );
258
-        }
259
-        if ($secure || $tunnel) {
260
-            $options['ssl'] = array();
261
-            foreach ($this->request->getConfig() as $name => $value) {
262
-                if ('ssl_' == substr($name, 0, 4) && null !== $value) {
263
-                    if ('ssl_verify_host' == $name) {
264
-                        if ($value) {
265
-                            $options['ssl']['CN_match'] = $reqHost;
266
-                        }
267
-                    } else {
268
-                        $options['ssl'][substr($name, 4)] = $value;
269
-                    }
270
-                }
271
-            }
272
-            ksort($options['ssl']);
273
-        }
274
-
275
-        // Use global request timeout if given, see feature requests #5735, #8964
276
-        if ($timeout = $this->request->getConfig('timeout')) {
277
-            $deadline = time() + $timeout;
278
-        } else {
279
-            $deadline = null;
280
-        }
281
-
282
-        // Changing SSL context options after connection is established does *not*
283
-        // work, we need a new connection if options change
284
-        $remote    = ((!$secure || $httpProxy || $socksProxy)? 'tcp://': 'ssl://')
285
-                     . $host . ':' . $port;
286
-        $socketKey = $remote . (
287
-                        ($secure && $httpProxy || $socksProxy)
288
-                        ? "->{$reqHost}:{$reqPort}" : ''
289
-                     ) . (empty($options)? '': ':' . serialize($options));
290
-        unset($this->socket);
291
-
292
-        // We use persistent connections and have a connected socket?
293
-        // Ensure that the socket is still connected, see bug #16149
294
-        if ($keepAlive && !empty(self::$sockets[$socketKey])
295
-            && !self::$sockets[$socketKey]->eof()
296
-        ) {
297
-            $this->socket =& self::$sockets[$socketKey];
298
-
299
-        } else {
300
-            if ($socksProxy) {
301
-                require_once 'HTTP/Request2/SOCKS5.php';
302
-
303
-                $this->socket = new HTTP_Request2_SOCKS5(
304
-                    $remote, $this->request->getConfig('connect_timeout'),
305
-                    $options, $this->request->getConfig('proxy_user'),
306
-                    $this->request->getConfig('proxy_password')
307
-                );
308
-                // handle request timeouts ASAP
309
-                $this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));
310
-                $this->socket->connect($reqHost, $reqPort);
311
-                if (!$secure) {
312
-                    $conninfo = "tcp://{$reqHost}:{$reqPort} via {$remote}";
313
-                } else {
314
-                    $this->socket->enableCrypto();
315
-                    $conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";
316
-                }
317
-
318
-            } elseif ($secure && $httpProxy && !$tunnel) {
319
-                $this->establishTunnel();
320
-                $conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";
321
-
322
-            } else {
323
-                $this->socket = new HTTP_Request2_SocketWrapper(
324
-                    $remote, $this->request->getConfig('connect_timeout'), $options
325
-                );
326
-            }
327
-            $this->request->setLastEvent('connect', empty($conninfo)? $remote: $conninfo);
328
-            self::$sockets[$socketKey] =& $this->socket;
329
-        }
330
-        $this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));
331
-        return $keepAlive;
332
-    }
333
-
334
-    /**
335
-     * Establishes a tunnel to a secure remote server via HTTP CONNECT request
336
-     *
337
-     * This method will fail if 'ssl_verify_peer' is enabled. Probably because PHP
338
-     * sees that we are connected to a proxy server (duh!) rather than the server
339
-     * that presents its certificate.
340
-     *
341
-     * @link     http://tools.ietf.org/html/rfc2817#section-5.2
342
-     * @throws   HTTP_Request2_Exception
343
-     */
344
-    protected function establishTunnel()
345
-    {
346
-        $donor   = new self;
347
-        $connect = new HTTP_Request2(
348
-            $this->request->getUrl(), HTTP_Request2::METHOD_CONNECT,
349
-            array_merge($this->request->getConfig(), array('adapter' => $donor))
350
-        );
351
-        $response = $connect->send();
352
-        // Need any successful (2XX) response
353
-        if (200 > $response->getStatus() || 300 <= $response->getStatus()) {
354
-            throw new HTTP_Request2_ConnectionException(
355
-                'Failed to connect via HTTPS proxy. Proxy response: ' .
356
-                $response->getStatus() . ' ' . $response->getReasonPhrase()
357
-            );
358
-        }
359
-        $this->socket = $donor->socket;
360
-        $this->socket->enableCrypto();
361
-    }
362
-
363
-    /**
364
-     * Checks whether current connection may be reused or should be closed
365
-     *
366
-     * @param boolean                $requestKeepAlive whether connection could
367
-     *                               be persistent in the first place
368
-     * @param HTTP_Request2_Response $response         response object to check
369
-     *
370
-     * @return   boolean
371
-     */
372
-    protected function canKeepAlive($requestKeepAlive, HTTP_Request2_Response $response)
373
-    {
374
-        // Do not close socket on successful CONNECT request
375
-        if (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()
376
-            && 200 <= $response->getStatus() && 300 > $response->getStatus()
377
-        ) {
378
-            return true;
379
-        }
380
-
381
-        $lengthKnown = 'chunked' == strtolower($response->getHeader('transfer-encoding'))
382
-                       || null !== $response->getHeader('content-length')
383
-                       // no body possible for such responses, see also request #17031
384
-                       || HTTP_Request2::METHOD_HEAD == $this->request->getMethod()
385
-                       || in_array($response->getStatus(), array(204, 304));
386
-        $persistent  = 'keep-alive' == strtolower($response->getHeader('connection')) ||
387
-                       (null === $response->getHeader('connection') &&
388
-                        '1.1' == $response->getVersion());
389
-        return $requestKeepAlive && $lengthKnown && $persistent;
390
-    }
391
-
392
-    /**
393
-     * Disconnects from the remote server
394
-     */
395
-    protected function disconnect()
396
-    {
397
-        if (!empty($this->socket)) {
398
-            $this->socket = null;
399
-            $this->request->setLastEvent('disconnect');
400
-        }
401
-    }
402
-
403
-    /**
404
-     * Handles HTTP redirection
405
-     *
406
-     * This method will throw an Exception if redirect to a non-HTTP(S) location
407
-     * is attempted, also if number of redirects performed already is equal to
408
-     * 'max_redirects' configuration parameter.
409
-     *
410
-     * @param HTTP_Request2          $request  Original request
411
-     * @param HTTP_Request2_Response $response Response containing redirect
412
-     *
413
-     * @return   HTTP_Request2_Response      Response from a new location
414
-     * @throws   HTTP_Request2_Exception
415
-     */
416
-    protected function handleRedirect(
417
-        HTTP_Request2 $request, HTTP_Request2_Response $response
418
-    ) {
419
-        if (is_null($this->redirectCountdown)) {
420
-            $this->redirectCountdown = $request->getConfig('max_redirects');
421
-        }
422
-        if (0 == $this->redirectCountdown) {
423
-            $this->redirectCountdown = null;
424
-            // Copying cURL behaviour
425
-            throw new HTTP_Request2_MessageException(
426
-                'Maximum (' . $request->getConfig('max_redirects') . ') redirects followed',
427
-                HTTP_Request2_Exception::TOO_MANY_REDIRECTS
428
-            );
429
-        }
430
-        $redirectUrl = new Net_URL2(
431
-            $response->getHeader('location'),
432
-            array(Net_URL2::OPTION_USE_BRACKETS => $request->getConfig('use_brackets'))
433
-        );
434
-        // refuse non-HTTP redirect
435
-        if ($redirectUrl->isAbsolute()
436
-            && !in_array($redirectUrl->getScheme(), array('http', 'https'))
437
-        ) {
438
-            $this->redirectCountdown = null;
439
-            throw new HTTP_Request2_MessageException(
440
-                'Refusing to redirect to a non-HTTP URL ' . $redirectUrl->__toString(),
441
-                HTTP_Request2_Exception::NON_HTTP_REDIRECT
442
-            );
443
-        }
444
-        // Theoretically URL should be absolute (see http://tools.ietf.org/html/rfc2616#section-14.30),
445
-        // but in practice it is often not
446
-        if (!$redirectUrl->isAbsolute()) {
447
-            $redirectUrl = $request->getUrl()->resolve($redirectUrl);
448
-        }
449
-        $redirect = clone $request;
450
-        $redirect->setUrl($redirectUrl);
451
-        if (303 == $response->getStatus()
452
-            || (!$request->getConfig('strict_redirects')
453
-                && in_array($response->getStatus(), array(301, 302)))
454
-        ) {
455
-            $redirect->setMethod(HTTP_Request2::METHOD_GET);
456
-            $redirect->setBody('');
457
-        }
458
-
459
-        if (0 < $this->redirectCountdown) {
460
-            $this->redirectCountdown--;
461
-        }
462
-        return $this->sendRequest($redirect);
463
-    }
464
-
465
-    /**
466
-     * Checks whether another request should be performed with server digest auth
467
-     *
468
-     * Several conditions should be satisfied for it to return true:
469
-     *   - response status should be 401
470
-     *   - auth credentials should be set in the request object
471
-     *   - response should contain WWW-Authenticate header with digest challenge
472
-     *   - there is either no challenge stored for this URL or new challenge
473
-     *     contains stale=true parameter (in other case we probably just failed
474
-     *     due to invalid username / password)
475
-     *
476
-     * The method stores challenge values in $challenges static property
477
-     *
478
-     * @param HTTP_Request2_Response $response response to check
479
-     *
480
-     * @return   boolean whether another request should be performed
481
-     * @throws   HTTP_Request2_Exception in case of unsupported challenge parameters
482
-     */
483
-    protected function shouldUseServerDigestAuth(HTTP_Request2_Response $response)
484
-    {
485
-        // no sense repeating a request if we don't have credentials
486
-        if (401 != $response->getStatus() || !$this->request->getAuth()) {
487
-            return false;
488
-        }
489
-        if (!$challenge = $this->parseDigestChallenge($response->getHeader('www-authenticate'))) {
490
-            return false;
491
-        }
492
-
493
-        $url    = $this->request->getUrl();
494
-        $scheme = $url->getScheme();
495
-        $host   = $scheme . '://' . $url->getHost();
496
-        if ($port = $url->getPort()) {
497
-            if ((0 == strcasecmp($scheme, 'http') && 80 != $port)
498
-                || (0 == strcasecmp($scheme, 'https') && 443 != $port)
499
-            ) {
500
-                $host .= ':' . $port;
501
-            }
502
-        }
503
-
504
-        if (!empty($challenge['domain'])) {
505
-            $prefixes = array();
506
-            foreach (preg_split('/\\s+/', $challenge['domain']) as $prefix) {
507
-                // don't bother with different servers
508
-                if ('/' == substr($prefix, 0, 1)) {
509
-                    $prefixes[] = $host . $prefix;
510
-                }
511
-            }
512
-        }
513
-        if (empty($prefixes)) {
514
-            $prefixes = array($host . '/');
515
-        }
516
-
517
-        $ret = true;
518
-        foreach ($prefixes as $prefix) {
519
-            if (!empty(self::$challenges[$prefix])
520
-                && (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
521
-            ) {
522
-                // probably credentials are invalid
523
-                $ret = false;
524
-            }
525
-            self::$challenges[$prefix] =& $challenge;
526
-        }
527
-        return $ret;
528
-    }
529
-
530
-    /**
531
-     * Checks whether another request should be performed with proxy digest auth
532
-     *
533
-     * Several conditions should be satisfied for it to return true:
534
-     *   - response status should be 407
535
-     *   - proxy auth credentials should be set in the request object
536
-     *   - response should contain Proxy-Authenticate header with digest challenge
537
-     *   - there is either no challenge stored for this proxy or new challenge
538
-     *     contains stale=true parameter (in other case we probably just failed
539
-     *     due to invalid username / password)
540
-     *
541
-     * The method stores challenge values in $challenges static property
542
-     *
543
-     * @param HTTP_Request2_Response $response response to check
544
-     *
545
-     * @return   boolean whether another request should be performed
546
-     * @throws   HTTP_Request2_Exception in case of unsupported challenge parameters
547
-     */
548
-    protected function shouldUseProxyDigestAuth(HTTP_Request2_Response $response)
549
-    {
550
-        if (407 != $response->getStatus() || !$this->request->getConfig('proxy_user')) {
551
-            return false;
552
-        }
553
-        if (!($challenge = $this->parseDigestChallenge($response->getHeader('proxy-authenticate')))) {
554
-            return false;
555
-        }
556
-
557
-        $key = 'proxy://' . $this->request->getConfig('proxy_host') .
558
-               ':' . $this->request->getConfig('proxy_port');
559
-
560
-        if (!empty(self::$challenges[$key])
561
-            && (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
562
-        ) {
563
-            $ret = false;
564
-        } else {
565
-            $ret = true;
566
-        }
567
-        self::$challenges[$key] = $challenge;
568
-        return $ret;
569
-    }
570
-
571
-    /**
572
-     * Extracts digest method challenge from (WWW|Proxy)-Authenticate header value
573
-     *
574
-     * There is a problem with implementation of RFC 2617: several of the parameters
575
-     * are defined as quoted-string there and thus may contain backslash escaped
576
-     * double quotes (RFC 2616, section 2.2). However, RFC 2617 defines unq(X) as
577
-     * just value of quoted-string X without surrounding quotes, it doesn't speak
578
-     * about removing backslash escaping.
579
-     *
580
-     * Now realm parameter is user-defined and human-readable, strange things
581
-     * happen when it contains quotes:
582
-     *   - Apache allows quotes in realm, but apparently uses realm value without
583
-     *     backslashes for digest computation
584
-     *   - Squid allows (manually escaped) quotes there, but it is impossible to
585
-     *     authorize with either escaped or unescaped quotes used in digest,
586
-     *     probably it can't parse the response (?)
587
-     *   - Both IE and Firefox display realm value with backslashes in
588
-     *     the password popup and apparently use the same value for digest
589
-     *
590
-     * HTTP_Request2 follows IE and Firefox (and hopefully RFC 2617) in
591
-     * quoted-string handling, unfortunately that means failure to authorize
592
-     * sometimes
593
-     *
594
-     * @param string $headerValue value of WWW-Authenticate or Proxy-Authenticate header
595
-     *
596
-     * @return   mixed   associative array with challenge parameters, false if
597
-     *                   no challenge is present in header value
598
-     * @throws   HTTP_Request2_NotImplementedException in case of unsupported challenge parameters
599
-     */
600
-    protected function parseDigestChallenge($headerValue)
601
-    {
602
-        $authParam   = '(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
603
-                       self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')';
604
-        $challenge   = "!(?<=^|\\s|,)Digest ({$authParam}\\s*(,\\s*|$))+!";
605
-        if (!preg_match($challenge, $headerValue, $matches)) {
606
-            return false;
607
-        }
608
-
609
-        preg_match_all('!' . $authParam . '!', $matches[0], $params);
610
-        $paramsAry   = array();
611
-        $knownParams = array('realm', 'domain', 'nonce', 'opaque', 'stale',
612
-                             'algorithm', 'qop');
613
-        for ($i = 0; $i < count($params[0]); $i++) {
614
-            // section 3.2.1: Any unrecognized directive MUST be ignored.
615
-            if (in_array($params[1][$i], $knownParams)) {
616
-                if ('"' == substr($params[2][$i], 0, 1)) {
617
-                    $paramsAry[$params[1][$i]] = substr($params[2][$i], 1, -1);
618
-                } else {
619
-                    $paramsAry[$params[1][$i]] = $params[2][$i];
620
-                }
621
-            }
622
-        }
623
-        // we only support qop=auth
624
-        if (!empty($paramsAry['qop'])
625
-            && !in_array('auth', array_map('trim', explode(',', $paramsAry['qop'])))
626
-        ) {
627
-            throw new HTTP_Request2_NotImplementedException(
628
-                "Only 'auth' qop is currently supported in digest authentication, " .
629
-                "server requested '{$paramsAry['qop']}'"
630
-            );
631
-        }
632
-        // we only support algorithm=MD5
633
-        if (!empty($paramsAry['algorithm']) && 'MD5' != $paramsAry['algorithm']) {
634
-            throw new HTTP_Request2_NotImplementedException(
635
-                "Only 'MD5' algorithm is currently supported in digest authentication, " .
636
-                "server requested '{$paramsAry['algorithm']}'"
637
-            );
638
-        }
639
-
640
-        return $paramsAry;
641
-    }
642
-
643
-    /**
644
-     * Parses [Proxy-]Authentication-Info header value and updates challenge
645
-     *
646
-     * @param array  &$challenge  challenge to update
647
-     * @param string $headerValue value of [Proxy-]Authentication-Info header
648
-     *
649
-     * @todo     validate server rspauth response
650
-     */
651
-    protected function updateChallenge(&$challenge, $headerValue)
652
-    {
653
-        $authParam   = '!(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
654
-                       self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')!';
655
-        $paramsAry   = array();
656
-
657
-        preg_match_all($authParam, $headerValue, $params);
658
-        for ($i = 0; $i < count($params[0]); $i++) {
659
-            if ('"' == substr($params[2][$i], 0, 1)) {
660
-                $paramsAry[$params[1][$i]] = substr($params[2][$i], 1, -1);
661
-            } else {
662
-                $paramsAry[$params[1][$i]] = $params[2][$i];
663
-            }
664
-        }
665
-        // for now, just update the nonce value
666
-        if (!empty($paramsAry['nextnonce'])) {
667
-            $challenge['nonce'] = $paramsAry['nextnonce'];
668
-            $challenge['nc']    = 1;
669
-        }
670
-    }
671
-
672
-    /**
673
-     * Creates a value for [Proxy-]Authorization header when using digest authentication
674
-     *
675
-     * @param string $user       user name
676
-     * @param string $password   password
677
-     * @param string $url        request URL
678
-     * @param array  &$challenge digest challenge parameters
679
-     *
680
-     * @return   string  value of [Proxy-]Authorization request header
681
-     * @link     http://tools.ietf.org/html/rfc2617#section-3.2.2
682
-     */
683
-    protected function createDigestResponse($user, $password, $url, &$challenge)
684
-    {
685
-        if (false !== ($q = strpos($url, '?'))
686
-            && $this->request->getConfig('digest_compat_ie')
687
-        ) {
688
-            $url = substr($url, 0, $q);
689
-        }
690
-
691
-        $a1 = md5($user . ':' . $challenge['realm'] . ':' . $password);
692
-        $a2 = md5($this->request->getMethod() . ':' . $url);
693
-
694
-        if (empty($challenge['qop'])) {
695
-            $digest = md5($a1 . ':' . $challenge['nonce'] . ':' . $a2);
696
-        } else {
697
-            $challenge['cnonce'] = 'Req2.' . rand();
698
-            if (empty($challenge['nc'])) {
699
-                $challenge['nc'] = 1;
700
-            }
701
-            $nc     = sprintf('%08x', $challenge['nc']++);
702
-            $digest = md5(
703
-                $a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' .
704
-                $challenge['cnonce'] . ':auth:' . $a2
705
-            );
706
-        }
707
-        return 'Digest username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $user) . '", ' .
708
-               'realm="' . $challenge['realm'] . '", ' .
709
-               'nonce="' . $challenge['nonce'] . '", ' .
710
-               'uri="' . $url . '", ' .
711
-               'response="' . $digest . '"' .
712
-               (!empty($challenge['opaque'])?
713
-                ', opaque="' . $challenge['opaque'] . '"':
714
-                '') .
715
-               (!empty($challenge['qop'])?
716
-                ', qop="auth", nc=' . $nc . ', cnonce="' . $challenge['cnonce'] . '"':
717
-                '');
718
-    }
719
-
720
-    /**
721
-     * Adds 'Authorization' header (if needed) to request headers array
722
-     *
723
-     * @param array  &$headers    request headers
724
-     * @param string $requestHost request host (needed for digest authentication)
725
-     * @param string $requestUrl  request URL (needed for digest authentication)
726
-     *
727
-     * @throws   HTTP_Request2_NotImplementedException
728
-     */
729
-    protected function addAuthorizationHeader(&$headers, $requestHost, $requestUrl)
730
-    {
731
-        if (!($auth = $this->request->getAuth())) {
732
-            return;
733
-        }
734
-        switch ($auth['scheme']) {
735
-        case HTTP_Request2::AUTH_BASIC:
736
-            $headers['authorization'] = 'Basic ' . base64_encode(
737
-                $auth['user'] . ':' . $auth['password']
738
-            );
739
-            break;
740
-
741
-        case HTTP_Request2::AUTH_DIGEST:
742
-            unset($this->serverChallenge);
743
-            $fullUrl = ('/' == $requestUrl[0])?
744
-                       $this->request->getUrl()->getScheme() . '://' .
745
-                        $requestHost . $requestUrl:
746
-                       $requestUrl;
747
-            foreach (array_keys(self::$challenges) as $key) {
748
-                if ($key == substr($fullUrl, 0, strlen($key))) {
749
-                    $headers['authorization'] = $this->createDigestResponse(
750
-                        $auth['user'], $auth['password'],
751
-                        $requestUrl, self::$challenges[$key]
752
-                    );
753
-                    $this->serverChallenge =& self::$challenges[$key];
754
-                    break;
755
-                }
756
-            }
757
-            break;
758
-
759
-        default:
760
-            throw new HTTP_Request2_NotImplementedException(
761
-                "Unknown HTTP authentication scheme '{$auth['scheme']}'"
762
-            );
763
-        }
764
-    }
765
-
766
-    /**
767
-     * Adds 'Proxy-Authorization' header (if needed) to request headers array
768
-     *
769
-     * @param array  &$headers   request headers
770
-     * @param string $requestUrl request URL (needed for digest authentication)
771
-     *
772
-     * @throws   HTTP_Request2_NotImplementedException
773
-     */
774
-    protected function addProxyAuthorizationHeader(&$headers, $requestUrl)
775
-    {
776
-        if (!$this->request->getConfig('proxy_host')
777
-            || !($user = $this->request->getConfig('proxy_user'))
778
-            || (0 == strcasecmp('https', $this->request->getUrl()->getScheme())
779
-                && HTTP_Request2::METHOD_CONNECT != $this->request->getMethod())
780
-        ) {
781
-            return;
782
-        }
783
-
784
-        $password = $this->request->getConfig('proxy_password');
785
-        switch ($this->request->getConfig('proxy_auth_scheme')) {
786
-        case HTTP_Request2::AUTH_BASIC:
787
-            $headers['proxy-authorization'] = 'Basic ' . base64_encode(
788
-                $user . ':' . $password
789
-            );
790
-            break;
791
-
792
-        case HTTP_Request2::AUTH_DIGEST:
793
-            unset($this->proxyChallenge);
794
-            $proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') .
795
-                        ':' . $this->request->getConfig('proxy_port');
796
-            if (!empty(self::$challenges[$proxyUrl])) {
797
-                $headers['proxy-authorization'] = $this->createDigestResponse(
798
-                    $user, $password,
799
-                    $requestUrl, self::$challenges[$proxyUrl]
800
-                );
801
-                $this->proxyChallenge =& self::$challenges[$proxyUrl];
802
-            }
803
-            break;
804
-
805
-        default:
806
-            throw new HTTP_Request2_NotImplementedException(
807
-                "Unknown HTTP authentication scheme '" .
808
-                $this->request->getConfig('proxy_auth_scheme') . "'"
809
-            );
810
-        }
811
-    }
812
-
813
-
814
-    /**
815
-     * Creates the string with the Request-Line and request headers
816
-     *
817
-     * @return   string
818
-     * @throws   HTTP_Request2_Exception
819
-     */
820
-    protected function prepareHeaders()
821
-    {
822
-        $headers = $this->request->getHeaders();
823
-        $url     = $this->request->getUrl();
824
-        $connect = HTTP_Request2::METHOD_CONNECT == $this->request->getMethod();
825
-        $host    = $url->getHost();
826
-
827
-        $defaultPort = 0 == strcasecmp($url->getScheme(), 'https')? 443: 80;
828
-        if (($port = $url->getPort()) && $port != $defaultPort || $connect) {
829
-            $host .= ':' . (empty($port)? $defaultPort: $port);
830
-        }
831
-        // Do not overwrite explicitly set 'Host' header, see bug #16146
832
-        if (!isset($headers['host'])) {
833
-            $headers['host'] = $host;
834
-        }
835
-
836
-        if ($connect) {
837
-            $requestUrl = $host;
838
-
839
-        } else {
840
-            if (!$this->request->getConfig('proxy_host')
841
-                || 'http' != $this->request->getConfig('proxy_type')
842
-                || 0 == strcasecmp($url->getScheme(), 'https')
843
-            ) {
844
-                $requestUrl = '';
845
-            } else {
846
-                $requestUrl = $url->getScheme() . '://' . $host;
847
-            }
848
-            $path        = $url->getPath();
849
-            $query       = $url->getQuery();
850
-            $requestUrl .= (empty($path)? '/': $path) . (empty($query)? '': '?' . $query);
851
-        }
852
-
853
-        if ('1.1' == $this->request->getConfig('protocol_version')
854
-            && extension_loaded('zlib') && !isset($headers['accept-encoding'])
855
-        ) {
856
-            $headers['accept-encoding'] = 'gzip, deflate';
857
-        }
858
-        if (($jar = $this->request->getCookieJar())
859
-            && ($cookies = $jar->getMatching($this->request->getUrl(), true))
860
-        ) {
861
-            $headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
862
-        }
863
-
864
-        $this->addAuthorizationHeader($headers, $host, $requestUrl);
865
-        $this->addProxyAuthorizationHeader($headers, $requestUrl);
866
-        $this->calculateRequestLength($headers);
867
-        if ('1.1' == $this->request->getConfig('protocol_version')) {
868
-            $this->updateExpectHeader($headers);
869
-        } else {
870
-            $this->expect100Continue = false;
871
-        }
872
-
873
-        $headersStr = $this->request->getMethod() . ' ' . $requestUrl . ' HTTP/' .
874
-                      $this->request->getConfig('protocol_version') . "\r\n";
875
-        foreach ($headers as $name => $value) {
876
-            $canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
877
-            $headersStr   .= $canonicalName . ': ' . $value . "\r\n";
878
-        }
879
-        return $headersStr . "\r\n";
880
-    }
881
-
882
-    /**
883
-     * Adds or removes 'Expect: 100-continue' header from request headers
884
-     *
885
-     * Also sets the $expect100Continue property. Parsing of existing header
886
-     * is somewhat needed due to its complex structure and due to the
887
-     * requirement in section 8.2.3 of RFC 2616:
888
-     * > A client MUST NOT send an Expect request-header field (section
889
-     * > 14.20) with the "100-continue" expectation if it does not intend
890
-     * > to send a request body.
891
-     *
892
-     * @param array &$headers Array of headers prepared for the request
893
-     *
894
-     * @throws HTTP_Request2_LogicException
895
-     * @link http://pear.php.net/bugs/bug.php?id=19233
896
-     * @link http://tools.ietf.org/html/rfc2616#section-8.2.3
897
-     */
898
-    protected function updateExpectHeader(&$headers)
899
-    {
900
-        $this->expect100Continue = false;
901
-        $expectations = array();
902
-        if (isset($headers['expect'])) {
903
-            if ('' === $headers['expect']) {
904
-                // empty 'Expect' header is technically invalid, so just get rid of it
905
-                unset($headers['expect']);
906
-                return;
907
-            }
908
-            // build regexp to parse the value of existing Expect header
909
-            $expectParam     = ';\s*' . self::REGEXP_TOKEN . '(?:\s*=\s*(?:'
910
-                               . self::REGEXP_TOKEN . '|'
911
-                               . self::REGEXP_QUOTED_STRING . '))?\s*';
912
-            $expectExtension = self::REGEXP_TOKEN . '(?:\s*=\s*(?:'
913
-                               . self::REGEXP_TOKEN . '|'
914
-                               . self::REGEXP_QUOTED_STRING . ')\s*(?:'
915
-                               . $expectParam . ')*)?';
916
-            $expectItem      = '!(100-continue|' . $expectExtension . ')!A';
917
-
918
-            $pos    = 0;
919
-            $length = strlen($headers['expect']);
920
-
921
-            while ($pos < $length) {
922
-                $pos += strspn($headers['expect'], " \t", $pos);
923
-                if (',' === substr($headers['expect'], $pos, 1)) {
924
-                    $pos++;
925
-                    continue;
926
-
927
-                } elseif (!preg_match($expectItem, $headers['expect'], $m, 0, $pos)) {
928
-                    throw new HTTP_Request2_LogicException(
929
-                        "Cannot parse value '{$headers['expect']}' of Expect header",
930
-                        HTTP_Request2_Exception::INVALID_ARGUMENT
931
-                    );
932
-
933
-                } else {
934
-                    $pos += strlen($m[0]);
935
-                    if (strcasecmp('100-continue', $m[0])) {
936
-                        $expectations[]  = $m[0];
937
-                    }
938
-                }
939
-            }
940
-        }
941
-
942
-        if (1024 < $this->contentLength) {
943
-            $expectations[] = '100-continue';
944
-            $this->expect100Continue = true;
945
-        }
946
-
947
-        if (empty($expectations)) {
948
-            unset($headers['expect']);
949
-        } else {
950
-            $headers['expect'] = implode(',', $expectations);
951
-        }
952
-    }
953
-
954
-    /**
955
-     * Sends the request body
956
-     *
957
-     * @throws   HTTP_Request2_MessageException
958
-     */
959
-    protected function writeBody()
960
-    {
961
-        if (in_array($this->request->getMethod(), self::$bodyDisallowed)
962
-            || 0 == $this->contentLength
963
-        ) {
964
-            return;
965
-        }
966
-
967
-        $position   = 0;
968
-        $bufferSize = $this->request->getConfig('buffer_size');
969
-        $headers    = $this->request->getHeaders();
970
-        $chunked    = isset($headers['transfer-encoding']);
971
-        while ($position < $this->contentLength) {
972
-            if (is_string($this->requestBody)) {
973
-                $str = substr($this->requestBody, $position, $bufferSize);
974
-            } elseif (is_resource($this->requestBody)) {
975
-                $str = fread($this->requestBody, $bufferSize);
976
-            } else {
977
-                $str = $this->requestBody->read($bufferSize);
978
-            }
979
-            if (!$chunked) {
980
-                $this->socket->write($str);
981
-            } else {
982
-                $this->socket->write(dechex(strlen($str)) . "\r\n{$str}\r\n");
983
-            }
984
-            // Provide the length of written string to the observer, request #7630
985
-            $this->request->setLastEvent('sentBodyPart', strlen($str));
986
-            $position += strlen($str);
987
-        }
988
-
989
-        // write zero-length chunk
990
-        if ($chunked) {
991
-            $this->socket->write("0\r\n\r\n");
992
-        }
993
-        $this->request->setLastEvent('sentBody', $this->contentLength);
994
-    }
995
-
996
-    /**
997
-     * Reads the remote server's response
998
-     *
999
-     * @return   HTTP_Request2_Response
1000
-     * @throws   HTTP_Request2_Exception
1001
-     */
1002
-    protected function readResponse()
1003
-    {
1004
-        $bufferSize = $this->request->getConfig('buffer_size');
1005
-        // http://tools.ietf.org/html/rfc2616#section-8.2.3
1006
-        // ...the client SHOULD NOT wait for an indefinite period before sending the request body
1007
-        $timeout    = $this->expect100Continue ? 1 : null;
1008
-
1009
-        do {
1010
-            try {
1011
-                $response = new HTTP_Request2_Response(
1012
-                    $this->socket->readLine($bufferSize, $timeout), true, $this->request->getUrl()
1013
-                );
1014
-                do {
1015
-                    $headerLine = $this->socket->readLine($bufferSize);
1016
-                    $response->parseHeaderLine($headerLine);
1017
-                } while ('' != $headerLine);
1018
-
1019
-            } catch (HTTP_Request2_MessageException $e) {
1020
-                if (HTTP_Request2_Exception::TIMEOUT === $e->getCode()
1021
-                    && $this->expect100Continue
1022
-                ) {
1023
-                    return null;
1024
-                }
1025
-                throw $e;
1026
-            }
1027
-            if ($this->expect100Continue && 100 == $response->getStatus()) {
1028
-                return $response;
1029
-            }
1030
-        } while (in_array($response->getStatus(), array(100, 101)));
1031
-
1032
-        $this->request->setLastEvent('receivedHeaders', $response);
1033
-
1034
-        // No body possible in such responses
1035
-        if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod()
1036
-            || (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()
1037
-                && 200 <= $response->getStatus() && 300 > $response->getStatus())
1038
-            || in_array($response->getStatus(), array(204, 304))
1039
-        ) {
1040
-            return $response;
1041
-        }
1042
-
1043
-        $chunked = 'chunked' == $response->getHeader('transfer-encoding');
1044
-        $length  = $response->getHeader('content-length');
1045
-        $hasBody = false;
1046
-        if ($chunked || null === $length || 0 < intval($length)) {
1047
-            // RFC 2616, section 4.4:
1048
-            // 3. ... If a message is received with both a
1049
-            // Transfer-Encoding header field and a Content-Length header field,
1050
-            // the latter MUST be ignored.
1051
-            $toRead = ($chunked || null === $length)? null: $length;
1052
-            $this->chunkLength = 0;
1053
-
1054
-            while (!$this->socket->eof() && (is_null($toRead) || 0 < $toRead)) {
1055
-                if ($chunked) {
1056
-                    $data = $this->readChunked($bufferSize);
1057
-                } elseif (is_null($toRead)) {
1058
-                    $data = $this->socket->read($bufferSize);
1059
-                } else {
1060
-                    $data    = $this->socket->read(min($toRead, $bufferSize));
1061
-                    $toRead -= strlen($data);
1062
-                }
1063
-                if ('' == $data && (!$this->chunkLength || $this->socket->eof())) {
1064
-                    break;
1065
-                }
1066
-
1067
-                $hasBody = true;
1068
-                if ($this->request->getConfig('store_body')) {
1069
-                    $response->appendBody($data);
1070
-                }
1071
-                if (!in_array($response->getHeader('content-encoding'), array('identity', null))) {
1072
-                    $this->request->setLastEvent('receivedEncodedBodyPart', $data);
1073
-                } else {
1074
-                    $this->request->setLastEvent('receivedBodyPart', $data);
1075
-                }
1076
-            }
1077
-        }
1078
-
1079
-        if ($hasBody) {
1080
-            $this->request->setLastEvent('receivedBody', $response);
1081
-        }
1082
-        return $response;
1083
-    }
1084
-
1085
-    /**
1086
-     * Reads a part of response body encoded with chunked Transfer-Encoding
1087
-     *
1088
-     * @param int $bufferSize buffer size to use for reading
1089
-     *
1090
-     * @return   string
1091
-     * @throws   HTTP_Request2_MessageException
1092
-     */
1093
-    protected function readChunked($bufferSize)
1094
-    {
1095
-        // at start of the next chunk?
1096
-        if (0 == $this->chunkLength) {
1097
-            $line = $this->socket->readLine($bufferSize);
1098
-            if (!preg_match('/^([0-9a-f]+)/i', $line, $matches)) {
1099
-                throw new HTTP_Request2_MessageException(
1100
-                    "Cannot decode chunked response, invalid chunk length '{$line}'",
1101
-                    HTTP_Request2_Exception::DECODE_ERROR
1102
-                );
1103
-            } else {
1104
-                $this->chunkLength = hexdec($matches[1]);
1105
-                // Chunk with zero length indicates the end
1106
-                if (0 == $this->chunkLength) {
1107
-                    $this->socket->readLine($bufferSize);
1108
-                    return '';
1109
-                }
1110
-            }
1111
-        }
1112
-        $data = $this->socket->read(min($this->chunkLength, $bufferSize));
1113
-        $this->chunkLength -= strlen($data);
1114
-        if (0 == $this->chunkLength) {
1115
-            $this->socket->readLine($bufferSize); // Trailing CRLF
1116
-        }
1117
-        return $data;
1118
-    }
42
+	/**
43
+	 * Regular expression for 'token' rule from RFC 2616
44
+	 */
45
+	const REGEXP_TOKEN = '[^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+';
46
+
47
+	/**
48
+	 * Regular expression for 'quoted-string' rule from RFC 2616
49
+	 */
50
+	const REGEXP_QUOTED_STRING = '"(?>[^"\\\\]+|\\\\.)*"';
51
+
52
+	/**
53
+	 * Connected sockets, needed for Keep-Alive support
54
+	 * @var  array
55
+	 * @see  connect()
56
+	 */
57
+	protected static $sockets = array();
58
+
59
+	/**
60
+	 * Data for digest authentication scheme
61
+	 *
62
+	 * The keys for the array are URL prefixes.
63
+	 *
64
+	 * The values are associative arrays with data (realm, nonce, nonce-count,
65
+	 * opaque...) needed for digest authentication. Stored here to prevent making
66
+	 * duplicate requests to digest-protected resources after we have already
67
+	 * received the challenge.
68
+	 *
69
+	 * @var  array
70
+	 */
71
+	protected static $challenges = array();
72
+
73
+	/**
74
+	 * Connected socket
75
+	 * @var  HTTP_Request2_SocketWrapper
76
+	 * @see  connect()
77
+	 */
78
+	protected $socket;
79
+
80
+	/**
81
+	 * Challenge used for server digest authentication
82
+	 * @var  array
83
+	 */
84
+	protected $serverChallenge;
85
+
86
+	/**
87
+	 * Challenge used for proxy digest authentication
88
+	 * @var  array
89
+	 */
90
+	protected $proxyChallenge;
91
+
92
+	/**
93
+	 * Remaining length of the current chunk, when reading chunked response
94
+	 * @var  integer
95
+	 * @see  readChunked()
96
+	 */
97
+	protected $chunkLength = 0;
98
+
99
+	/**
100
+	 * Remaining amount of redirections to follow
101
+	 *
102
+	 * Starts at 'max_redirects' configuration parameter and is reduced on each
103
+	 * subsequent redirect. An Exception will be thrown once it reaches zero.
104
+	 *
105
+	 * @var  integer
106
+	 */
107
+	protected $redirectCountdown = null;
108
+
109
+	/**
110
+	 * Whether to wait for "100 Continue" response before sending request body
111
+	 * @var bool
112
+	 */
113
+	protected $expect100Continue = false;
114
+
115
+	/**
116
+	 * Sends request to the remote server and returns its response
117
+	 *
118
+	 * @param HTTP_Request2 $request HTTP request message
119
+	 *
120
+	 * @return   HTTP_Request2_Response
121
+	 * @throws   HTTP_Request2_Exception
122
+	 */
123
+	public function sendRequest(HTTP_Request2 $request)
124
+	{
125
+		$this->request = $request;
126
+
127
+		try {
128
+			$keepAlive = $this->connect();
129
+			$headers   = $this->prepareHeaders();
130
+			$this->socket->write($headers);
131
+			// provide request headers to the observer, see request #7633
132
+			$this->request->setLastEvent('sentHeaders', $headers);
133
+
134
+			if (!$this->expect100Continue) {
135
+				$this->writeBody();
136
+				$response = $this->readResponse();
137
+
138
+			} else {
139
+				$response = $this->readResponse();
140
+				if (!$response || 100 == $response->getStatus()) {
141
+					$this->expect100Continue = false;
142
+					// either got "100 Continue" or timed out -> send body
143
+					$this->writeBody();
144
+					$response = $this->readResponse();
145
+				}
146
+			}
147
+
148
+
149
+			if ($jar = $request->getCookieJar()) {
150
+				$jar->addCookiesFromResponse($response, $request->getUrl());
151
+			}
152
+
153
+			if (!$this->canKeepAlive($keepAlive, $response)) {
154
+				$this->disconnect();
155
+			}
156
+
157
+			if ($this->shouldUseProxyDigestAuth($response)) {
158
+				return $this->sendRequest($request);
159
+			}
160
+			if ($this->shouldUseServerDigestAuth($response)) {
161
+				return $this->sendRequest($request);
162
+			}
163
+			if ($authInfo = $response->getHeader('authentication-info')) {
164
+				$this->updateChallenge($this->serverChallenge, $authInfo);
165
+			}
166
+			if ($proxyInfo = $response->getHeader('proxy-authentication-info')) {
167
+				$this->updateChallenge($this->proxyChallenge, $proxyInfo);
168
+			}
169
+
170
+		} catch (Exception $e) {
171
+			$this->disconnect();
172
+		}
173
+
174
+		unset($this->request, $this->requestBody);
175
+
176
+		if (!empty($e)) {
177
+			$this->redirectCountdown = null;
178
+			throw $e;
179
+		}
180
+
181
+		if (!$request->getConfig('follow_redirects') || !$response->isRedirect()) {
182
+			$this->redirectCountdown = null;
183
+			return $response;
184
+		} else {
185
+			return $this->handleRedirect($request, $response);
186
+		}
187
+	}
188
+
189
+	/**
190
+	 * Connects to the remote server
191
+	 *
192
+	 * @return   bool    whether the connection can be persistent
193
+	 * @throws   HTTP_Request2_Exception
194
+	 */
195
+	protected function connect()
196
+	{
197
+		$secure  = 0 == strcasecmp($this->request->getUrl()->getScheme(), 'https');
198
+		$tunnel  = HTTP_Request2::METHOD_CONNECT == $this->request->getMethod();
199
+		$headers = $this->request->getHeaders();
200
+		$reqHost = $this->request->getUrl()->getHost();
201
+		if (!($reqPort = $this->request->getUrl()->getPort())) {
202
+			$reqPort = $secure? 443: 80;
203
+		}
204
+
205
+		$httpProxy = $socksProxy = false;
206
+		if (!($host = $this->request->getConfig('proxy_host'))) {
207
+			$host = $reqHost;
208
+			$port = $reqPort;
209
+		} else {
210
+			if (!($port = $this->request->getConfig('proxy_port'))) {
211
+				throw new HTTP_Request2_LogicException(
212
+					'Proxy port not provided',
213
+					HTTP_Request2_Exception::MISSING_VALUE
214
+				);
215
+			}
216
+			if ('http' == ($type = $this->request->getConfig('proxy_type'))) {
217
+				$httpProxy = true;
218
+			} elseif ('socks5' == $type) {
219
+				$socksProxy = true;
220
+			} else {
221
+				throw new HTTP_Request2_NotImplementedException(
222
+					"Proxy type '{$type}' is not supported"
223
+				);
224
+			}
225
+		}
226
+
227
+		if ($tunnel && !$httpProxy) {
228
+			throw new HTTP_Request2_LogicException(
229
+				"Trying to perform CONNECT request without proxy",
230
+				HTTP_Request2_Exception::MISSING_VALUE
231
+			);
232
+		}
233
+		if ($secure && !in_array('ssl', stream_get_transports())) {
234
+			throw new HTTP_Request2_LogicException(
235
+				'Need OpenSSL support for https:// requests',
236
+				HTTP_Request2_Exception::MISCONFIGURATION
237
+			);
238
+		}
239
+
240
+		// RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
241
+		// connection token to a proxy server...
242
+		if ($httpProxy && !$secure && !empty($headers['connection'])
243
+			&& 'Keep-Alive' == $headers['connection']
244
+		) {
245
+			$this->request->setHeader('connection');
246
+		}
247
+
248
+		$keepAlive = ('1.1' == $this->request->getConfig('protocol_version') &&
249
+					  empty($headers['connection'])) ||
250
+					 (!empty($headers['connection']) &&
251
+					  'Keep-Alive' == $headers['connection']);
252
+
253
+		$options = array();
254
+		if ($ip = $this->request->getConfig('local_ip')) {
255
+			$options['socket'] = array(
256
+				'bindto' => (false === strpos($ip, ':') ? $ip : '[' . $ip . ']') . ':0'
257
+			);
258
+		}
259
+		if ($secure || $tunnel) {
260
+			$options['ssl'] = array();
261
+			foreach ($this->request->getConfig() as $name => $value) {
262
+				if ('ssl_' == substr($name, 0, 4) && null !== $value) {
263
+					if ('ssl_verify_host' == $name) {
264
+						if ($value) {
265
+							$options['ssl']['CN_match'] = $reqHost;
266
+						}
267
+					} else {
268
+						$options['ssl'][substr($name, 4)] = $value;
269
+					}
270
+				}
271
+			}
272
+			ksort($options['ssl']);
273
+		}
274
+
275
+		// Use global request timeout if given, see feature requests #5735, #8964
276
+		if ($timeout = $this->request->getConfig('timeout')) {
277
+			$deadline = time() + $timeout;
278
+		} else {
279
+			$deadline = null;
280
+		}
281
+
282
+		// Changing SSL context options after connection is established does *not*
283
+		// work, we need a new connection if options change
284
+		$remote    = ((!$secure || $httpProxy || $socksProxy)? 'tcp://': 'ssl://')
285
+					 . $host . ':' . $port;
286
+		$socketKey = $remote . (
287
+						($secure && $httpProxy || $socksProxy)
288
+						? "->{$reqHost}:{$reqPort}" : ''
289
+					 ) . (empty($options)? '': ':' . serialize($options));
290
+		unset($this->socket);
291
+
292
+		// We use persistent connections and have a connected socket?
293
+		// Ensure that the socket is still connected, see bug #16149
294
+		if ($keepAlive && !empty(self::$sockets[$socketKey])
295
+			&& !self::$sockets[$socketKey]->eof()
296
+		) {
297
+			$this->socket =& self::$sockets[$socketKey];
298
+
299
+		} else {
300
+			if ($socksProxy) {
301
+				require_once 'HTTP/Request2/SOCKS5.php';
302
+
303
+				$this->socket = new HTTP_Request2_SOCKS5(
304
+					$remote, $this->request->getConfig('connect_timeout'),
305
+					$options, $this->request->getConfig('proxy_user'),
306
+					$this->request->getConfig('proxy_password')
307
+				);
308
+				// handle request timeouts ASAP
309
+				$this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));
310
+				$this->socket->connect($reqHost, $reqPort);
311
+				if (!$secure) {
312
+					$conninfo = "tcp://{$reqHost}:{$reqPort} via {$remote}";
313
+				} else {
314
+					$this->socket->enableCrypto();
315
+					$conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";
316
+				}
317
+
318
+			} elseif ($secure && $httpProxy && !$tunnel) {
319
+				$this->establishTunnel();
320
+				$conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";
321
+
322
+			} else {
323
+				$this->socket = new HTTP_Request2_SocketWrapper(
324
+					$remote, $this->request->getConfig('connect_timeout'), $options
325
+				);
326
+			}
327
+			$this->request->setLastEvent('connect', empty($conninfo)? $remote: $conninfo);
328
+			self::$sockets[$socketKey] =& $this->socket;
329
+		}
330
+		$this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));
331
+		return $keepAlive;
332
+	}
333
+
334
+	/**
335
+	 * Establishes a tunnel to a secure remote server via HTTP CONNECT request
336
+	 *
337
+	 * This method will fail if 'ssl_verify_peer' is enabled. Probably because PHP
338
+	 * sees that we are connected to a proxy server (duh!) rather than the server
339
+	 * that presents its certificate.
340
+	 *
341
+	 * @link     http://tools.ietf.org/html/rfc2817#section-5.2
342
+	 * @throws   HTTP_Request2_Exception
343
+	 */
344
+	protected function establishTunnel()
345
+	{
346
+		$donor   = new self;
347
+		$connect = new HTTP_Request2(
348
+			$this->request->getUrl(), HTTP_Request2::METHOD_CONNECT,
349
+			array_merge($this->request->getConfig(), array('adapter' => $donor))
350
+		);
351
+		$response = $connect->send();
352
+		// Need any successful (2XX) response
353
+		if (200 > $response->getStatus() || 300 <= $response->getStatus()) {
354
+			throw new HTTP_Request2_ConnectionException(
355
+				'Failed to connect via HTTPS proxy. Proxy response: ' .
356
+				$response->getStatus() . ' ' . $response->getReasonPhrase()
357
+			);
358
+		}
359
+		$this->socket = $donor->socket;
360
+		$this->socket->enableCrypto();
361
+	}
362
+
363
+	/**
364
+	 * Checks whether current connection may be reused or should be closed
365
+	 *
366
+	 * @param boolean                $requestKeepAlive whether connection could
367
+	 *                               be persistent in the first place
368
+	 * @param HTTP_Request2_Response $response         response object to check
369
+	 *
370
+	 * @return   boolean
371
+	 */
372
+	protected function canKeepAlive($requestKeepAlive, HTTP_Request2_Response $response)
373
+	{
374
+		// Do not close socket on successful CONNECT request
375
+		if (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()
376
+			&& 200 <= $response->getStatus() && 300 > $response->getStatus()
377
+		) {
378
+			return true;
379
+		}
380
+
381
+		$lengthKnown = 'chunked' == strtolower($response->getHeader('transfer-encoding'))
382
+					   || null !== $response->getHeader('content-length')
383
+					   // no body possible for such responses, see also request #17031
384
+					   || HTTP_Request2::METHOD_HEAD == $this->request->getMethod()
385
+					   || in_array($response->getStatus(), array(204, 304));
386
+		$persistent  = 'keep-alive' == strtolower($response->getHeader('connection')) ||
387
+					   (null === $response->getHeader('connection') &&
388
+						'1.1' == $response->getVersion());
389
+		return $requestKeepAlive && $lengthKnown && $persistent;
390
+	}
391
+
392
+	/**
393
+	 * Disconnects from the remote server
394
+	 */
395
+	protected function disconnect()
396
+	{
397
+		if (!empty($this->socket)) {
398
+			$this->socket = null;
399
+			$this->request->setLastEvent('disconnect');
400
+		}
401
+	}
402
+
403
+	/**
404
+	 * Handles HTTP redirection
405
+	 *
406
+	 * This method will throw an Exception if redirect to a non-HTTP(S) location
407
+	 * is attempted, also if number of redirects performed already is equal to
408
+	 * 'max_redirects' configuration parameter.
409
+	 *
410
+	 * @param HTTP_Request2          $request  Original request
411
+	 * @param HTTP_Request2_Response $response Response containing redirect
412
+	 *
413
+	 * @return   HTTP_Request2_Response      Response from a new location
414
+	 * @throws   HTTP_Request2_Exception
415
+	 */
416
+	protected function handleRedirect(
417
+		HTTP_Request2 $request, HTTP_Request2_Response $response
418
+	) {
419
+		if (is_null($this->redirectCountdown)) {
420
+			$this->redirectCountdown = $request->getConfig('max_redirects');
421
+		}
422
+		if (0 == $this->redirectCountdown) {
423
+			$this->redirectCountdown = null;
424
+			// Copying cURL behaviour
425
+			throw new HTTP_Request2_MessageException(
426
+				'Maximum (' . $request->getConfig('max_redirects') . ') redirects followed',
427
+				HTTP_Request2_Exception::TOO_MANY_REDIRECTS
428
+			);
429
+		}
430
+		$redirectUrl = new Net_URL2(
431
+			$response->getHeader('location'),
432
+			array(Net_URL2::OPTION_USE_BRACKETS => $request->getConfig('use_brackets'))
433
+		);
434
+		// refuse non-HTTP redirect
435
+		if ($redirectUrl->isAbsolute()
436
+			&& !in_array($redirectUrl->getScheme(), array('http', 'https'))
437
+		) {
438
+			$this->redirectCountdown = null;
439
+			throw new HTTP_Request2_MessageException(
440
+				'Refusing to redirect to a non-HTTP URL ' . $redirectUrl->__toString(),
441
+				HTTP_Request2_Exception::NON_HTTP_REDIRECT
442
+			);
443
+		}
444
+		// Theoretically URL should be absolute (see http://tools.ietf.org/html/rfc2616#section-14.30),
445
+		// but in practice it is often not
446
+		if (!$redirectUrl->isAbsolute()) {
447
+			$redirectUrl = $request->getUrl()->resolve($redirectUrl);
448
+		}
449
+		$redirect = clone $request;
450
+		$redirect->setUrl($redirectUrl);
451
+		if (303 == $response->getStatus()
452
+			|| (!$request->getConfig('strict_redirects')
453
+				&& in_array($response->getStatus(), array(301, 302)))
454
+		) {
455
+			$redirect->setMethod(HTTP_Request2::METHOD_GET);
456
+			$redirect->setBody('');
457
+		}
458
+
459
+		if (0 < $this->redirectCountdown) {
460
+			$this->redirectCountdown--;
461
+		}
462
+		return $this->sendRequest($redirect);
463
+	}
464
+
465
+	/**
466
+	 * Checks whether another request should be performed with server digest auth
467
+	 *
468
+	 * Several conditions should be satisfied for it to return true:
469
+	 *   - response status should be 401
470
+	 *   - auth credentials should be set in the request object
471
+	 *   - response should contain WWW-Authenticate header with digest challenge
472
+	 *   - there is either no challenge stored for this URL or new challenge
473
+	 *     contains stale=true parameter (in other case we probably just failed
474
+	 *     due to invalid username / password)
475
+	 *
476
+	 * The method stores challenge values in $challenges static property
477
+	 *
478
+	 * @param HTTP_Request2_Response $response response to check
479
+	 *
480
+	 * @return   boolean whether another request should be performed
481
+	 * @throws   HTTP_Request2_Exception in case of unsupported challenge parameters
482
+	 */
483
+	protected function shouldUseServerDigestAuth(HTTP_Request2_Response $response)
484
+	{
485
+		// no sense repeating a request if we don't have credentials
486
+		if (401 != $response->getStatus() || !$this->request->getAuth()) {
487
+			return false;
488
+		}
489
+		if (!$challenge = $this->parseDigestChallenge($response->getHeader('www-authenticate'))) {
490
+			return false;
491
+		}
492
+
493
+		$url    = $this->request->getUrl();
494
+		$scheme = $url->getScheme();
495
+		$host   = $scheme . '://' . $url->getHost();
496
+		if ($port = $url->getPort()) {
497
+			if ((0 == strcasecmp($scheme, 'http') && 80 != $port)
498
+				|| (0 == strcasecmp($scheme, 'https') && 443 != $port)
499
+			) {
500
+				$host .= ':' . $port;
501
+			}
502
+		}
503
+
504
+		if (!empty($challenge['domain'])) {
505
+			$prefixes = array();
506
+			foreach (preg_split('/\\s+/', $challenge['domain']) as $prefix) {
507
+				// don't bother with different servers
508
+				if ('/' == substr($prefix, 0, 1)) {
509
+					$prefixes[] = $host . $prefix;
510
+				}
511
+			}
512
+		}
513
+		if (empty($prefixes)) {
514
+			$prefixes = array($host . '/');
515
+		}
516
+
517
+		$ret = true;
518
+		foreach ($prefixes as $prefix) {
519
+			if (!empty(self::$challenges[$prefix])
520
+				&& (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
521
+			) {
522
+				// probably credentials are invalid
523
+				$ret = false;
524
+			}
525
+			self::$challenges[$prefix] =& $challenge;
526
+		}
527
+		return $ret;
528
+	}
529
+
530
+	/**
531
+	 * Checks whether another request should be performed with proxy digest auth
532
+	 *
533
+	 * Several conditions should be satisfied for it to return true:
534
+	 *   - response status should be 407
535
+	 *   - proxy auth credentials should be set in the request object
536
+	 *   - response should contain Proxy-Authenticate header with digest challenge
537
+	 *   - there is either no challenge stored for this proxy or new challenge
538
+	 *     contains stale=true parameter (in other case we probably just failed
539
+	 *     due to invalid username / password)
540
+	 *
541
+	 * The method stores challenge values in $challenges static property
542
+	 *
543
+	 * @param HTTP_Request2_Response $response response to check
544
+	 *
545
+	 * @return   boolean whether another request should be performed
546
+	 * @throws   HTTP_Request2_Exception in case of unsupported challenge parameters
547
+	 */
548
+	protected function shouldUseProxyDigestAuth(HTTP_Request2_Response $response)
549
+	{
550
+		if (407 != $response->getStatus() || !$this->request->getConfig('proxy_user')) {
551
+			return false;
552
+		}
553
+		if (!($challenge = $this->parseDigestChallenge($response->getHeader('proxy-authenticate')))) {
554
+			return false;
555
+		}
556
+
557
+		$key = 'proxy://' . $this->request->getConfig('proxy_host') .
558
+			   ':' . $this->request->getConfig('proxy_port');
559
+
560
+		if (!empty(self::$challenges[$key])
561
+			&& (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
562
+		) {
563
+			$ret = false;
564
+		} else {
565
+			$ret = true;
566
+		}
567
+		self::$challenges[$key] = $challenge;
568
+		return $ret;
569
+	}
570
+
571
+	/**
572
+	 * Extracts digest method challenge from (WWW|Proxy)-Authenticate header value
573
+	 *
574
+	 * There is a problem with implementation of RFC 2617: several of the parameters
575
+	 * are defined as quoted-string there and thus may contain backslash escaped
576
+	 * double quotes (RFC 2616, section 2.2). However, RFC 2617 defines unq(X) as
577
+	 * just value of quoted-string X without surrounding quotes, it doesn't speak
578
+	 * about removing backslash escaping.
579
+	 *
580
+	 * Now realm parameter is user-defined and human-readable, strange things
581
+	 * happen when it contains quotes:
582
+	 *   - Apache allows quotes in realm, but apparently uses realm value without
583
+	 *     backslashes for digest computation
584
+	 *   - Squid allows (manually escaped) quotes there, but it is impossible to
585
+	 *     authorize with either escaped or unescaped quotes used in digest,
586
+	 *     probably it can't parse the response (?)
587
+	 *   - Both IE and Firefox display realm value with backslashes in
588
+	 *     the password popup and apparently use the same value for digest
589
+	 *
590
+	 * HTTP_Request2 follows IE and Firefox (and hopefully RFC 2617) in
591
+	 * quoted-string handling, unfortunately that means failure to authorize
592
+	 * sometimes
593
+	 *
594
+	 * @param string $headerValue value of WWW-Authenticate or Proxy-Authenticate header
595
+	 *
596
+	 * @return   mixed   associative array with challenge parameters, false if
597
+	 *                   no challenge is present in header value
598
+	 * @throws   HTTP_Request2_NotImplementedException in case of unsupported challenge parameters
599
+	 */
600
+	protected function parseDigestChallenge($headerValue)
601
+	{
602
+		$authParam   = '(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
603
+					   self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')';
604
+		$challenge   = "!(?<=^|\\s|,)Digest ({$authParam}\\s*(,\\s*|$))+!";
605
+		if (!preg_match($challenge, $headerValue, $matches)) {
606
+			return false;
607
+		}
608
+
609
+		preg_match_all('!' . $authParam . '!', $matches[0], $params);
610
+		$paramsAry   = array();
611
+		$knownParams = array('realm', 'domain', 'nonce', 'opaque', 'stale',
612
+							 'algorithm', 'qop');
613
+		for ($i = 0; $i < count($params[0]); $i++) {
614
+			// section 3.2.1: Any unrecognized directive MUST be ignored.
615
+			if (in_array($params[1][$i], $knownParams)) {
616
+				if ('"' == substr($params[2][$i], 0, 1)) {
617
+					$paramsAry[$params[1][$i]] = substr($params[2][$i], 1, -1);
618
+				} else {
619
+					$paramsAry[$params[1][$i]] = $params[2][$i];
620
+				}
621
+			}
622
+		}
623
+		// we only support qop=auth
624
+		if (!empty($paramsAry['qop'])
625
+			&& !in_array('auth', array_map('trim', explode(',', $paramsAry['qop'])))
626
+		) {
627
+			throw new HTTP_Request2_NotImplementedException(
628
+				"Only 'auth' qop is currently supported in digest authentication, " .
629
+				"server requested '{$paramsAry['qop']}'"
630
+			);
631
+		}
632
+		// we only support algorithm=MD5
633
+		if (!empty($paramsAry['algorithm']) && 'MD5' != $paramsAry['algorithm']) {
634
+			throw new HTTP_Request2_NotImplementedException(
635
+				"Only 'MD5' algorithm is currently supported in digest authentication, " .
636
+				"server requested '{$paramsAry['algorithm']}'"
637
+			);
638
+		}
639
+
640
+		return $paramsAry;
641
+	}
642
+
643
+	/**
644
+	 * Parses [Proxy-]Authentication-Info header value and updates challenge
645
+	 *
646
+	 * @param array  &$challenge  challenge to update
647
+	 * @param string $headerValue value of [Proxy-]Authentication-Info header
648
+	 *
649
+	 * @todo     validate server rspauth response
650
+	 */
651
+	protected function updateChallenge(&$challenge, $headerValue)
652
+	{
653
+		$authParam   = '!(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
654
+					   self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')!';
655
+		$paramsAry   = array();
656
+
657
+		preg_match_all($authParam, $headerValue, $params);
658
+		for ($i = 0; $i < count($params[0]); $i++) {
659
+			if ('"' == substr($params[2][$i], 0, 1)) {
660
+				$paramsAry[$params[1][$i]] = substr($params[2][$i], 1, -1);
661
+			} else {
662
+				$paramsAry[$params[1][$i]] = $params[2][$i];
663
+			}
664
+		}
665
+		// for now, just update the nonce value
666
+		if (!empty($paramsAry['nextnonce'])) {
667
+			$challenge['nonce'] = $paramsAry['nextnonce'];
668
+			$challenge['nc']    = 1;
669
+		}
670
+	}
671
+
672
+	/**
673
+	 * Creates a value for [Proxy-]Authorization header when using digest authentication
674
+	 *
675
+	 * @param string $user       user name
676
+	 * @param string $password   password
677
+	 * @param string $url        request URL
678
+	 * @param array  &$challenge digest challenge parameters
679
+	 *
680
+	 * @return   string  value of [Proxy-]Authorization request header
681
+	 * @link     http://tools.ietf.org/html/rfc2617#section-3.2.2
682
+	 */
683
+	protected function createDigestResponse($user, $password, $url, &$challenge)
684
+	{
685
+		if (false !== ($q = strpos($url, '?'))
686
+			&& $this->request->getConfig('digest_compat_ie')
687
+		) {
688
+			$url = substr($url, 0, $q);
689
+		}
690
+
691
+		$a1 = md5($user . ':' . $challenge['realm'] . ':' . $password);
692
+		$a2 = md5($this->request->getMethod() . ':' . $url);
693
+
694
+		if (empty($challenge['qop'])) {
695
+			$digest = md5($a1 . ':' . $challenge['nonce'] . ':' . $a2);
696
+		} else {
697
+			$challenge['cnonce'] = 'Req2.' . rand();
698
+			if (empty($challenge['nc'])) {
699
+				$challenge['nc'] = 1;
700
+			}
701
+			$nc     = sprintf('%08x', $challenge['nc']++);
702
+			$digest = md5(
703
+				$a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' .
704
+				$challenge['cnonce'] . ':auth:' . $a2
705
+			);
706
+		}
707
+		return 'Digest username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $user) . '", ' .
708
+			   'realm="' . $challenge['realm'] . '", ' .
709
+			   'nonce="' . $challenge['nonce'] . '", ' .
710
+			   'uri="' . $url . '", ' .
711
+			   'response="' . $digest . '"' .
712
+			   (!empty($challenge['opaque'])?
713
+				', opaque="' . $challenge['opaque'] . '"':
714
+				'') .
715
+			   (!empty($challenge['qop'])?
716
+				', qop="auth", nc=' . $nc . ', cnonce="' . $challenge['cnonce'] . '"':
717
+				'');
718
+	}
719
+
720
+	/**
721
+	 * Adds 'Authorization' header (if needed) to request headers array
722
+	 *
723
+	 * @param array  &$headers    request headers
724
+	 * @param string $requestHost request host (needed for digest authentication)
725
+	 * @param string $requestUrl  request URL (needed for digest authentication)
726
+	 *
727
+	 * @throws   HTTP_Request2_NotImplementedException
728
+	 */
729
+	protected function addAuthorizationHeader(&$headers, $requestHost, $requestUrl)
730
+	{
731
+		if (!($auth = $this->request->getAuth())) {
732
+			return;
733
+		}
734
+		switch ($auth['scheme']) {
735
+		case HTTP_Request2::AUTH_BASIC:
736
+			$headers['authorization'] = 'Basic ' . base64_encode(
737
+				$auth['user'] . ':' . $auth['password']
738
+			);
739
+			break;
740
+
741
+		case HTTP_Request2::AUTH_DIGEST:
742
+			unset($this->serverChallenge);
743
+			$fullUrl = ('/' == $requestUrl[0])?
744
+					   $this->request->getUrl()->getScheme() . '://' .
745
+						$requestHost . $requestUrl:
746
+					   $requestUrl;
747
+			foreach (array_keys(self::$challenges) as $key) {
748
+				if ($key == substr($fullUrl, 0, strlen($key))) {
749
+					$headers['authorization'] = $this->createDigestResponse(
750
+						$auth['user'], $auth['password'],
751
+						$requestUrl, self::$challenges[$key]
752
+					);
753
+					$this->serverChallenge =& self::$challenges[$key];
754
+					break;
755
+				}
756
+			}
757
+			break;
758
+
759
+		default:
760
+			throw new HTTP_Request2_NotImplementedException(
761
+				"Unknown HTTP authentication scheme '{$auth['scheme']}'"
762
+			);
763
+		}
764
+	}
765
+
766
+	/**
767
+	 * Adds 'Proxy-Authorization' header (if needed) to request headers array
768
+	 *
769
+	 * @param array  &$headers   request headers
770
+	 * @param string $requestUrl request URL (needed for digest authentication)
771
+	 *
772
+	 * @throws   HTTP_Request2_NotImplementedException
773
+	 */
774
+	protected function addProxyAuthorizationHeader(&$headers, $requestUrl)
775
+	{
776
+		if (!$this->request->getConfig('proxy_host')
777
+			|| !($user = $this->request->getConfig('proxy_user'))
778
+			|| (0 == strcasecmp('https', $this->request->getUrl()->getScheme())
779
+				&& HTTP_Request2::METHOD_CONNECT != $this->request->getMethod())
780
+		) {
781
+			return;
782
+		}
783
+
784
+		$password = $this->request->getConfig('proxy_password');
785
+		switch ($this->request->getConfig('proxy_auth_scheme')) {
786
+		case HTTP_Request2::AUTH_BASIC:
787
+			$headers['proxy-authorization'] = 'Basic ' . base64_encode(
788
+				$user . ':' . $password
789
+			);
790
+			break;
791
+
792
+		case HTTP_Request2::AUTH_DIGEST:
793
+			unset($this->proxyChallenge);
794
+			$proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') .
795
+						':' . $this->request->getConfig('proxy_port');
796
+			if (!empty(self::$challenges[$proxyUrl])) {
797
+				$headers['proxy-authorization'] = $this->createDigestResponse(
798
+					$user, $password,
799
+					$requestUrl, self::$challenges[$proxyUrl]
800
+				);
801
+				$this->proxyChallenge =& self::$challenges[$proxyUrl];
802
+			}
803
+			break;
804
+
805
+		default:
806
+			throw new HTTP_Request2_NotImplementedException(
807
+				"Unknown HTTP authentication scheme '" .
808
+				$this->request->getConfig('proxy_auth_scheme') . "'"
809
+			);
810
+		}
811
+	}
812
+
813
+
814
+	/**
815
+	 * Creates the string with the Request-Line and request headers
816
+	 *
817
+	 * @return   string
818
+	 * @throws   HTTP_Request2_Exception
819
+	 */
820
+	protected function prepareHeaders()
821
+	{
822
+		$headers = $this->request->getHeaders();
823
+		$url     = $this->request->getUrl();
824
+		$connect = HTTP_Request2::METHOD_CONNECT == $this->request->getMethod();
825
+		$host    = $url->getHost();
826
+
827
+		$defaultPort = 0 == strcasecmp($url->getScheme(), 'https')? 443: 80;
828
+		if (($port = $url->getPort()) && $port != $defaultPort || $connect) {
829
+			$host .= ':' . (empty($port)? $defaultPort: $port);
830
+		}
831
+		// Do not overwrite explicitly set 'Host' header, see bug #16146
832
+		if (!isset($headers['host'])) {
833
+			$headers['host'] = $host;
834
+		}
835
+
836
+		if ($connect) {
837
+			$requestUrl = $host;
838
+
839
+		} else {
840
+			if (!$this->request->getConfig('proxy_host')
841
+				|| 'http' != $this->request->getConfig('proxy_type')
842
+				|| 0 == strcasecmp($url->getScheme(), 'https')
843
+			) {
844
+				$requestUrl = '';
845
+			} else {
846
+				$requestUrl = $url->getScheme() . '://' . $host;
847
+			}
848
+			$path        = $url->getPath();
849
+			$query       = $url->getQuery();
850
+			$requestUrl .= (empty($path)? '/': $path) . (empty($query)? '': '?' . $query);
851
+		}
852
+
853
+		if ('1.1' == $this->request->getConfig('protocol_version')
854
+			&& extension_loaded('zlib') && !isset($headers['accept-encoding'])
855
+		) {
856
+			$headers['accept-encoding'] = 'gzip, deflate';
857
+		}
858
+		if (($jar = $this->request->getCookieJar())
859
+			&& ($cookies = $jar->getMatching($this->request->getUrl(), true))
860
+		) {
861
+			$headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
862
+		}
863
+
864
+		$this->addAuthorizationHeader($headers, $host, $requestUrl);
865
+		$this->addProxyAuthorizationHeader($headers, $requestUrl);
866
+		$this->calculateRequestLength($headers);
867
+		if ('1.1' == $this->request->getConfig('protocol_version')) {
868
+			$this->updateExpectHeader($headers);
869
+		} else {
870
+			$this->expect100Continue = false;
871
+		}
872
+
873
+		$headersStr = $this->request->getMethod() . ' ' . $requestUrl . ' HTTP/' .
874
+					  $this->request->getConfig('protocol_version') . "\r\n";
875
+		foreach ($headers as $name => $value) {
876
+			$canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
877
+			$headersStr   .= $canonicalName . ': ' . $value . "\r\n";
878
+		}
879
+		return $headersStr . "\r\n";
880
+	}
881
+
882
+	/**
883
+	 * Adds or removes 'Expect: 100-continue' header from request headers
884
+	 *
885
+	 * Also sets the $expect100Continue property. Parsing of existing header
886
+	 * is somewhat needed due to its complex structure and due to the
887
+	 * requirement in section 8.2.3 of RFC 2616:
888
+	 * > A client MUST NOT send an Expect request-header field (section
889
+	 * > 14.20) with the "100-continue" expectation if it does not intend
890
+	 * > to send a request body.
891
+	 *
892
+	 * @param array &$headers Array of headers prepared for the request
893
+	 *
894
+	 * @throws HTTP_Request2_LogicException
895
+	 * @link http://pear.php.net/bugs/bug.php?id=19233
896
+	 * @link http://tools.ietf.org/html/rfc2616#section-8.2.3
897
+	 */
898
+	protected function updateExpectHeader(&$headers)
899
+	{
900
+		$this->expect100Continue = false;
901
+		$expectations = array();
902
+		if (isset($headers['expect'])) {
903
+			if ('' === $headers['expect']) {
904
+				// empty 'Expect' header is technically invalid, so just get rid of it
905
+				unset($headers['expect']);
906
+				return;
907
+			}
908
+			// build regexp to parse the value of existing Expect header
909
+			$expectParam     = ';\s*' . self::REGEXP_TOKEN . '(?:\s*=\s*(?:'
910
+							   . self::REGEXP_TOKEN . '|'
911
+							   . self::REGEXP_QUOTED_STRING . '))?\s*';
912
+			$expectExtension = self::REGEXP_TOKEN . '(?:\s*=\s*(?:'
913
+							   . self::REGEXP_TOKEN . '|'
914
+							   . self::REGEXP_QUOTED_STRING . ')\s*(?:'
915
+							   . $expectParam . ')*)?';
916
+			$expectItem      = '!(100-continue|' . $expectExtension . ')!A';
917
+
918
+			$pos    = 0;
919
+			$length = strlen($headers['expect']);
920
+
921
+			while ($pos < $length) {
922
+				$pos += strspn($headers['expect'], " \t", $pos);
923
+				if (',' === substr($headers['expect'], $pos, 1)) {
924
+					$pos++;
925
+					continue;
926
+
927
+				} elseif (!preg_match($expectItem, $headers['expect'], $m, 0, $pos)) {
928
+					throw new HTTP_Request2_LogicException(
929
+						"Cannot parse value '{$headers['expect']}' of Expect header",
930
+						HTTP_Request2_Exception::INVALID_ARGUMENT
931
+					);
932
+
933
+				} else {
934
+					$pos += strlen($m[0]);
935
+					if (strcasecmp('100-continue', $m[0])) {
936
+						$expectations[]  = $m[0];
937
+					}
938
+				}
939
+			}
940
+		}
941
+
942
+		if (1024 < $this->contentLength) {
943
+			$expectations[] = '100-continue';
944
+			$this->expect100Continue = true;
945
+		}
946
+
947
+		if (empty($expectations)) {
948
+			unset($headers['expect']);
949
+		} else {
950
+			$headers['expect'] = implode(',', $expectations);
951
+		}
952
+	}
953
+
954
+	/**
955
+	 * Sends the request body
956
+	 *
957
+	 * @throws   HTTP_Request2_MessageException
958
+	 */
959
+	protected function writeBody()
960
+	{
961
+		if (in_array($this->request->getMethod(), self::$bodyDisallowed)
962
+			|| 0 == $this->contentLength
963
+		) {
964
+			return;
965
+		}
966
+
967
+		$position   = 0;
968
+		$bufferSize = $this->request->getConfig('buffer_size');
969
+		$headers    = $this->request->getHeaders();
970
+		$chunked    = isset($headers['transfer-encoding']);
971
+		while ($position < $this->contentLength) {
972
+			if (is_string($this->requestBody)) {
973
+				$str = substr($this->requestBody, $position, $bufferSize);
974
+			} elseif (is_resource($this->requestBody)) {
975
+				$str = fread($this->requestBody, $bufferSize);
976
+			} else {
977
+				$str = $this->requestBody->read($bufferSize);
978
+			}
979
+			if (!$chunked) {
980
+				$this->socket->write($str);
981
+			} else {
982
+				$this->socket->write(dechex(strlen($str)) . "\r\n{$str}\r\n");
983
+			}
984
+			// Provide the length of written string to the observer, request #7630
985
+			$this->request->setLastEvent('sentBodyPart', strlen($str));
986
+			$position += strlen($str);
987
+		}
988
+
989
+		// write zero-length chunk
990
+		if ($chunked) {
991
+			$this->socket->write("0\r\n\r\n");
992
+		}
993
+		$this->request->setLastEvent('sentBody', $this->contentLength);
994
+	}
995
+
996
+	/**
997
+	 * Reads the remote server's response
998
+	 *
999
+	 * @return   HTTP_Request2_Response
1000
+	 * @throws   HTTP_Request2_Exception
1001
+	 */
1002
+	protected function readResponse()
1003
+	{
1004
+		$bufferSize = $this->request->getConfig('buffer_size');
1005
+		// http://tools.ietf.org/html/rfc2616#section-8.2.3
1006
+		// ...the client SHOULD NOT wait for an indefinite period before sending the request body
1007
+		$timeout    = $this->expect100Continue ? 1 : null;
1008
+
1009
+		do {
1010
+			try {
1011
+				$response = new HTTP_Request2_Response(
1012
+					$this->socket->readLine($bufferSize, $timeout), true, $this->request->getUrl()
1013
+				);
1014
+				do {
1015
+					$headerLine = $this->socket->readLine($bufferSize);
1016
+					$response->parseHeaderLine($headerLine);
1017
+				} while ('' != $headerLine);
1018
+
1019
+			} catch (HTTP_Request2_MessageException $e) {
1020
+				if (HTTP_Request2_Exception::TIMEOUT === $e->getCode()
1021
+					&& $this->expect100Continue
1022
+				) {
1023
+					return null;
1024
+				}
1025
+				throw $e;
1026
+			}
1027
+			if ($this->expect100Continue && 100 == $response->getStatus()) {
1028
+				return $response;
1029
+			}
1030
+		} while (in_array($response->getStatus(), array(100, 101)));
1031
+
1032
+		$this->request->setLastEvent('receivedHeaders', $response);
1033
+
1034
+		// No body possible in such responses
1035
+		if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod()
1036
+			|| (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()
1037
+				&& 200 <= $response->getStatus() && 300 > $response->getStatus())
1038
+			|| in_array($response->getStatus(), array(204, 304))
1039
+		) {
1040
+			return $response;
1041
+		}
1042
+
1043
+		$chunked = 'chunked' == $response->getHeader('transfer-encoding');
1044
+		$length  = $response->getHeader('content-length');
1045
+		$hasBody = false;
1046
+		if ($chunked || null === $length || 0 < intval($length)) {
1047
+			// RFC 2616, section 4.4:
1048
+			// 3. ... If a message is received with both a
1049
+			// Transfer-Encoding header field and a Content-Length header field,
1050
+			// the latter MUST be ignored.
1051
+			$toRead = ($chunked || null === $length)? null: $length;
1052
+			$this->chunkLength = 0;
1053
+
1054
+			while (!$this->socket->eof() && (is_null($toRead) || 0 < $toRead)) {
1055
+				if ($chunked) {
1056
+					$data = $this->readChunked($bufferSize);
1057
+				} elseif (is_null($toRead)) {
1058
+					$data = $this->socket->read($bufferSize);
1059
+				} else {
1060
+					$data    = $this->socket->read(min($toRead, $bufferSize));
1061
+					$toRead -= strlen($data);
1062
+				}
1063
+				if ('' == $data && (!$this->chunkLength || $this->socket->eof())) {
1064
+					break;
1065
+				}
1066
+
1067
+				$hasBody = true;
1068
+				if ($this->request->getConfig('store_body')) {
1069
+					$response->appendBody($data);
1070
+				}
1071
+				if (!in_array($response->getHeader('content-encoding'), array('identity', null))) {
1072
+					$this->request->setLastEvent('receivedEncodedBodyPart', $data);
1073
+				} else {
1074
+					$this->request->setLastEvent('receivedBodyPart', $data);
1075
+				}
1076
+			}
1077
+		}
1078
+
1079
+		if ($hasBody) {
1080
+			$this->request->setLastEvent('receivedBody', $response);
1081
+		}
1082
+		return $response;
1083
+	}
1084
+
1085
+	/**
1086
+	 * Reads a part of response body encoded with chunked Transfer-Encoding
1087
+	 *
1088
+	 * @param int $bufferSize buffer size to use for reading
1089
+	 *
1090
+	 * @return   string
1091
+	 * @throws   HTTP_Request2_MessageException
1092
+	 */
1093
+	protected function readChunked($bufferSize)
1094
+	{
1095
+		// at start of the next chunk?
1096
+		if (0 == $this->chunkLength) {
1097
+			$line = $this->socket->readLine($bufferSize);
1098
+			if (!preg_match('/^([0-9a-f]+)/i', $line, $matches)) {
1099
+				throw new HTTP_Request2_MessageException(
1100
+					"Cannot decode chunked response, invalid chunk length '{$line}'",
1101
+					HTTP_Request2_Exception::DECODE_ERROR
1102
+				);
1103
+			} else {
1104
+				$this->chunkLength = hexdec($matches[1]);
1105
+				// Chunk with zero length indicates the end
1106
+				if (0 == $this->chunkLength) {
1107
+					$this->socket->readLine($bufferSize);
1108
+					return '';
1109
+				}
1110
+			}
1111
+		}
1112
+		$data = $this->socket->read(min($this->chunkLength, $bufferSize));
1113
+		$this->chunkLength -= strlen($data);
1114
+		if (0 == $this->chunkLength) {
1115
+			$this->socket->readLine($bufferSize); // Trailing CRLF
1116
+		}
1117
+		return $data;
1118
+	}
1119 1119
 }
1120 1120
 
1121 1121
 ?>
1122 1122
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +76 added lines, -79 removed lines patch added patch discarded remove patch
@@ -199,7 +199,7 @@  discard block
 block discarded – undo
199 199
         $headers = $this->request->getHeaders();
200 200
         $reqHost = $this->request->getUrl()->getHost();
201 201
         if (!($reqPort = $this->request->getUrl()->getPort())) {
202
-            $reqPort = $secure? 443: 80;
202
+            $reqPort = $secure ? 443 : 80;
203 203
         }
204 204
 
205 205
         $httpProxy = $socksProxy = false;
@@ -253,7 +253,7 @@  discard block
 block discarded – undo
253 253
         $options = array();
254 254
         if ($ip = $this->request->getConfig('local_ip')) {
255 255
             $options['socket'] = array(
256
-                'bindto' => (false === strpos($ip, ':') ? $ip : '[' . $ip . ']') . ':0'
256
+                'bindto' => (false === strpos($ip, ':') ? $ip : '['.$ip.']').':0'
257 257
             );
258 258
         }
259 259
         if ($secure || $tunnel) {
@@ -281,12 +281,12 @@  discard block
 block discarded – undo
281 281
 
282 282
         // Changing SSL context options after connection is established does *not*
283 283
         // work, we need a new connection if options change
284
-        $remote    = ((!$secure || $httpProxy || $socksProxy)? 'tcp://': 'ssl://')
285
-                     . $host . ':' . $port;
286
-        $socketKey = $remote . (
284
+        $remote    = ((!$secure || $httpProxy || $socksProxy) ? 'tcp://' : 'ssl://')
285
+                     . $host.':'.$port;
286
+        $socketKey = $remote.(
287 287
                         ($secure && $httpProxy || $socksProxy)
288 288
                         ? "->{$reqHost}:{$reqPort}" : ''
289
-                     ) . (empty($options)? '': ':' . serialize($options));
289
+                     ).(empty($options) ? '' : ':'.serialize($options));
290 290
         unset($this->socket);
291 291
 
292 292
         // We use persistent connections and have a connected socket?
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
         if ($keepAlive && !empty(self::$sockets[$socketKey])
295 295
             && !self::$sockets[$socketKey]->eof()
296 296
         ) {
297
-            $this->socket =& self::$sockets[$socketKey];
297
+            $this->socket = & self::$sockets[$socketKey];
298 298
 
299 299
         } else {
300 300
             if ($socksProxy) {
@@ -324,8 +324,8 @@  discard block
 block discarded – undo
324 324
                     $remote, $this->request->getConfig('connect_timeout'), $options
325 325
                 );
326 326
             }
327
-            $this->request->setLastEvent('connect', empty($conninfo)? $remote: $conninfo);
328
-            self::$sockets[$socketKey] =& $this->socket;
327
+            $this->request->setLastEvent('connect', empty($conninfo) ? $remote : $conninfo);
328
+            self::$sockets[$socketKey] = & $this->socket;
329 329
         }
330 330
         $this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));
331 331
         return $keepAlive;
@@ -352,8 +352,8 @@  discard block
 block discarded – undo
352 352
         // Need any successful (2XX) response
353 353
         if (200 > $response->getStatus() || 300 <= $response->getStatus()) {
354 354
             throw new HTTP_Request2_ConnectionException(
355
-                'Failed to connect via HTTPS proxy. Proxy response: ' .
356
-                $response->getStatus() . ' ' . $response->getReasonPhrase()
355
+                'Failed to connect via HTTPS proxy. Proxy response: '.
356
+                $response->getStatus().' '.$response->getReasonPhrase()
357 357
             );
358 358
         }
359 359
         $this->socket = $donor->socket;
@@ -383,7 +383,7 @@  discard block
 block discarded – undo
383 383
                        // no body possible for such responses, see also request #17031
384 384
                        || HTTP_Request2::METHOD_HEAD == $this->request->getMethod()
385 385
                        || in_array($response->getStatus(), array(204, 304));
386
-        $persistent  = 'keep-alive' == strtolower($response->getHeader('connection')) ||
386
+        $persistent = 'keep-alive' == strtolower($response->getHeader('connection')) ||
387 387
                        (null === $response->getHeader('connection') &&
388 388
                         '1.1' == $response->getVersion());
389 389
         return $requestKeepAlive && $lengthKnown && $persistent;
@@ -423,7 +423,7 @@  discard block
 block discarded – undo
423 423
             $this->redirectCountdown = null;
424 424
             // Copying cURL behaviour
425 425
             throw new HTTP_Request2_MessageException(
426
-                'Maximum (' . $request->getConfig('max_redirects') . ') redirects followed',
426
+                'Maximum ('.$request->getConfig('max_redirects').') redirects followed',
427 427
                 HTTP_Request2_Exception::TOO_MANY_REDIRECTS
428 428
             );
429 429
         }
@@ -437,7 +437,7 @@  discard block
 block discarded – undo
437 437
         ) {
438 438
             $this->redirectCountdown = null;
439 439
             throw new HTTP_Request2_MessageException(
440
-                'Refusing to redirect to a non-HTTP URL ' . $redirectUrl->__toString(),
440
+                'Refusing to redirect to a non-HTTP URL '.$redirectUrl->__toString(),
441 441
                 HTTP_Request2_Exception::NON_HTTP_REDIRECT
442 442
             );
443 443
         }
@@ -492,12 +492,12 @@  discard block
 block discarded – undo
492 492
 
493 493
         $url    = $this->request->getUrl();
494 494
         $scheme = $url->getScheme();
495
-        $host   = $scheme . '://' . $url->getHost();
495
+        $host   = $scheme.'://'.$url->getHost();
496 496
         if ($port = $url->getPort()) {
497 497
             if ((0 == strcasecmp($scheme, 'http') && 80 != $port)
498 498
                 || (0 == strcasecmp($scheme, 'https') && 443 != $port)
499 499
             ) {
500
-                $host .= ':' . $port;
500
+                $host .= ':'.$port;
501 501
             }
502 502
         }
503 503
 
@@ -506,12 +506,12 @@  discard block
 block discarded – undo
506 506
             foreach (preg_split('/\\s+/', $challenge['domain']) as $prefix) {
507 507
                 // don't bother with different servers
508 508
                 if ('/' == substr($prefix, 0, 1)) {
509
-                    $prefixes[] = $host . $prefix;
509
+                    $prefixes[] = $host.$prefix;
510 510
                 }
511 511
             }
512 512
         }
513 513
         if (empty($prefixes)) {
514
-            $prefixes = array($host . '/');
514
+            $prefixes = array($host.'/');
515 515
         }
516 516
 
517 517
         $ret = true;
@@ -522,7 +522,7 @@  discard block
 block discarded – undo
522 522
                 // probably credentials are invalid
523 523
                 $ret = false;
524 524
             }
525
-            self::$challenges[$prefix] =& $challenge;
525
+            self::$challenges[$prefix] = & $challenge;
526 526
         }
527 527
         return $ret;
528 528
     }
@@ -554,8 +554,8 @@  discard block
 block discarded – undo
554 554
             return false;
555 555
         }
556 556
 
557
-        $key = 'proxy://' . $this->request->getConfig('proxy_host') .
558
-               ':' . $this->request->getConfig('proxy_port');
557
+        $key = 'proxy://'.$this->request->getConfig('proxy_host').
558
+               ':'.$this->request->getConfig('proxy_port');
559 559
 
560 560
         if (!empty(self::$challenges[$key])
561 561
             && (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
@@ -599,14 +599,14 @@  discard block
 block discarded – undo
599 599
      */
600 600
     protected function parseDigestChallenge($headerValue)
601 601
     {
602
-        $authParam   = '(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
603
-                       self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')';
602
+        $authParam   = '('.self::REGEXP_TOKEN.')\\s*=\\s*('.
603
+                       self::REGEXP_TOKEN.'|'.self::REGEXP_QUOTED_STRING.')';
604 604
         $challenge   = "!(?<=^|\\s|,)Digest ({$authParam}\\s*(,\\s*|$))+!";
605 605
         if (!preg_match($challenge, $headerValue, $matches)) {
606 606
             return false;
607 607
         }
608 608
 
609
-        preg_match_all('!' . $authParam . '!', $matches[0], $params);
609
+        preg_match_all('!'.$authParam.'!', $matches[0], $params);
610 610
         $paramsAry   = array();
611 611
         $knownParams = array('realm', 'domain', 'nonce', 'opaque', 'stale',
612 612
                              'algorithm', 'qop');
@@ -625,14 +625,14 @@  discard block
 block discarded – undo
625 625
             && !in_array('auth', array_map('trim', explode(',', $paramsAry['qop'])))
626 626
         ) {
627 627
             throw new HTTP_Request2_NotImplementedException(
628
-                "Only 'auth' qop is currently supported in digest authentication, " .
628
+                "Only 'auth' qop is currently supported in digest authentication, ".
629 629
                 "server requested '{$paramsAry['qop']}'"
630 630
             );
631 631
         }
632 632
         // we only support algorithm=MD5
633 633
         if (!empty($paramsAry['algorithm']) && 'MD5' != $paramsAry['algorithm']) {
634 634
             throw new HTTP_Request2_NotImplementedException(
635
-                "Only 'MD5' algorithm is currently supported in digest authentication, " .
635
+                "Only 'MD5' algorithm is currently supported in digest authentication, ".
636 636
                 "server requested '{$paramsAry['algorithm']}'"
637 637
             );
638 638
         }
@@ -650,8 +650,8 @@  discard block
 block discarded – undo
650 650
      */
651 651
     protected function updateChallenge(&$challenge, $headerValue)
652 652
     {
653
-        $authParam   = '!(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
654
-                       self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')!';
653
+        $authParam   = '!('.self::REGEXP_TOKEN.')\\s*=\\s*('.
654
+                       self::REGEXP_TOKEN.'|'.self::REGEXP_QUOTED_STRING.')!';
655 655
         $paramsAry   = array();
656 656
 
657 657
         preg_match_all($authParam, $headerValue, $params);
@@ -688,33 +688,31 @@  discard block
 block discarded – undo
688 688
             $url = substr($url, 0, $q);
689 689
         }
690 690
 
691
-        $a1 = md5($user . ':' . $challenge['realm'] . ':' . $password);
692
-        $a2 = md5($this->request->getMethod() . ':' . $url);
691
+        $a1 = md5($user.':'.$challenge['realm'].':'.$password);
692
+        $a2 = md5($this->request->getMethod().':'.$url);
693 693
 
694 694
         if (empty($challenge['qop'])) {
695
-            $digest = md5($a1 . ':' . $challenge['nonce'] . ':' . $a2);
695
+            $digest = md5($a1.':'.$challenge['nonce'].':'.$a2);
696 696
         } else {
697
-            $challenge['cnonce'] = 'Req2.' . rand();
697
+            $challenge['cnonce'] = 'Req2.'.rand();
698 698
             if (empty($challenge['nc'])) {
699 699
                 $challenge['nc'] = 1;
700 700
             }
701 701
             $nc     = sprintf('%08x', $challenge['nc']++);
702 702
             $digest = md5(
703
-                $a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' .
704
-                $challenge['cnonce'] . ':auth:' . $a2
703
+                $a1.':'.$challenge['nonce'].':'.$nc.':'.
704
+                $challenge['cnonce'].':auth:'.$a2
705 705
             );
706 706
         }
707
-        return 'Digest username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $user) . '", ' .
708
-               'realm="' . $challenge['realm'] . '", ' .
709
-               'nonce="' . $challenge['nonce'] . '", ' .
710
-               'uri="' . $url . '", ' .
711
-               'response="' . $digest . '"' .
712
-               (!empty($challenge['opaque'])?
713
-                ', opaque="' . $challenge['opaque'] . '"':
714
-                '') .
715
-               (!empty($challenge['qop'])?
716
-                ', qop="auth", nc=' . $nc . ', cnonce="' . $challenge['cnonce'] . '"':
717
-                '');
707
+        return 'Digest username="'.str_replace(array('\\', '"'), array('\\\\', '\\"'), $user).'", '.
708
+               'realm="'.$challenge['realm'].'", '.
709
+               'nonce="'.$challenge['nonce'].'", '.
710
+               'uri="'.$url.'", '.
711
+               'response="'.$digest.'"'.
712
+               (!empty($challenge['opaque']) ?
713
+                ', opaque="'.$challenge['opaque'].'"' : '').
714
+               (!empty($challenge['qop']) ?
715
+                ', qop="auth", nc='.$nc.', cnonce="'.$challenge['cnonce'].'"' : '');
718 716
     }
719 717
 
720 718
     /**
@@ -733,24 +731,23 @@  discard block
 block discarded – undo
733 731
         }
734 732
         switch ($auth['scheme']) {
735 733
         case HTTP_Request2::AUTH_BASIC:
736
-            $headers['authorization'] = 'Basic ' . base64_encode(
737
-                $auth['user'] . ':' . $auth['password']
734
+            $headers['authorization'] = 'Basic '.base64_encode(
735
+                $auth['user'].':'.$auth['password']
738 736
             );
739 737
             break;
740 738
 
741 739
         case HTTP_Request2::AUTH_DIGEST:
742 740
             unset($this->serverChallenge);
743
-            $fullUrl = ('/' == $requestUrl[0])?
744
-                       $this->request->getUrl()->getScheme() . '://' .
745
-                        $requestHost . $requestUrl:
746
-                       $requestUrl;
741
+            $fullUrl = ('/' == $requestUrl[0]) ?
742
+                       $this->request->getUrl()->getScheme().'://'.
743
+                        $requestHost.$requestUrl : $requestUrl;
747 744
             foreach (array_keys(self::$challenges) as $key) {
748 745
                 if ($key == substr($fullUrl, 0, strlen($key))) {
749 746
                     $headers['authorization'] = $this->createDigestResponse(
750 747
                         $auth['user'], $auth['password'],
751 748
                         $requestUrl, self::$challenges[$key]
752 749
                     );
753
-                    $this->serverChallenge =& self::$challenges[$key];
750
+                    $this->serverChallenge = & self::$challenges[$key];
754 751
                     break;
755 752
                 }
756 753
             }
@@ -784,28 +781,28 @@  discard block
 block discarded – undo
784 781
         $password = $this->request->getConfig('proxy_password');
785 782
         switch ($this->request->getConfig('proxy_auth_scheme')) {
786 783
         case HTTP_Request2::AUTH_BASIC:
787
-            $headers['proxy-authorization'] = 'Basic ' . base64_encode(
788
-                $user . ':' . $password
784
+            $headers['proxy-authorization'] = 'Basic '.base64_encode(
785
+                $user.':'.$password
789 786
             );
790 787
             break;
791 788
 
792 789
         case HTTP_Request2::AUTH_DIGEST:
793 790
             unset($this->proxyChallenge);
794
-            $proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') .
795
-                        ':' . $this->request->getConfig('proxy_port');
791
+            $proxyUrl = 'proxy://'.$this->request->getConfig('proxy_host').
792
+                        ':'.$this->request->getConfig('proxy_port');
796 793
             if (!empty(self::$challenges[$proxyUrl])) {
797 794
                 $headers['proxy-authorization'] = $this->createDigestResponse(
798 795
                     $user, $password,
799 796
                     $requestUrl, self::$challenges[$proxyUrl]
800 797
                 );
801
-                $this->proxyChallenge =& self::$challenges[$proxyUrl];
798
+                $this->proxyChallenge = & self::$challenges[$proxyUrl];
802 799
             }
803 800
             break;
804 801
 
805 802
         default:
806 803
             throw new HTTP_Request2_NotImplementedException(
807
-                "Unknown HTTP authentication scheme '" .
808
-                $this->request->getConfig('proxy_auth_scheme') . "'"
804
+                "Unknown HTTP authentication scheme '".
805
+                $this->request->getConfig('proxy_auth_scheme')."'"
809 806
             );
810 807
         }
811 808
     }
@@ -824,9 +821,9 @@  discard block
 block discarded – undo
824 821
         $connect = HTTP_Request2::METHOD_CONNECT == $this->request->getMethod();
825 822
         $host    = $url->getHost();
826 823
 
827
-        $defaultPort = 0 == strcasecmp($url->getScheme(), 'https')? 443: 80;
824
+        $defaultPort = 0 == strcasecmp($url->getScheme(), 'https') ? 443 : 80;
828 825
         if (($port = $url->getPort()) && $port != $defaultPort || $connect) {
829
-            $host .= ':' . (empty($port)? $defaultPort: $port);
826
+            $host .= ':'.(empty($port) ? $defaultPort : $port);
830 827
         }
831 828
         // Do not overwrite explicitly set 'Host' header, see bug #16146
832 829
         if (!isset($headers['host'])) {
@@ -843,11 +840,11 @@  discard block
 block discarded – undo
843 840
             ) {
844 841
                 $requestUrl = '';
845 842
             } else {
846
-                $requestUrl = $url->getScheme() . '://' . $host;
843
+                $requestUrl = $url->getScheme().'://'.$host;
847 844
             }
848 845
             $path        = $url->getPath();
849 846
             $query       = $url->getQuery();
850
-            $requestUrl .= (empty($path)? '/': $path) . (empty($query)? '': '?' . $query);
847
+            $requestUrl .= (empty($path) ? '/' : $path).(empty($query) ? '' : '?'.$query);
851 848
         }
852 849
 
853 850
         if ('1.1' == $this->request->getConfig('protocol_version')
@@ -858,7 +855,7 @@  discard block
 block discarded – undo
858 855
         if (($jar = $this->request->getCookieJar())
859 856
             && ($cookies = $jar->getMatching($this->request->getUrl(), true))
860 857
         ) {
861
-            $headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
858
+            $headers['cookie'] = (empty($headers['cookie']) ? '' : $headers['cookie'].'; ').$cookies;
862 859
         }
863 860
 
864 861
         $this->addAuthorizationHeader($headers, $host, $requestUrl);
@@ -870,13 +867,13 @@  discard block
 block discarded – undo
870 867
             $this->expect100Continue = false;
871 868
         }
872 869
 
873
-        $headersStr = $this->request->getMethod() . ' ' . $requestUrl . ' HTTP/' .
874
-                      $this->request->getConfig('protocol_version') . "\r\n";
870
+        $headersStr = $this->request->getMethod().' '.$requestUrl.' HTTP/'.
871
+                      $this->request->getConfig('protocol_version')."\r\n";
875 872
         foreach ($headers as $name => $value) {
876 873
             $canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
877
-            $headersStr   .= $canonicalName . ': ' . $value . "\r\n";
874
+            $headersStr   .= $canonicalName.': '.$value."\r\n";
878 875
         }
879
-        return $headersStr . "\r\n";
876
+        return $headersStr."\r\n";
880 877
     }
881 878
 
882 879
     /**
@@ -906,14 +903,14 @@  discard block
 block discarded – undo
906 903
                 return;
907 904
             }
908 905
             // build regexp to parse the value of existing Expect header
909
-            $expectParam     = ';\s*' . self::REGEXP_TOKEN . '(?:\s*=\s*(?:'
910
-                               . self::REGEXP_TOKEN . '|'
911
-                               . self::REGEXP_QUOTED_STRING . '))?\s*';
912
-            $expectExtension = self::REGEXP_TOKEN . '(?:\s*=\s*(?:'
913
-                               . self::REGEXP_TOKEN . '|'
914
-                               . self::REGEXP_QUOTED_STRING . ')\s*(?:'
915
-                               . $expectParam . ')*)?';
916
-            $expectItem      = '!(100-continue|' . $expectExtension . ')!A';
906
+            $expectParam     = ';\s*'.self::REGEXP_TOKEN.'(?:\s*=\s*(?:'
907
+                               . self::REGEXP_TOKEN.'|'
908
+                               . self::REGEXP_QUOTED_STRING.'))?\s*';
909
+            $expectExtension = self::REGEXP_TOKEN.'(?:\s*=\s*(?:'
910
+                               . self::REGEXP_TOKEN.'|'
911
+                               . self::REGEXP_QUOTED_STRING.')\s*(?:'
912
+                               . $expectParam.')*)?';
913
+            $expectItem = '!(100-continue|'.$expectExtension.')!A';
917 914
 
918 915
             $pos    = 0;
919 916
             $length = strlen($headers['expect']);
@@ -933,7 +930,7 @@  discard block
 block discarded – undo
933 930
                 } else {
934 931
                     $pos += strlen($m[0]);
935 932
                     if (strcasecmp('100-continue', $m[0])) {
936
-                        $expectations[]  = $m[0];
933
+                        $expectations[] = $m[0];
937 934
                     }
938 935
                 }
939 936
             }
@@ -979,7 +976,7 @@  discard block
 block discarded – undo
979 976
             if (!$chunked) {
980 977
                 $this->socket->write($str);
981 978
             } else {
982
-                $this->socket->write(dechex(strlen($str)) . "\r\n{$str}\r\n");
979
+                $this->socket->write(dechex(strlen($str))."\r\n{$str}\r\n");
983 980
             }
984 981
             // Provide the length of written string to the observer, request #7630
985 982
             $this->request->setLastEvent('sentBodyPart', strlen($str));
@@ -1048,7 +1045,7 @@  discard block
 block discarded – undo
1048 1045
             // 3. ... If a message is received with both a
1049 1046
             // Transfer-Encoding header field and a Content-Length header field,
1050 1047
             // the latter MUST be ignored.
1051
-            $toRead = ($chunked || null === $length)? null: $length;
1048
+            $toRead = ($chunked || null === $length) ? null : $length;
1052 1049
             $this->chunkLength = 0;
1053 1050
 
1054 1051
             while (!$this->socket->eof() && (is_null($toRead) || 0 < $toRead)) {
Please login to merge, or discard this patch.
libs/PEAR.1.9.5/HTTP/Request2/MultipartBody.php 2 patches
Indentation   +211 added lines, -211 removed lines patch added patch discarded remove patch
@@ -37,232 +37,232 @@
 block discarded – undo
37 37
  */
38 38
 class HTTP_Request2_MultipartBody
39 39
 {
40
-    /**
41
-     * MIME boundary
42
-     * @var  string
43
-     */
44
-    private $_boundary;
40
+	/**
41
+	 * MIME boundary
42
+	 * @var  string
43
+	 */
44
+	private $_boundary;
45 45
 
46
-    /**
47
-     * Form parameters added via {@link HTTP_Request2::addPostParameter()}
48
-     * @var  array
49
-     */
50
-    private $_params = array();
46
+	/**
47
+	 * Form parameters added via {@link HTTP_Request2::addPostParameter()}
48
+	 * @var  array
49
+	 */
50
+	private $_params = array();
51 51
 
52
-    /**
53
-     * File uploads added via {@link HTTP_Request2::addUpload()}
54
-     * @var  array
55
-     */
56
-    private $_uploads = array();
52
+	/**
53
+	 * File uploads added via {@link HTTP_Request2::addUpload()}
54
+	 * @var  array
55
+	 */
56
+	private $_uploads = array();
57 57
 
58
-    /**
59
-     * Header for parts with parameters
60
-     * @var  string
61
-     */
62
-    private $_headerParam = "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n";
58
+	/**
59
+	 * Header for parts with parameters
60
+	 * @var  string
61
+	 */
62
+	private $_headerParam = "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n";
63 63
 
64
-    /**
65
-     * Header for parts with uploads
66
-     * @var  string
67
-     */
68
-    private $_headerUpload = "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n";
64
+	/**
65
+	 * Header for parts with uploads
66
+	 * @var  string
67
+	 */
68
+	private $_headerUpload = "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n";
69 69
 
70
-    /**
71
-     * Current position in parameter and upload arrays
72
-     *
73
-     * First number is index of "current" part, second number is position within
74
-     * "current" part
75
-     *
76
-     * @var  array
77
-     */
78
-    private $_pos = array(0, 0);
70
+	/**
71
+	 * Current position in parameter and upload arrays
72
+	 *
73
+	 * First number is index of "current" part, second number is position within
74
+	 * "current" part
75
+	 *
76
+	 * @var  array
77
+	 */
78
+	private $_pos = array(0, 0);
79 79
 
80 80
 
81
-    /**
82
-     * Constructor. Sets the arrays with POST data.
83
-     *
84
-     * @param array $params      values of form fields set via
85
-     *                           {@link HTTP_Request2::addPostParameter()}
86
-     * @param array $uploads     file uploads set via
87
-     *                           {@link HTTP_Request2::addUpload()}
88
-     * @param bool  $useBrackets whether to append brackets to array variable names
89
-     */
90
-    public function __construct(array $params, array $uploads, $useBrackets = true)
91
-    {
92
-        $this->_params = self::_flattenArray('', $params, $useBrackets);
93
-        foreach ($uploads as $fieldName => $f) {
94
-            if (!is_array($f['fp'])) {
95
-                $this->_uploads[] = $f + array('name' => $fieldName);
96
-            } else {
97
-                for ($i = 0; $i < count($f['fp']); $i++) {
98
-                    $upload = array(
99
-                        'name' => ($useBrackets? $fieldName . '[' . $i . ']': $fieldName)
100
-                    );
101
-                    foreach (array('fp', 'filename', 'size', 'type') as $key) {
102
-                        $upload[$key] = $f[$key][$i];
103
-                    }
104
-                    $this->_uploads[] = $upload;
105
-                }
106
-            }
107
-        }
108
-    }
81
+	/**
82
+	 * Constructor. Sets the arrays with POST data.
83
+	 *
84
+	 * @param array $params      values of form fields set via
85
+	 *                           {@link HTTP_Request2::addPostParameter()}
86
+	 * @param array $uploads     file uploads set via
87
+	 *                           {@link HTTP_Request2::addUpload()}
88
+	 * @param bool  $useBrackets whether to append brackets to array variable names
89
+	 */
90
+	public function __construct(array $params, array $uploads, $useBrackets = true)
91
+	{
92
+		$this->_params = self::_flattenArray('', $params, $useBrackets);
93
+		foreach ($uploads as $fieldName => $f) {
94
+			if (!is_array($f['fp'])) {
95
+				$this->_uploads[] = $f + array('name' => $fieldName);
96
+			} else {
97
+				for ($i = 0; $i < count($f['fp']); $i++) {
98
+					$upload = array(
99
+						'name' => ($useBrackets? $fieldName . '[' . $i . ']': $fieldName)
100
+					);
101
+					foreach (array('fp', 'filename', 'size', 'type') as $key) {
102
+						$upload[$key] = $f[$key][$i];
103
+					}
104
+					$this->_uploads[] = $upload;
105
+				}
106
+			}
107
+		}
108
+	}
109 109
 
110
-    /**
111
-     * Returns the length of the body to use in Content-Length header
112
-     *
113
-     * @return   integer
114
-     */
115
-    public function getLength()
116
-    {
117
-        $boundaryLength     = strlen($this->getBoundary());
118
-        $headerParamLength  = strlen($this->_headerParam) - 4 + $boundaryLength;
119
-        $headerUploadLength = strlen($this->_headerUpload) - 8 + $boundaryLength;
120
-        $length             = $boundaryLength + 6;
121
-        foreach ($this->_params as $p) {
122
-            $length += $headerParamLength + strlen($p[0]) + strlen($p[1]) + 2;
123
-        }
124
-        foreach ($this->_uploads as $u) {
125
-            $length += $headerUploadLength + strlen($u['name']) + strlen($u['type']) +
126
-                       strlen($u['filename']) + $u['size'] + 2;
127
-        }
128
-        return $length;
129
-    }
110
+	/**
111
+	 * Returns the length of the body to use in Content-Length header
112
+	 *
113
+	 * @return   integer
114
+	 */
115
+	public function getLength()
116
+	{
117
+		$boundaryLength     = strlen($this->getBoundary());
118
+		$headerParamLength  = strlen($this->_headerParam) - 4 + $boundaryLength;
119
+		$headerUploadLength = strlen($this->_headerUpload) - 8 + $boundaryLength;
120
+		$length             = $boundaryLength + 6;
121
+		foreach ($this->_params as $p) {
122
+			$length += $headerParamLength + strlen($p[0]) + strlen($p[1]) + 2;
123
+		}
124
+		foreach ($this->_uploads as $u) {
125
+			$length += $headerUploadLength + strlen($u['name']) + strlen($u['type']) +
126
+					   strlen($u['filename']) + $u['size'] + 2;
127
+		}
128
+		return $length;
129
+	}
130 130
 
131
-    /**
132
-     * Returns the boundary to use in Content-Type header
133
-     *
134
-     * @return   string
135
-     */
136
-    public function getBoundary()
137
-    {
138
-        if (empty($this->_boundary)) {
139
-            $this->_boundary = '--' . md5('PEAR-HTTP_Request2-' . microtime());
140
-        }
141
-        return $this->_boundary;
142
-    }
131
+	/**
132
+	 * Returns the boundary to use in Content-Type header
133
+	 *
134
+	 * @return   string
135
+	 */
136
+	public function getBoundary()
137
+	{
138
+		if (empty($this->_boundary)) {
139
+			$this->_boundary = '--' . md5('PEAR-HTTP_Request2-' . microtime());
140
+		}
141
+		return $this->_boundary;
142
+	}
143 143
 
144
-    /**
145
-     * Returns next chunk of request body
146
-     *
147
-     * @param integer $length Number of bytes to read
148
-     *
149
-     * @return   string  Up to $length bytes of data, empty string if at end
150
-     * @throws   HTTP_Request2_LogicException
151
-     */
152
-    public function read($length)
153
-    {
154
-        $ret         = '';
155
-        $boundary    = $this->getBoundary();
156
-        $paramCount  = count($this->_params);
157
-        $uploadCount = count($this->_uploads);
158
-        while ($length > 0 && $this->_pos[0] <= $paramCount + $uploadCount) {
159
-            $oldLength = $length;
160
-            if ($this->_pos[0] < $paramCount) {
161
-                $param = sprintf(
162
-                    $this->_headerParam, $boundary, $this->_params[$this->_pos[0]][0]
163
-                ) . $this->_params[$this->_pos[0]][1] . "\r\n";
164
-                $ret    .= substr($param, $this->_pos[1], $length);
165
-                $length -= min(strlen($param) - $this->_pos[1], $length);
144
+	/**
145
+	 * Returns next chunk of request body
146
+	 *
147
+	 * @param integer $length Number of bytes to read
148
+	 *
149
+	 * @return   string  Up to $length bytes of data, empty string if at end
150
+	 * @throws   HTTP_Request2_LogicException
151
+	 */
152
+	public function read($length)
153
+	{
154
+		$ret         = '';
155
+		$boundary    = $this->getBoundary();
156
+		$paramCount  = count($this->_params);
157
+		$uploadCount = count($this->_uploads);
158
+		while ($length > 0 && $this->_pos[0] <= $paramCount + $uploadCount) {
159
+			$oldLength = $length;
160
+			if ($this->_pos[0] < $paramCount) {
161
+				$param = sprintf(
162
+					$this->_headerParam, $boundary, $this->_params[$this->_pos[0]][0]
163
+				) . $this->_params[$this->_pos[0]][1] . "\r\n";
164
+				$ret    .= substr($param, $this->_pos[1], $length);
165
+				$length -= min(strlen($param) - $this->_pos[1], $length);
166 166
 
167
-            } elseif ($this->_pos[0] < $paramCount + $uploadCount) {
168
-                $pos    = $this->_pos[0] - $paramCount;
169
-                $header = sprintf(
170
-                    $this->_headerUpload, $boundary, $this->_uploads[$pos]['name'],
171
-                    $this->_uploads[$pos]['filename'], $this->_uploads[$pos]['type']
172
-                );
173
-                if ($this->_pos[1] < strlen($header)) {
174
-                    $ret    .= substr($header, $this->_pos[1], $length);
175
-                    $length -= min(strlen($header) - $this->_pos[1], $length);
176
-                }
177
-                $filePos  = max(0, $this->_pos[1] - strlen($header));
178
-                if ($filePos < $this->_uploads[$pos]['size']) {
179
-                    while ($length > 0 && !feof($this->_uploads[$pos]['fp'])) {
180
-                        if (false === ($chunk = fread($this->_uploads[$pos]['fp'], $length))) {
181
-                            throw new HTTP_Request2_LogicException(
182
-                                'Failed reading file upload', HTTP_Request2_Exception::READ_ERROR
183
-                            );
184
-                        }
185
-                        $ret    .= $chunk;
186
-                        $length -= strlen($chunk);
187
-                    }
188
-                }
189
-                if ($length > 0) {
190
-                    $start   = $this->_pos[1] + ($oldLength - $length) -
191
-                               strlen($header) - $this->_uploads[$pos]['size'];
192
-                    $ret    .= substr("\r\n", $start, $length);
193
-                    $length -= min(2 - $start, $length);
194
-                }
167
+			} elseif ($this->_pos[0] < $paramCount + $uploadCount) {
168
+				$pos    = $this->_pos[0] - $paramCount;
169
+				$header = sprintf(
170
+					$this->_headerUpload, $boundary, $this->_uploads[$pos]['name'],
171
+					$this->_uploads[$pos]['filename'], $this->_uploads[$pos]['type']
172
+				);
173
+				if ($this->_pos[1] < strlen($header)) {
174
+					$ret    .= substr($header, $this->_pos[1], $length);
175
+					$length -= min(strlen($header) - $this->_pos[1], $length);
176
+				}
177
+				$filePos  = max(0, $this->_pos[1] - strlen($header));
178
+				if ($filePos < $this->_uploads[$pos]['size']) {
179
+					while ($length > 0 && !feof($this->_uploads[$pos]['fp'])) {
180
+						if (false === ($chunk = fread($this->_uploads[$pos]['fp'], $length))) {
181
+							throw new HTTP_Request2_LogicException(
182
+								'Failed reading file upload', HTTP_Request2_Exception::READ_ERROR
183
+							);
184
+						}
185
+						$ret    .= $chunk;
186
+						$length -= strlen($chunk);
187
+					}
188
+				}
189
+				if ($length > 0) {
190
+					$start   = $this->_pos[1] + ($oldLength - $length) -
191
+							   strlen($header) - $this->_uploads[$pos]['size'];
192
+					$ret    .= substr("\r\n", $start, $length);
193
+					$length -= min(2 - $start, $length);
194
+				}
195 195
 
196
-            } else {
197
-                $closing  = '--' . $boundary . "--\r\n";
198
-                $ret     .= substr($closing, $this->_pos[1], $length);
199
-                $length  -= min(strlen($closing) - $this->_pos[1], $length);
200
-            }
201
-            if ($length > 0) {
202
-                $this->_pos     = array($this->_pos[0] + 1, 0);
203
-            } else {
204
-                $this->_pos[1] += $oldLength;
205
-            }
206
-        }
207
-        return $ret;
208
-    }
196
+			} else {
197
+				$closing  = '--' . $boundary . "--\r\n";
198
+				$ret     .= substr($closing, $this->_pos[1], $length);
199
+				$length  -= min(strlen($closing) - $this->_pos[1], $length);
200
+			}
201
+			if ($length > 0) {
202
+				$this->_pos     = array($this->_pos[0] + 1, 0);
203
+			} else {
204
+				$this->_pos[1] += $oldLength;
205
+			}
206
+		}
207
+		return $ret;
208
+	}
209 209
 
210
-    /**
211
-     * Sets the current position to the start of the body
212
-     *
213
-     * This allows reusing the same body in another request
214
-     */
215
-    public function rewind()
216
-    {
217
-        $this->_pos = array(0, 0);
218
-        foreach ($this->_uploads as $u) {
219
-            rewind($u['fp']);
220
-        }
221
-    }
210
+	/**
211
+	 * Sets the current position to the start of the body
212
+	 *
213
+	 * This allows reusing the same body in another request
214
+	 */
215
+	public function rewind()
216
+	{
217
+		$this->_pos = array(0, 0);
218
+		foreach ($this->_uploads as $u) {
219
+			rewind($u['fp']);
220
+		}
221
+	}
222 222
 
223
-    /**
224
-     * Returns the body as string
225
-     *
226
-     * Note that it reads all file uploads into memory so it is a good idea not
227
-     * to use this method with large file uploads and rely on read() instead.
228
-     *
229
-     * @return   string
230
-     */
231
-    public function __toString()
232
-    {
233
-        $this->rewind();
234
-        return $this->read($this->getLength());
235
-    }
223
+	/**
224
+	 * Returns the body as string
225
+	 *
226
+	 * Note that it reads all file uploads into memory so it is a good idea not
227
+	 * to use this method with large file uploads and rely on read() instead.
228
+	 *
229
+	 * @return   string
230
+	 */
231
+	public function __toString()
232
+	{
233
+		$this->rewind();
234
+		return $this->read($this->getLength());
235
+	}
236 236
 
237 237
 
238
-    /**
239
-     * Helper function to change the (probably multidimensional) associative array
240
-     * into the simple one.
241
-     *
242
-     * @param string $name        name for item
243
-     * @param mixed  $values      item's values
244
-     * @param bool   $useBrackets whether to append [] to array variables' names
245
-     *
246
-     * @return   array   array with the following items: array('item name', 'item value');
247
-     */
248
-    private static function _flattenArray($name, $values, $useBrackets)
249
-    {
250
-        if (!is_array($values)) {
251
-            return array(array($name, $values));
252
-        } else {
253
-            $ret = array();
254
-            foreach ($values as $k => $v) {
255
-                if (empty($name)) {
256
-                    $newName = $k;
257
-                } elseif ($useBrackets) {
258
-                    $newName = $name . '[' . $k . ']';
259
-                } else {
260
-                    $newName = $name;
261
-                }
262
-                $ret = array_merge($ret, self::_flattenArray($newName, $v, $useBrackets));
263
-            }
264
-            return $ret;
265
-        }
266
-    }
238
+	/**
239
+	 * Helper function to change the (probably multidimensional) associative array
240
+	 * into the simple one.
241
+	 *
242
+	 * @param string $name        name for item
243
+	 * @param mixed  $values      item's values
244
+	 * @param bool   $useBrackets whether to append [] to array variables' names
245
+	 *
246
+	 * @return   array   array with the following items: array('item name', 'item value');
247
+	 */
248
+	private static function _flattenArray($name, $values, $useBrackets)
249
+	{
250
+		if (!is_array($values)) {
251
+			return array(array($name, $values));
252
+		} else {
253
+			$ret = array();
254
+			foreach ($values as $k => $v) {
255
+				if (empty($name)) {
256
+					$newName = $k;
257
+				} elseif ($useBrackets) {
258
+					$newName = $name . '[' . $k . ']';
259
+				} else {
260
+					$newName = $name;
261
+				}
262
+				$ret = array_merge($ret, self::_flattenArray($newName, $v, $useBrackets));
263
+			}
264
+			return $ret;
265
+		}
266
+	}
267 267
 }
268 268
 ?>
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -96,7 +96,7 @@  discard block
 block discarded – undo
96 96
             } else {
97 97
                 for ($i = 0; $i < count($f['fp']); $i++) {
98 98
                     $upload = array(
99
-                        'name' => ($useBrackets? $fieldName . '[' . $i . ']': $fieldName)
99
+                        'name' => ($useBrackets ? $fieldName.'['.$i.']' : $fieldName)
100 100
                     );
101 101
                     foreach (array('fp', 'filename', 'size', 'type') as $key) {
102 102
                         $upload[$key] = $f[$key][$i];
@@ -136,7 +136,7 @@  discard block
 block discarded – undo
136 136
     public function getBoundary()
137 137
     {
138 138
         if (empty($this->_boundary)) {
139
-            $this->_boundary = '--' . md5('PEAR-HTTP_Request2-' . microtime());
139
+            $this->_boundary = '--'.md5('PEAR-HTTP_Request2-'.microtime());
140 140
         }
141 141
         return $this->_boundary;
142 142
     }
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
             if ($this->_pos[0] < $paramCount) {
161 161
                 $param = sprintf(
162 162
                     $this->_headerParam, $boundary, $this->_params[$this->_pos[0]][0]
163
-                ) . $this->_params[$this->_pos[0]][1] . "\r\n";
163
+                ).$this->_params[$this->_pos[0]][1]."\r\n";
164 164
                 $ret    .= substr($param, $this->_pos[1], $length);
165 165
                 $length -= min(strlen($param) - $this->_pos[1], $length);
166 166
 
@@ -174,7 +174,7 @@  discard block
 block discarded – undo
174 174
                     $ret    .= substr($header, $this->_pos[1], $length);
175 175
                     $length -= min(strlen($header) - $this->_pos[1], $length);
176 176
                 }
177
-                $filePos  = max(0, $this->_pos[1] - strlen($header));
177
+                $filePos = max(0, $this->_pos[1] - strlen($header));
178 178
                 if ($filePos < $this->_uploads[$pos]['size']) {
179 179
                     while ($length > 0 && !feof($this->_uploads[$pos]['fp'])) {
180 180
                         if (false === ($chunk = fread($this->_uploads[$pos]['fp'], $length))) {
@@ -194,7 +194,7 @@  discard block
 block discarded – undo
194 194
                 }
195 195
 
196 196
             } else {
197
-                $closing  = '--' . $boundary . "--\r\n";
197
+                $closing  = '--'.$boundary."--\r\n";
198 198
                 $ret     .= substr($closing, $this->_pos[1], $length);
199 199
                 $length  -= min(strlen($closing) - $this->_pos[1], $length);
200 200
             }
@@ -255,7 +255,7 @@  discard block
 block discarded – undo
255 255
                 if (empty($name)) {
256 256
                     $newName = $k;
257 257
                 } elseif ($useBrackets) {
258
-                    $newName = $name . '[' . $k . ']';
258
+                    $newName = $name.'['.$k.']';
259 259
                 } else {
260 260
                     $newName = $name;
261 261
                 }
Please login to merge, or discard this patch.
libs/PEAR.1.9.5/HTTP/Request2/Observer/Log.php 3 patches
Switch Indentation   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -134,36 +134,36 @@
 block discarded – undo
134 134
         }
135 135
 
136 136
         switch ($event['name']) {
137
-        case 'connect':
138
-            $this->log('* Connected to ' . $event['data']);
139
-            break;
140
-        case 'sentHeaders':
141
-            $headers = explode("\r\n", $event['data']);
142
-            array_pop($headers);
143
-            foreach ($headers as $header) {
144
-                $this->log('> ' . $header);
145
-            }
146
-            break;
147
-        case 'sentBody':
148
-            $this->log('> ' . $event['data'] . ' byte(s) sent');
149
-            break;
150
-        case 'receivedHeaders':
151
-            $this->log(sprintf(
152
-                '< HTTP/%s %s %s', $event['data']->getVersion(),
153
-                $event['data']->getStatus(), $event['data']->getReasonPhrase()
154
-            ));
155
-            $headers = $event['data']->getHeader();
156
-            foreach ($headers as $key => $val) {
157
-                $this->log('< ' . $key . ': ' . $val);
158
-            }
159
-            $this->log('< ');
160
-            break;
161
-        case 'receivedBody':
162
-            $this->log($event['data']->getBody());
163
-            break;
164
-        case 'disconnect':
165
-            $this->log('* Disconnected');
166
-            break;
137
+        	case 'connect':
138
+            	$this->log('* Connected to ' . $event['data']);
139
+            	break;
140
+        	case 'sentHeaders':
141
+            	$headers = explode("\r\n", $event['data']);
142
+            	array_pop($headers);
143
+            	foreach ($headers as $header) {
144
+                	$this->log('> ' . $header);
145
+            	}
146
+            	break;
147
+        	case 'sentBody':
148
+            	$this->log('> ' . $event['data'] . ' byte(s) sent');
149
+            	break;
150
+        	case 'receivedHeaders':
151
+            	$this->log(sprintf(
152
+                	'< HTTP/%s %s %s', $event['data']->getVersion(),
153
+                	$event['data']->getStatus(), $event['data']->getReasonPhrase()
154
+            	));
155
+            	$headers = $event['data']->getHeader();
156
+            	foreach ($headers as $key => $val) {
157
+                	$this->log('< ' . $key . ': ' . $val);
158
+            	}
159
+            	$this->log('< ');
160
+            	break;
161
+        	case 'receivedBody':
162
+            	$this->log($event['data']->getBody());
163
+            	break;
164
+        	case 'disconnect':
165
+            	$this->log('* Disconnected');
166
+            	break;
167 167
         }
168 168
     }
169 169
 
Please login to merge, or discard this patch.
Indentation   +108 added lines, -108 removed lines patch added patch discarded remove patch
@@ -69,124 +69,124 @@
 block discarded – undo
69 69
  */
70 70
 class HTTP_Request2_Observer_Log implements SplObserver
71 71
 {
72
-    // properties {{{
72
+	// properties {{{
73 73
 
74
-    /**
75
-     * The log target, it can be a a resource or a PEAR Log instance.
76
-     *
77
-     * @var resource|Log $target
78
-     */
79
-    protected $target = null;
74
+	/**
75
+	 * The log target, it can be a a resource or a PEAR Log instance.
76
+	 *
77
+	 * @var resource|Log $target
78
+	 */
79
+	protected $target = null;
80 80
 
81
-    /**
82
-     * The events to log.
83
-     *
84
-     * @var array $events
85
-     */
86
-    public $events = array(
87
-        'connect',
88
-        'sentHeaders',
89
-        'sentBody',
90
-        'receivedHeaders',
91
-        'receivedBody',
92
-        'disconnect',
93
-    );
81
+	/**
82
+	 * The events to log.
83
+	 *
84
+	 * @var array $events
85
+	 */
86
+	public $events = array(
87
+		'connect',
88
+		'sentHeaders',
89
+		'sentBody',
90
+		'receivedHeaders',
91
+		'receivedBody',
92
+		'disconnect',
93
+	);
94 94
 
95
-    // }}}
96
-    // __construct() {{{
95
+	// }}}
96
+	// __construct() {{{
97 97
 
98
-    /**
99
-     * Constructor.
100
-     *
101
-     * @param mixed $target Can be a file path (default: php://output), a resource,
102
-     *                      or an instance of the PEAR Log class.
103
-     * @param array $events Array of events to listen to (default: all events)
104
-     *
105
-     * @return void
106
-     */
107
-    public function __construct($target = 'php://output', array $events = array())
108
-    {
109
-        if (!empty($events)) {
110
-            $this->events = $events;
111
-        }
112
-        if (is_resource($target) || $target instanceof Log) {
113
-            $this->target = $target;
114
-        } elseif (false === ($this->target = @fopen($target, 'ab'))) {
115
-            throw new HTTP_Request2_Exception("Unable to open '{$target}'");
116
-        }
117
-    }
98
+	/**
99
+	 * Constructor.
100
+	 *
101
+	 * @param mixed $target Can be a file path (default: php://output), a resource,
102
+	 *                      or an instance of the PEAR Log class.
103
+	 * @param array $events Array of events to listen to (default: all events)
104
+	 *
105
+	 * @return void
106
+	 */
107
+	public function __construct($target = 'php://output', array $events = array())
108
+	{
109
+		if (!empty($events)) {
110
+			$this->events = $events;
111
+		}
112
+		if (is_resource($target) || $target instanceof Log) {
113
+			$this->target = $target;
114
+		} elseif (false === ($this->target = @fopen($target, 'ab'))) {
115
+			throw new HTTP_Request2_Exception("Unable to open '{$target}'");
116
+		}
117
+	}
118 118
 
119
-    // }}}
120
-    // update() {{{
119
+	// }}}
120
+	// update() {{{
121 121
 
122
-    /**
123
-     * Called when the request notifies us of an event.
124
-     *
125
-     * @param HTTP_Request2 $subject The HTTP_Request2 instance
126
-     *
127
-     * @return void
128
-     */
129
-    public function update(SplSubject $subject)
130
-    {
131
-        $event = $subject->getLastEvent();
132
-        if (!in_array($event['name'], $this->events)) {
133
-            return;
134
-        }
122
+	/**
123
+	 * Called when the request notifies us of an event.
124
+	 *
125
+	 * @param HTTP_Request2 $subject The HTTP_Request2 instance
126
+	 *
127
+	 * @return void
128
+	 */
129
+	public function update(SplSubject $subject)
130
+	{
131
+		$event = $subject->getLastEvent();
132
+		if (!in_array($event['name'], $this->events)) {
133
+			return;
134
+		}
135 135
 
136
-        switch ($event['name']) {
137
-        case 'connect':
138
-            $this->log('* Connected to ' . $event['data']);
139
-            break;
140
-        case 'sentHeaders':
141
-            $headers = explode("\r\n", $event['data']);
142
-            array_pop($headers);
143
-            foreach ($headers as $header) {
144
-                $this->log('> ' . $header);
145
-            }
146
-            break;
147
-        case 'sentBody':
148
-            $this->log('> ' . $event['data'] . ' byte(s) sent');
149
-            break;
150
-        case 'receivedHeaders':
151
-            $this->log(sprintf(
152
-                '< HTTP/%s %s %s', $event['data']->getVersion(),
153
-                $event['data']->getStatus(), $event['data']->getReasonPhrase()
154
-            ));
155
-            $headers = $event['data']->getHeader();
156
-            foreach ($headers as $key => $val) {
157
-                $this->log('< ' . $key . ': ' . $val);
158
-            }
159
-            $this->log('< ');
160
-            break;
161
-        case 'receivedBody':
162
-            $this->log($event['data']->getBody());
163
-            break;
164
-        case 'disconnect':
165
-            $this->log('* Disconnected');
166
-            break;
167
-        }
168
-    }
136
+		switch ($event['name']) {
137
+		case 'connect':
138
+			$this->log('* Connected to ' . $event['data']);
139
+			break;
140
+		case 'sentHeaders':
141
+			$headers = explode("\r\n", $event['data']);
142
+			array_pop($headers);
143
+			foreach ($headers as $header) {
144
+				$this->log('> ' . $header);
145
+			}
146
+			break;
147
+		case 'sentBody':
148
+			$this->log('> ' . $event['data'] . ' byte(s) sent');
149
+			break;
150
+		case 'receivedHeaders':
151
+			$this->log(sprintf(
152
+				'< HTTP/%s %s %s', $event['data']->getVersion(),
153
+				$event['data']->getStatus(), $event['data']->getReasonPhrase()
154
+			));
155
+			$headers = $event['data']->getHeader();
156
+			foreach ($headers as $key => $val) {
157
+				$this->log('< ' . $key . ': ' . $val);
158
+			}
159
+			$this->log('< ');
160
+			break;
161
+		case 'receivedBody':
162
+			$this->log($event['data']->getBody());
163
+			break;
164
+		case 'disconnect':
165
+			$this->log('* Disconnected');
166
+			break;
167
+		}
168
+	}
169 169
 
170
-    // }}}
171
-    // log() {{{
170
+	// }}}
171
+	// log() {{{
172 172
 
173
-    /**
174
-     * Logs the given message to the configured target.
175
-     *
176
-     * @param string $message Message to display
177
-     *
178
-     * @return void
179
-     */
180
-    protected function log($message)
181
-    {
182
-        if ($this->target instanceof Log) {
183
-            $this->target->debug($message);
184
-        } elseif (is_resource($this->target)) {
185
-            fwrite($this->target, $message . "\r\n");
186
-        }
187
-    }
173
+	/**
174
+	 * Logs the given message to the configured target.
175
+	 *
176
+	 * @param string $message Message to display
177
+	 *
178
+	 * @return void
179
+	 */
180
+	protected function log($message)
181
+	{
182
+		if ($this->target instanceof Log) {
183
+			$this->target->debug($message);
184
+		} elseif (is_resource($this->target)) {
185
+			fwrite($this->target, $message . "\r\n");
186
+		}
187
+	}
188 188
 
189
-    // }}}
189
+	// }}}
190 190
 }
191 191
 
192 192
 ?>
193 193
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -135,17 +135,17 @@  discard block
 block discarded – undo
135 135
 
136 136
         switch ($event['name']) {
137 137
         case 'connect':
138
-            $this->log('* Connected to ' . $event['data']);
138
+            $this->log('* Connected to '.$event['data']);
139 139
             break;
140 140
         case 'sentHeaders':
141 141
             $headers = explode("\r\n", $event['data']);
142 142
             array_pop($headers);
143 143
             foreach ($headers as $header) {
144
-                $this->log('> ' . $header);
144
+                $this->log('> '.$header);
145 145
             }
146 146
             break;
147 147
         case 'sentBody':
148
-            $this->log('> ' . $event['data'] . ' byte(s) sent');
148
+            $this->log('> '.$event['data'].' byte(s) sent');
149 149
             break;
150 150
         case 'receivedHeaders':
151 151
             $this->log(sprintf(
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
             ));
155 155
             $headers = $event['data']->getHeader();
156 156
             foreach ($headers as $key => $val) {
157
-                $this->log('< ' . $key . ': ' . $val);
157
+                $this->log('< '.$key.': '.$val);
158 158
             }
159 159
             $this->log('< ');
160 160
             break;
@@ -182,7 +182,7 @@  discard block
 block discarded – undo
182 182
         if ($this->target instanceof Log) {
183 183
             $this->target->debug($message);
184 184
         } elseif (is_resource($this->target)) {
185
-            fwrite($this->target, $message . "\r\n");
185
+            fwrite($this->target, $message."\r\n");
186 186
         }
187 187
     }
188 188
 
Please login to merge, or discard this patch.
libs/PEAR.1.9.5/HTTP/Request2/Response.php 3 patches
Indentation   +574 added lines, -574 removed lines patch added patch discarded remove patch
@@ -53,579 +53,579 @@
 block discarded – undo
53 53
  */
54 54
 class HTTP_Request2_Response
55 55
 {
56
-    /**
57
-     * HTTP protocol version (e.g. 1.0, 1.1)
58
-     * @var  string
59
-     */
60
-    protected $version;
61
-
62
-    /**
63
-     * Status code
64
-     * @var  integer
65
-     * @link http://tools.ietf.org/html/rfc2616#section-6.1.1
66
-     */
67
-    protected $code;
68
-
69
-    /**
70
-     * Reason phrase
71
-     * @var  string
72
-     * @link http://tools.ietf.org/html/rfc2616#section-6.1.1
73
-     */
74
-    protected $reasonPhrase;
75
-
76
-    /**
77
-     * Effective URL (may be different from original request URL in case of redirects)
78
-     * @var  string
79
-     */
80
-    protected $effectiveUrl;
81
-
82
-    /**
83
-     * Associative array of response headers
84
-     * @var  array
85
-     */
86
-    protected $headers = array();
87
-
88
-    /**
89
-     * Cookies set in the response
90
-     * @var  array
91
-     */
92
-    protected $cookies = array();
93
-
94
-    /**
95
-     * Name of last header processed by parseHederLine()
96
-     *
97
-     * Used to handle the headers that span multiple lines
98
-     *
99
-     * @var  string
100
-     */
101
-    protected $lastHeader = null;
102
-
103
-    /**
104
-     * Response body
105
-     * @var  string
106
-     */
107
-    protected $body = '';
108
-
109
-    /**
110
-     * Whether the body is still encoded by Content-Encoding
111
-     *
112
-     * cURL provides the decoded body to the callback; if we are reading from
113
-     * socket the body is still gzipped / deflated
114
-     *
115
-     * @var  bool
116
-     */
117
-    protected $bodyEncoded;
118
-
119
-    /**
120
-     * Associative array of HTTP status code / reason phrase.
121
-     *
122
-     * @var  array
123
-     * @link http://tools.ietf.org/html/rfc2616#section-10
124
-     */
125
-    protected static $phrases = array(
126
-
127
-        // 1xx: Informational - Request received, continuing process
128
-        100 => 'Continue',
129
-        101 => 'Switching Protocols',
130
-
131
-        // 2xx: Success - The action was successfully received, understood and
132
-        // accepted
133
-        200 => 'OK',
134
-        201 => 'Created',
135
-        202 => 'Accepted',
136
-        203 => 'Non-Authoritative Information',
137
-        204 => 'No Content',
138
-        205 => 'Reset Content',
139
-        206 => 'Partial Content',
140
-
141
-        // 3xx: Redirection - Further action must be taken in order to complete
142
-        // the request
143
-        300 => 'Multiple Choices',
144
-        301 => 'Moved Permanently',
145
-        302 => 'Found',  // 1.1
146
-        303 => 'See Other',
147
-        304 => 'Not Modified',
148
-        305 => 'Use Proxy',
149
-        307 => 'Temporary Redirect',
150
-
151
-        // 4xx: Client Error - The request contains bad syntax or cannot be
152
-        // fulfilled
153
-        400 => 'Bad Request',
154
-        401 => 'Unauthorized',
155
-        402 => 'Payment Required',
156
-        403 => 'Forbidden',
157
-        404 => 'Not Found',
158
-        405 => 'Method Not Allowed',
159
-        406 => 'Not Acceptable',
160
-        407 => 'Proxy Authentication Required',
161
-        408 => 'Request Timeout',
162
-        409 => 'Conflict',
163
-        410 => 'Gone',
164
-        411 => 'Length Required',
165
-        412 => 'Precondition Failed',
166
-        413 => 'Request Entity Too Large',
167
-        414 => 'Request-URI Too Long',
168
-        415 => 'Unsupported Media Type',
169
-        416 => 'Requested Range Not Satisfiable',
170
-        417 => 'Expectation Failed',
171
-
172
-        // 5xx: Server Error - The server failed to fulfill an apparently
173
-        // valid request
174
-        500 => 'Internal Server Error',
175
-        501 => 'Not Implemented',
176
-        502 => 'Bad Gateway',
177
-        503 => 'Service Unavailable',
178
-        504 => 'Gateway Timeout',
179
-        505 => 'HTTP Version Not Supported',
180
-        509 => 'Bandwidth Limit Exceeded',
181
-
182
-    );
183
-
184
-    /**
185
-     * Returns the default reason phrase for the given code or all reason phrases
186
-     *
187
-     * @param int $code Response code
188
-     *
189
-     * @return string|array|null Default reason phrase for $code if $code is given
190
-     *                           (null if no phrase is available), array of all
191
-     *                           reason phrases if $code is null
192
-     * @link   http://pear.php.net/bugs/18716
193
-     */
194
-    public static function getDefaultReasonPhrase($code = null)
195
-    {
196
-        if (null === $code) {
197
-            return self::$phrases;
198
-        } else {
199
-            return isset(self::$phrases[$code]) ? self::$phrases[$code] : null;
200
-        }
201
-    }
202
-
203
-    /**
204
-     * Constructor, parses the response status line
205
-     *
206
-     * @param string $statusLine   Response status line (e.g. "HTTP/1.1 200 OK")
207
-     * @param bool   $bodyEncoded  Whether body is still encoded by Content-Encoding
208
-     * @param string $effectiveUrl Effective URL of the response
209
-     *
210
-     * @throws   HTTP_Request2_MessageException if status line is invalid according to spec
211
-     */
212
-    public function __construct($statusLine, $bodyEncoded = true, $effectiveUrl = null)
213
-    {
214
-        if (!preg_match('!^HTTP/(\d\.\d) (\d{3})(?: (.+))?!', $statusLine, $m)) {
215
-            throw new HTTP_Request2_MessageException(
216
-                "Malformed response: {$statusLine}",
217
-                HTTP_Request2_Exception::MALFORMED_RESPONSE
218
-            );
219
-        }
220
-        $this->version      = $m[1];
221
-        $this->code         = intval($m[2]);
222
-        $this->reasonPhrase = !empty($m[3]) ? trim($m[3]) : self::getDefaultReasonPhrase($this->code);
223
-        $this->bodyEncoded  = (bool)$bodyEncoded;
224
-        $this->effectiveUrl = (string)$effectiveUrl;
225
-    }
226
-
227
-    /**
228
-     * Parses the line from HTTP response filling $headers array
229
-     *
230
-     * The method should be called after reading the line from socket or receiving
231
-     * it into cURL callback. Passing an empty string here indicates the end of
232
-     * response headers and triggers additional processing, so be sure to pass an
233
-     * empty string in the end.
234
-     *
235
-     * @param string $headerLine Line from HTTP response
236
-     */
237
-    public function parseHeaderLine($headerLine)
238
-    {
239
-        $headerLine = trim($headerLine, "\r\n");
240
-
241
-        if ('' == $headerLine) {
242
-            // empty string signals the end of headers, process the received ones
243
-            if (!empty($this->headers['set-cookie'])) {
244
-                $cookies = is_array($this->headers['set-cookie'])?
245
-                           $this->headers['set-cookie']:
246
-                           array($this->headers['set-cookie']);
247
-                foreach ($cookies as $cookieString) {
248
-                    $this->parseCookie($cookieString);
249
-                }
250
-                unset($this->headers['set-cookie']);
251
-            }
252
-            foreach (array_keys($this->headers) as $k) {
253
-                if (is_array($this->headers[$k])) {
254
-                    $this->headers[$k] = implode(', ', $this->headers[$k]);
255
-                }
256
-            }
257
-
258
-        } elseif (preg_match('!^([^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+):(.+)$!', $headerLine, $m)) {
259
-            // string of the form header-name: header value
260
-            $name  = strtolower($m[1]);
261
-            $value = trim($m[2]);
262
-            if (empty($this->headers[$name])) {
263
-                $this->headers[$name] = $value;
264
-            } else {
265
-                if (!is_array($this->headers[$name])) {
266
-                    $this->headers[$name] = array($this->headers[$name]);
267
-                }
268
-                $this->headers[$name][] = $value;
269
-            }
270
-            $this->lastHeader = $name;
271
-
272
-        } elseif (preg_match('!^\s+(.+)$!', $headerLine, $m) && $this->lastHeader) {
273
-            // continuation of a previous header
274
-            if (!is_array($this->headers[$this->lastHeader])) {
275
-                $this->headers[$this->lastHeader] .= ' ' . trim($m[1]);
276
-            } else {
277
-                $key = count($this->headers[$this->lastHeader]) - 1;
278
-                $this->headers[$this->lastHeader][$key] .= ' ' . trim($m[1]);
279
-            }
280
-        }
281
-    }
282
-
283
-    /**
284
-     * Parses a Set-Cookie header to fill $cookies array
285
-     *
286
-     * @param string $cookieString value of Set-Cookie header
287
-     *
288
-     * @link     http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html
289
-     */
290
-    protected function parseCookie($cookieString)
291
-    {
292
-        $cookie = array(
293
-            'expires' => null,
294
-            'domain'  => null,
295
-            'path'    => null,
296
-            'secure'  => false
297
-        );
298
-
299
-        if (!strpos($cookieString, ';')) {
300
-            // Only a name=value pair
301
-            $pos = strpos($cookieString, '=');
302
-            $cookie['name']  = trim(substr($cookieString, 0, $pos));
303
-            $cookie['value'] = trim(substr($cookieString, $pos + 1));
304
-
305
-        } else {
306
-            // Some optional parameters are supplied
307
-            $elements = explode(';', $cookieString);
308
-            $pos = strpos($elements[0], '=');
309
-            $cookie['name']  = trim(substr($elements[0], 0, $pos));
310
-            $cookie['value'] = trim(substr($elements[0], $pos + 1));
311
-
312
-            for ($i = 1; $i < count($elements); $i++) {
313
-                if (false === strpos($elements[$i], '=')) {
314
-                    $elName  = trim($elements[$i]);
315
-                    $elValue = null;
316
-                } else {
317
-                    list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i]));
318
-                }
319
-                $elName = strtolower($elName);
320
-                if ('secure' == $elName) {
321
-                    $cookie['secure'] = true;
322
-                } elseif ('expires' == $elName) {
323
-                    $cookie['expires'] = str_replace('"', '', $elValue);
324
-                } elseif ('path' == $elName || 'domain' == $elName) {
325
-                    $cookie[$elName] = urldecode($elValue);
326
-                } else {
327
-                    $cookie[$elName] = $elValue;
328
-                }
329
-            }
330
-        }
331
-        $this->cookies[] = $cookie;
332
-    }
333
-
334
-    /**
335
-     * Appends a string to the response body
336
-     *
337
-     * @param string $bodyChunk part of response body
338
-     */
339
-    public function appendBody($bodyChunk)
340
-    {
341
-        $this->body .= $bodyChunk;
342
-    }
343
-
344
-    /**
345
-     * Returns the effective URL of the response
346
-     *
347
-     * This may be different from the request URL if redirects were followed.
348
-     *
349
-     * @return string
350
-     * @link   http://pear.php.net/bugs/bug.php?id=18412
351
-     */
352
-    public function getEffectiveUrl()
353
-    {
354
-        return $this->effectiveUrl;
355
-    }
356
-
357
-    /**
358
-     * Returns the status code
359
-     *
360
-     * @return   integer
361
-     */
362
-    public function getStatus()
363
-    {
364
-        return $this->code;
365
-    }
366
-
367
-    /**
368
-     * Returns the reason phrase
369
-     *
370
-     * @return   string
371
-     */
372
-    public function getReasonPhrase()
373
-    {
374
-        return $this->reasonPhrase;
375
-    }
376
-
377
-    /**
378
-     * Whether response is a redirect that can be automatically handled by HTTP_Request2
379
-     *
380
-     * @return   bool
381
-     */
382
-    public function isRedirect()
383
-    {
384
-        return in_array($this->code, array(300, 301, 302, 303, 307))
385
-               && isset($this->headers['location']);
386
-    }
387
-
388
-    /**
389
-     * Returns either the named header or all response headers
390
-     *
391
-     * @param string $headerName Name of header to return
392
-     *
393
-     * @return   string|array    Value of $headerName header (null if header is
394
-     *                           not present), array of all response headers if
395
-     *                           $headerName is null
396
-     */
397
-    public function getHeader($headerName = null)
398
-    {
399
-        if (null === $headerName) {
400
-            return $this->headers;
401
-        } else {
402
-            $headerName = strtolower($headerName);
403
-            return isset($this->headers[$headerName])? $this->headers[$headerName]: null;
404
-        }
405
-    }
406
-
407
-    /**
408
-     * Returns cookies set in response
409
-     *
410
-     * @return   array
411
-     */
412
-    public function getCookies()
413
-    {
414
-        return $this->cookies;
415
-    }
416
-
417
-    /**
418
-     * Returns the body of the response
419
-     *
420
-     * @return   string
421
-     * @throws   HTTP_Request2_Exception if body cannot be decoded
422
-     */
423
-    public function getBody()
424
-    {
425
-        if (0 == strlen($this->body) || !$this->bodyEncoded
426
-            || !in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate'))
427
-        ) {
428
-            return $this->body;
429
-
430
-        } else {
431
-            if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
432
-                $oldEncoding = mb_internal_encoding();
433
-                mb_internal_encoding('8bit');
434
-            }
435
-
436
-            try {
437
-                switch (strtolower($this->getHeader('content-encoding'))) {
438
-                case 'gzip':
439
-                    $decoded = self::decodeGzip($this->body);
440
-                    break;
441
-                case 'deflate':
442
-                    $decoded = self::decodeDeflate($this->body);
443
-                }
444
-            } catch (Exception $e) {
445
-            }
446
-
447
-            if (!empty($oldEncoding)) {
448
-                mb_internal_encoding($oldEncoding);
449
-            }
450
-            if (!empty($e)) {
451
-                throw $e;
452
-            }
453
-            return $decoded;
454
-        }
455
-    }
456
-
457
-    /**
458
-     * Get the HTTP version of the response
459
-     *
460
-     * @return   string
461
-     */
462
-    public function getVersion()
463
-    {
464
-        return $this->version;
465
-    }
466
-
467
-    /**
468
-     * Decodes the message-body encoded by gzip
469
-     *
470
-     * The real decoding work is done by gzinflate() built-in function, this
471
-     * method only parses the header and checks data for compliance with
472
-     * RFC 1952
473
-     *
474
-     * @param string $data gzip-encoded data
475
-     *
476
-     * @return   string  decoded data
477
-     * @throws   HTTP_Request2_LogicException
478
-     * @throws   HTTP_Request2_MessageException
479
-     * @link     http://tools.ietf.org/html/rfc1952
480
-     */
481
-    public static function decodeGzip($data)
482
-    {
483
-        $length = strlen($data);
484
-        // If it doesn't look like gzip-encoded data, don't bother
485
-        if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) {
486
-            return $data;
487
-        }
488
-        if (!function_exists('gzinflate')) {
489
-            throw new HTTP_Request2_LogicException(
490
-                'Unable to decode body: gzip extension not available',
491
-                HTTP_Request2_Exception::MISCONFIGURATION
492
-            );
493
-        }
494
-        $method = ord(substr($data, 2, 1));
495
-        if (8 != $method) {
496
-            throw new HTTP_Request2_MessageException(
497
-                'Error parsing gzip header: unknown compression method',
498
-                HTTP_Request2_Exception::DECODE_ERROR
499
-            );
500
-        }
501
-        $flags = ord(substr($data, 3, 1));
502
-        if ($flags & 224) {
503
-            throw new HTTP_Request2_MessageException(
504
-                'Error parsing gzip header: reserved bits are set',
505
-                HTTP_Request2_Exception::DECODE_ERROR
506
-            );
507
-        }
508
-
509
-        // header is 10 bytes minimum. may be longer, though.
510
-        $headerLength = 10;
511
-        // extra fields, need to skip 'em
512
-        if ($flags & 4) {
513
-            if ($length - $headerLength - 2 < 8) {
514
-                throw new HTTP_Request2_MessageException(
515
-                    'Error parsing gzip header: data too short',
516
-                    HTTP_Request2_Exception::DECODE_ERROR
517
-                );
518
-            }
519
-            $extraLength = unpack('v', substr($data, 10, 2));
520
-            if ($length - $headerLength - 2 - $extraLength[1] < 8) {
521
-                throw new HTTP_Request2_MessageException(
522
-                    'Error parsing gzip header: data too short',
523
-                    HTTP_Request2_Exception::DECODE_ERROR
524
-                );
525
-            }
526
-            $headerLength += $extraLength[1] + 2;
527
-        }
528
-        // file name, need to skip that
529
-        if ($flags & 8) {
530
-            if ($length - $headerLength - 1 < 8) {
531
-                throw new HTTP_Request2_MessageException(
532
-                    'Error parsing gzip header: data too short',
533
-                    HTTP_Request2_Exception::DECODE_ERROR
534
-                );
535
-            }
536
-            $filenameLength = strpos(substr($data, $headerLength), chr(0));
537
-            if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) {
538
-                throw new HTTP_Request2_MessageException(
539
-                    'Error parsing gzip header: data too short',
540
-                    HTTP_Request2_Exception::DECODE_ERROR
541
-                );
542
-            }
543
-            $headerLength += $filenameLength + 1;
544
-        }
545
-        // comment, need to skip that also
546
-        if ($flags & 16) {
547
-            if ($length - $headerLength - 1 < 8) {
548
-                throw new HTTP_Request2_MessageException(
549
-                    'Error parsing gzip header: data too short',
550
-                    HTTP_Request2_Exception::DECODE_ERROR
551
-                );
552
-            }
553
-            $commentLength = strpos(substr($data, $headerLength), chr(0));
554
-            if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) {
555
-                throw new HTTP_Request2_MessageException(
556
-                    'Error parsing gzip header: data too short',
557
-                    HTTP_Request2_Exception::DECODE_ERROR
558
-                );
559
-            }
560
-            $headerLength += $commentLength + 1;
561
-        }
562
-        // have a CRC for header. let's check
563
-        if ($flags & 2) {
564
-            if ($length - $headerLength - 2 < 8) {
565
-                throw new HTTP_Request2_MessageException(
566
-                    'Error parsing gzip header: data too short',
567
-                    HTTP_Request2_Exception::DECODE_ERROR
568
-                );
569
-            }
570
-            $crcReal   = 0xffff & crc32(substr($data, 0, $headerLength));
571
-            $crcStored = unpack('v', substr($data, $headerLength, 2));
572
-            if ($crcReal != $crcStored[1]) {
573
-                throw new HTTP_Request2_MessageException(
574
-                    'Header CRC check failed',
575
-                    HTTP_Request2_Exception::DECODE_ERROR
576
-                );
577
-            }
578
-            $headerLength += 2;
579
-        }
580
-        // unpacked data CRC and size at the end of encoded data
581
-        $tmp = unpack('V2', substr($data, -8));
582
-        $dataCrc  = $tmp[1];
583
-        $dataSize = $tmp[2];
584
-
585
-        // finally, call the gzinflate() function
586
-        // don't pass $dataSize to gzinflate, see bugs #13135, #14370
587
-        $unpacked = gzinflate(substr($data, $headerLength, -8));
588
-        if (false === $unpacked) {
589
-            throw new HTTP_Request2_MessageException(
590
-                'gzinflate() call failed',
591
-                HTTP_Request2_Exception::DECODE_ERROR
592
-            );
593
-        } elseif ($dataSize != strlen($unpacked)) {
594
-            throw new HTTP_Request2_MessageException(
595
-                'Data size check failed',
596
-                HTTP_Request2_Exception::DECODE_ERROR
597
-            );
598
-        } elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) {
599
-            throw new HTTP_Request2_Exception(
600
-                'Data CRC check failed',
601
-                HTTP_Request2_Exception::DECODE_ERROR
602
-            );
603
-        }
604
-        return $unpacked;
605
-    }
606
-
607
-    /**
608
-     * Decodes the message-body encoded by deflate
609
-     *
610
-     * @param string $data deflate-encoded data
611
-     *
612
-     * @return   string  decoded data
613
-     * @throws   HTTP_Request2_LogicException
614
-     */
615
-    public static function decodeDeflate($data)
616
-    {
617
-        if (!function_exists('gzuncompress')) {
618
-            throw new HTTP_Request2_LogicException(
619
-                'Unable to decode body: gzip extension not available',
620
-                HTTP_Request2_Exception::MISCONFIGURATION
621
-            );
622
-        }
623
-        // RFC 2616 defines 'deflate' encoding as zlib format from RFC 1950,
624
-        // while many applications send raw deflate stream from RFC 1951.
625
-        // We should check for presence of zlib header and use gzuncompress() or
626
-        // gzinflate() as needed. See bug #15305
627
-        $header = unpack('n', substr($data, 0, 2));
628
-        return (0 == $header[1] % 31)? gzuncompress($data): gzinflate($data);
629
-    }
56
+	/**
57
+	 * HTTP protocol version (e.g. 1.0, 1.1)
58
+	 * @var  string
59
+	 */
60
+	protected $version;
61
+
62
+	/**
63
+	 * Status code
64
+	 * @var  integer
65
+	 * @link http://tools.ietf.org/html/rfc2616#section-6.1.1
66
+	 */
67
+	protected $code;
68
+
69
+	/**
70
+	 * Reason phrase
71
+	 * @var  string
72
+	 * @link http://tools.ietf.org/html/rfc2616#section-6.1.1
73
+	 */
74
+	protected $reasonPhrase;
75
+
76
+	/**
77
+	 * Effective URL (may be different from original request URL in case of redirects)
78
+	 * @var  string
79
+	 */
80
+	protected $effectiveUrl;
81
+
82
+	/**
83
+	 * Associative array of response headers
84
+	 * @var  array
85
+	 */
86
+	protected $headers = array();
87
+
88
+	/**
89
+	 * Cookies set in the response
90
+	 * @var  array
91
+	 */
92
+	protected $cookies = array();
93
+
94
+	/**
95
+	 * Name of last header processed by parseHederLine()
96
+	 *
97
+	 * Used to handle the headers that span multiple lines
98
+	 *
99
+	 * @var  string
100
+	 */
101
+	protected $lastHeader = null;
102
+
103
+	/**
104
+	 * Response body
105
+	 * @var  string
106
+	 */
107
+	protected $body = '';
108
+
109
+	/**
110
+	 * Whether the body is still encoded by Content-Encoding
111
+	 *
112
+	 * cURL provides the decoded body to the callback; if we are reading from
113
+	 * socket the body is still gzipped / deflated
114
+	 *
115
+	 * @var  bool
116
+	 */
117
+	protected $bodyEncoded;
118
+
119
+	/**
120
+	 * Associative array of HTTP status code / reason phrase.
121
+	 *
122
+	 * @var  array
123
+	 * @link http://tools.ietf.org/html/rfc2616#section-10
124
+	 */
125
+	protected static $phrases = array(
126
+
127
+		// 1xx: Informational - Request received, continuing process
128
+		100 => 'Continue',
129
+		101 => 'Switching Protocols',
130
+
131
+		// 2xx: Success - The action was successfully received, understood and
132
+		// accepted
133
+		200 => 'OK',
134
+		201 => 'Created',
135
+		202 => 'Accepted',
136
+		203 => 'Non-Authoritative Information',
137
+		204 => 'No Content',
138
+		205 => 'Reset Content',
139
+		206 => 'Partial Content',
140
+
141
+		// 3xx: Redirection - Further action must be taken in order to complete
142
+		// the request
143
+		300 => 'Multiple Choices',
144
+		301 => 'Moved Permanently',
145
+		302 => 'Found',  // 1.1
146
+		303 => 'See Other',
147
+		304 => 'Not Modified',
148
+		305 => 'Use Proxy',
149
+		307 => 'Temporary Redirect',
150
+
151
+		// 4xx: Client Error - The request contains bad syntax or cannot be
152
+		// fulfilled
153
+		400 => 'Bad Request',
154
+		401 => 'Unauthorized',
155
+		402 => 'Payment Required',
156
+		403 => 'Forbidden',
157
+		404 => 'Not Found',
158
+		405 => 'Method Not Allowed',
159
+		406 => 'Not Acceptable',
160
+		407 => 'Proxy Authentication Required',
161
+		408 => 'Request Timeout',
162
+		409 => 'Conflict',
163
+		410 => 'Gone',
164
+		411 => 'Length Required',
165
+		412 => 'Precondition Failed',
166
+		413 => 'Request Entity Too Large',
167
+		414 => 'Request-URI Too Long',
168
+		415 => 'Unsupported Media Type',
169
+		416 => 'Requested Range Not Satisfiable',
170
+		417 => 'Expectation Failed',
171
+
172
+		// 5xx: Server Error - The server failed to fulfill an apparently
173
+		// valid request
174
+		500 => 'Internal Server Error',
175
+		501 => 'Not Implemented',
176
+		502 => 'Bad Gateway',
177
+		503 => 'Service Unavailable',
178
+		504 => 'Gateway Timeout',
179
+		505 => 'HTTP Version Not Supported',
180
+		509 => 'Bandwidth Limit Exceeded',
181
+
182
+	);
183
+
184
+	/**
185
+	 * Returns the default reason phrase for the given code or all reason phrases
186
+	 *
187
+	 * @param int $code Response code
188
+	 *
189
+	 * @return string|array|null Default reason phrase for $code if $code is given
190
+	 *                           (null if no phrase is available), array of all
191
+	 *                           reason phrases if $code is null
192
+	 * @link   http://pear.php.net/bugs/18716
193
+	 */
194
+	public static function getDefaultReasonPhrase($code = null)
195
+	{
196
+		if (null === $code) {
197
+			return self::$phrases;
198
+		} else {
199
+			return isset(self::$phrases[$code]) ? self::$phrases[$code] : null;
200
+		}
201
+	}
202
+
203
+	/**
204
+	 * Constructor, parses the response status line
205
+	 *
206
+	 * @param string $statusLine   Response status line (e.g. "HTTP/1.1 200 OK")
207
+	 * @param bool   $bodyEncoded  Whether body is still encoded by Content-Encoding
208
+	 * @param string $effectiveUrl Effective URL of the response
209
+	 *
210
+	 * @throws   HTTP_Request2_MessageException if status line is invalid according to spec
211
+	 */
212
+	public function __construct($statusLine, $bodyEncoded = true, $effectiveUrl = null)
213
+	{
214
+		if (!preg_match('!^HTTP/(\d\.\d) (\d{3})(?: (.+))?!', $statusLine, $m)) {
215
+			throw new HTTP_Request2_MessageException(
216
+				"Malformed response: {$statusLine}",
217
+				HTTP_Request2_Exception::MALFORMED_RESPONSE
218
+			);
219
+		}
220
+		$this->version      = $m[1];
221
+		$this->code         = intval($m[2]);
222
+		$this->reasonPhrase = !empty($m[3]) ? trim($m[3]) : self::getDefaultReasonPhrase($this->code);
223
+		$this->bodyEncoded  = (bool)$bodyEncoded;
224
+		$this->effectiveUrl = (string)$effectiveUrl;
225
+	}
226
+
227
+	/**
228
+	 * Parses the line from HTTP response filling $headers array
229
+	 *
230
+	 * The method should be called after reading the line from socket or receiving
231
+	 * it into cURL callback. Passing an empty string here indicates the end of
232
+	 * response headers and triggers additional processing, so be sure to pass an
233
+	 * empty string in the end.
234
+	 *
235
+	 * @param string $headerLine Line from HTTP response
236
+	 */
237
+	public function parseHeaderLine($headerLine)
238
+	{
239
+		$headerLine = trim($headerLine, "\r\n");
240
+
241
+		if ('' == $headerLine) {
242
+			// empty string signals the end of headers, process the received ones
243
+			if (!empty($this->headers['set-cookie'])) {
244
+				$cookies = is_array($this->headers['set-cookie'])?
245
+						   $this->headers['set-cookie']:
246
+						   array($this->headers['set-cookie']);
247
+				foreach ($cookies as $cookieString) {
248
+					$this->parseCookie($cookieString);
249
+				}
250
+				unset($this->headers['set-cookie']);
251
+			}
252
+			foreach (array_keys($this->headers) as $k) {
253
+				if (is_array($this->headers[$k])) {
254
+					$this->headers[$k] = implode(', ', $this->headers[$k]);
255
+				}
256
+			}
257
+
258
+		} elseif (preg_match('!^([^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+):(.+)$!', $headerLine, $m)) {
259
+			// string of the form header-name: header value
260
+			$name  = strtolower($m[1]);
261
+			$value = trim($m[2]);
262
+			if (empty($this->headers[$name])) {
263
+				$this->headers[$name] = $value;
264
+			} else {
265
+				if (!is_array($this->headers[$name])) {
266
+					$this->headers[$name] = array($this->headers[$name]);
267
+				}
268
+				$this->headers[$name][] = $value;
269
+			}
270
+			$this->lastHeader = $name;
271
+
272
+		} elseif (preg_match('!^\s+(.+)$!', $headerLine, $m) && $this->lastHeader) {
273
+			// continuation of a previous header
274
+			if (!is_array($this->headers[$this->lastHeader])) {
275
+				$this->headers[$this->lastHeader] .= ' ' . trim($m[1]);
276
+			} else {
277
+				$key = count($this->headers[$this->lastHeader]) - 1;
278
+				$this->headers[$this->lastHeader][$key] .= ' ' . trim($m[1]);
279
+			}
280
+		}
281
+	}
282
+
283
+	/**
284
+	 * Parses a Set-Cookie header to fill $cookies array
285
+	 *
286
+	 * @param string $cookieString value of Set-Cookie header
287
+	 *
288
+	 * @link     http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html
289
+	 */
290
+	protected function parseCookie($cookieString)
291
+	{
292
+		$cookie = array(
293
+			'expires' => null,
294
+			'domain'  => null,
295
+			'path'    => null,
296
+			'secure'  => false
297
+		);
298
+
299
+		if (!strpos($cookieString, ';')) {
300
+			// Only a name=value pair
301
+			$pos = strpos($cookieString, '=');
302
+			$cookie['name']  = trim(substr($cookieString, 0, $pos));
303
+			$cookie['value'] = trim(substr($cookieString, $pos + 1));
304
+
305
+		} else {
306
+			// Some optional parameters are supplied
307
+			$elements = explode(';', $cookieString);
308
+			$pos = strpos($elements[0], '=');
309
+			$cookie['name']  = trim(substr($elements[0], 0, $pos));
310
+			$cookie['value'] = trim(substr($elements[0], $pos + 1));
311
+
312
+			for ($i = 1; $i < count($elements); $i++) {
313
+				if (false === strpos($elements[$i], '=')) {
314
+					$elName  = trim($elements[$i]);
315
+					$elValue = null;
316
+				} else {
317
+					list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i]));
318
+				}
319
+				$elName = strtolower($elName);
320
+				if ('secure' == $elName) {
321
+					$cookie['secure'] = true;
322
+				} elseif ('expires' == $elName) {
323
+					$cookie['expires'] = str_replace('"', '', $elValue);
324
+				} elseif ('path' == $elName || 'domain' == $elName) {
325
+					$cookie[$elName] = urldecode($elValue);
326
+				} else {
327
+					$cookie[$elName] = $elValue;
328
+				}
329
+			}
330
+		}
331
+		$this->cookies[] = $cookie;
332
+	}
333
+
334
+	/**
335
+	 * Appends a string to the response body
336
+	 *
337
+	 * @param string $bodyChunk part of response body
338
+	 */
339
+	public function appendBody($bodyChunk)
340
+	{
341
+		$this->body .= $bodyChunk;
342
+	}
343
+
344
+	/**
345
+	 * Returns the effective URL of the response
346
+	 *
347
+	 * This may be different from the request URL if redirects were followed.
348
+	 *
349
+	 * @return string
350
+	 * @link   http://pear.php.net/bugs/bug.php?id=18412
351
+	 */
352
+	public function getEffectiveUrl()
353
+	{
354
+		return $this->effectiveUrl;
355
+	}
356
+
357
+	/**
358
+	 * Returns the status code
359
+	 *
360
+	 * @return   integer
361
+	 */
362
+	public function getStatus()
363
+	{
364
+		return $this->code;
365
+	}
366
+
367
+	/**
368
+	 * Returns the reason phrase
369
+	 *
370
+	 * @return   string
371
+	 */
372
+	public function getReasonPhrase()
373
+	{
374
+		return $this->reasonPhrase;
375
+	}
376
+
377
+	/**
378
+	 * Whether response is a redirect that can be automatically handled by HTTP_Request2
379
+	 *
380
+	 * @return   bool
381
+	 */
382
+	public function isRedirect()
383
+	{
384
+		return in_array($this->code, array(300, 301, 302, 303, 307))
385
+			   && isset($this->headers['location']);
386
+	}
387
+
388
+	/**
389
+	 * Returns either the named header or all response headers
390
+	 *
391
+	 * @param string $headerName Name of header to return
392
+	 *
393
+	 * @return   string|array    Value of $headerName header (null if header is
394
+	 *                           not present), array of all response headers if
395
+	 *                           $headerName is null
396
+	 */
397
+	public function getHeader($headerName = null)
398
+	{
399
+		if (null === $headerName) {
400
+			return $this->headers;
401
+		} else {
402
+			$headerName = strtolower($headerName);
403
+			return isset($this->headers[$headerName])? $this->headers[$headerName]: null;
404
+		}
405
+	}
406
+
407
+	/**
408
+	 * Returns cookies set in response
409
+	 *
410
+	 * @return   array
411
+	 */
412
+	public function getCookies()
413
+	{
414
+		return $this->cookies;
415
+	}
416
+
417
+	/**
418
+	 * Returns the body of the response
419
+	 *
420
+	 * @return   string
421
+	 * @throws   HTTP_Request2_Exception if body cannot be decoded
422
+	 */
423
+	public function getBody()
424
+	{
425
+		if (0 == strlen($this->body) || !$this->bodyEncoded
426
+			|| !in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate'))
427
+		) {
428
+			return $this->body;
429
+
430
+		} else {
431
+			if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
432
+				$oldEncoding = mb_internal_encoding();
433
+				mb_internal_encoding('8bit');
434
+			}
435
+
436
+			try {
437
+				switch (strtolower($this->getHeader('content-encoding'))) {
438
+				case 'gzip':
439
+					$decoded = self::decodeGzip($this->body);
440
+					break;
441
+				case 'deflate':
442
+					$decoded = self::decodeDeflate($this->body);
443
+				}
444
+			} catch (Exception $e) {
445
+			}
446
+
447
+			if (!empty($oldEncoding)) {
448
+				mb_internal_encoding($oldEncoding);
449
+			}
450
+			if (!empty($e)) {
451
+				throw $e;
452
+			}
453
+			return $decoded;
454
+		}
455
+	}
456
+
457
+	/**
458
+	 * Get the HTTP version of the response
459
+	 *
460
+	 * @return   string
461
+	 */
462
+	public function getVersion()
463
+	{
464
+		return $this->version;
465
+	}
466
+
467
+	/**
468
+	 * Decodes the message-body encoded by gzip
469
+	 *
470
+	 * The real decoding work is done by gzinflate() built-in function, this
471
+	 * method only parses the header and checks data for compliance with
472
+	 * RFC 1952
473
+	 *
474
+	 * @param string $data gzip-encoded data
475
+	 *
476
+	 * @return   string  decoded data
477
+	 * @throws   HTTP_Request2_LogicException
478
+	 * @throws   HTTP_Request2_MessageException
479
+	 * @link     http://tools.ietf.org/html/rfc1952
480
+	 */
481
+	public static function decodeGzip($data)
482
+	{
483
+		$length = strlen($data);
484
+		// If it doesn't look like gzip-encoded data, don't bother
485
+		if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) {
486
+			return $data;
487
+		}
488
+		if (!function_exists('gzinflate')) {
489
+			throw new HTTP_Request2_LogicException(
490
+				'Unable to decode body: gzip extension not available',
491
+				HTTP_Request2_Exception::MISCONFIGURATION
492
+			);
493
+		}
494
+		$method = ord(substr($data, 2, 1));
495
+		if (8 != $method) {
496
+			throw new HTTP_Request2_MessageException(
497
+				'Error parsing gzip header: unknown compression method',
498
+				HTTP_Request2_Exception::DECODE_ERROR
499
+			);
500
+		}
501
+		$flags = ord(substr($data, 3, 1));
502
+		if ($flags & 224) {
503
+			throw new HTTP_Request2_MessageException(
504
+				'Error parsing gzip header: reserved bits are set',
505
+				HTTP_Request2_Exception::DECODE_ERROR
506
+			);
507
+		}
508
+
509
+		// header is 10 bytes minimum. may be longer, though.
510
+		$headerLength = 10;
511
+		// extra fields, need to skip 'em
512
+		if ($flags & 4) {
513
+			if ($length - $headerLength - 2 < 8) {
514
+				throw new HTTP_Request2_MessageException(
515
+					'Error parsing gzip header: data too short',
516
+					HTTP_Request2_Exception::DECODE_ERROR
517
+				);
518
+			}
519
+			$extraLength = unpack('v', substr($data, 10, 2));
520
+			if ($length - $headerLength - 2 - $extraLength[1] < 8) {
521
+				throw new HTTP_Request2_MessageException(
522
+					'Error parsing gzip header: data too short',
523
+					HTTP_Request2_Exception::DECODE_ERROR
524
+				);
525
+			}
526
+			$headerLength += $extraLength[1] + 2;
527
+		}
528
+		// file name, need to skip that
529
+		if ($flags & 8) {
530
+			if ($length - $headerLength - 1 < 8) {
531
+				throw new HTTP_Request2_MessageException(
532
+					'Error parsing gzip header: data too short',
533
+					HTTP_Request2_Exception::DECODE_ERROR
534
+				);
535
+			}
536
+			$filenameLength = strpos(substr($data, $headerLength), chr(0));
537
+			if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) {
538
+				throw new HTTP_Request2_MessageException(
539
+					'Error parsing gzip header: data too short',
540
+					HTTP_Request2_Exception::DECODE_ERROR
541
+				);
542
+			}
543
+			$headerLength += $filenameLength + 1;
544
+		}
545
+		// comment, need to skip that also
546
+		if ($flags & 16) {
547
+			if ($length - $headerLength - 1 < 8) {
548
+				throw new HTTP_Request2_MessageException(
549
+					'Error parsing gzip header: data too short',
550
+					HTTP_Request2_Exception::DECODE_ERROR
551
+				);
552
+			}
553
+			$commentLength = strpos(substr($data, $headerLength), chr(0));
554
+			if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) {
555
+				throw new HTTP_Request2_MessageException(
556
+					'Error parsing gzip header: data too short',
557
+					HTTP_Request2_Exception::DECODE_ERROR
558
+				);
559
+			}
560
+			$headerLength += $commentLength + 1;
561
+		}
562
+		// have a CRC for header. let's check
563
+		if ($flags & 2) {
564
+			if ($length - $headerLength - 2 < 8) {
565
+				throw new HTTP_Request2_MessageException(
566
+					'Error parsing gzip header: data too short',
567
+					HTTP_Request2_Exception::DECODE_ERROR
568
+				);
569
+			}
570
+			$crcReal   = 0xffff & crc32(substr($data, 0, $headerLength));
571
+			$crcStored = unpack('v', substr($data, $headerLength, 2));
572
+			if ($crcReal != $crcStored[1]) {
573
+				throw new HTTP_Request2_MessageException(
574
+					'Header CRC check failed',
575
+					HTTP_Request2_Exception::DECODE_ERROR
576
+				);
577
+			}
578
+			$headerLength += 2;
579
+		}
580
+		// unpacked data CRC and size at the end of encoded data
581
+		$tmp = unpack('V2', substr($data, -8));
582
+		$dataCrc  = $tmp[1];
583
+		$dataSize = $tmp[2];
584
+
585
+		// finally, call the gzinflate() function
586
+		// don't pass $dataSize to gzinflate, see bugs #13135, #14370
587
+		$unpacked = gzinflate(substr($data, $headerLength, -8));
588
+		if (false === $unpacked) {
589
+			throw new HTTP_Request2_MessageException(
590
+				'gzinflate() call failed',
591
+				HTTP_Request2_Exception::DECODE_ERROR
592
+			);
593
+		} elseif ($dataSize != strlen($unpacked)) {
594
+			throw new HTTP_Request2_MessageException(
595
+				'Data size check failed',
596
+				HTTP_Request2_Exception::DECODE_ERROR
597
+			);
598
+		} elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) {
599
+			throw new HTTP_Request2_Exception(
600
+				'Data CRC check failed',
601
+				HTTP_Request2_Exception::DECODE_ERROR
602
+			);
603
+		}
604
+		return $unpacked;
605
+	}
606
+
607
+	/**
608
+	 * Decodes the message-body encoded by deflate
609
+	 *
610
+	 * @param string $data deflate-encoded data
611
+	 *
612
+	 * @return   string  decoded data
613
+	 * @throws   HTTP_Request2_LogicException
614
+	 */
615
+	public static function decodeDeflate($data)
616
+	{
617
+		if (!function_exists('gzuncompress')) {
618
+			throw new HTTP_Request2_LogicException(
619
+				'Unable to decode body: gzip extension not available',
620
+				HTTP_Request2_Exception::MISCONFIGURATION
621
+			);
622
+		}
623
+		// RFC 2616 defines 'deflate' encoding as zlib format from RFC 1950,
624
+		// while many applications send raw deflate stream from RFC 1951.
625
+		// We should check for presence of zlib header and use gzuncompress() or
626
+		// gzinflate() as needed. See bug #15305
627
+		$header = unpack('n', substr($data, 0, 2));
628
+		return (0 == $header[1] % 31)? gzuncompress($data): gzinflate($data);
629
+	}
630 630
 }
631 631
 ?>
632 632
\ No newline at end of file
Please login to merge, or discard this patch.
Switch Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -435,11 +435,11 @@
 block discarded – undo
435 435
 
436 436
             try {
437 437
                 switch (strtolower($this->getHeader('content-encoding'))) {
438
-                case 'gzip':
439
-                    $decoded = self::decodeGzip($this->body);
440
-                    break;
441
-                case 'deflate':
442
-                    $decoded = self::decodeDeflate($this->body);
438
+                	case 'gzip':
439
+                    	$decoded = self::decodeGzip($this->body);
440
+                    	break;
441
+                	case 'deflate':
442
+                    	$decoded = self::decodeDeflate($this->body);
443 443
                 }
444 444
             } catch (Exception $e) {
445 445
             }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -10 removed lines patch added patch discarded remove patch
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
         // the request
143 143
         300 => 'Multiple Choices',
144 144
         301 => 'Moved Permanently',
145
-        302 => 'Found',  // 1.1
145
+        302 => 'Found', // 1.1
146 146
         303 => 'See Other',
147 147
         304 => 'Not Modified',
148 148
         305 => 'Use Proxy',
@@ -220,8 +220,8 @@  discard block
 block discarded – undo
220 220
         $this->version      = $m[1];
221 221
         $this->code         = intval($m[2]);
222 222
         $this->reasonPhrase = !empty($m[3]) ? trim($m[3]) : self::getDefaultReasonPhrase($this->code);
223
-        $this->bodyEncoded  = (bool)$bodyEncoded;
224
-        $this->effectiveUrl = (string)$effectiveUrl;
223
+        $this->bodyEncoded  = (bool) $bodyEncoded;
224
+        $this->effectiveUrl = (string) $effectiveUrl;
225 225
     }
226 226
 
227 227
     /**
@@ -241,9 +241,8 @@  discard block
 block discarded – undo
241 241
         if ('' == $headerLine) {
242 242
             // empty string signals the end of headers, process the received ones
243 243
             if (!empty($this->headers['set-cookie'])) {
244
-                $cookies = is_array($this->headers['set-cookie'])?
245
-                           $this->headers['set-cookie']:
246
-                           array($this->headers['set-cookie']);
244
+                $cookies = is_array($this->headers['set-cookie']) ?
245
+                           $this->headers['set-cookie'] : array($this->headers['set-cookie']);
247 246
                 foreach ($cookies as $cookieString) {
248 247
                     $this->parseCookie($cookieString);
249 248
                 }
@@ -272,10 +271,10 @@  discard block
 block discarded – undo
272 271
         } elseif (preg_match('!^\s+(.+)$!', $headerLine, $m) && $this->lastHeader) {
273 272
             // continuation of a previous header
274 273
             if (!is_array($this->headers[$this->lastHeader])) {
275
-                $this->headers[$this->lastHeader] .= ' ' . trim($m[1]);
274
+                $this->headers[$this->lastHeader] .= ' '.trim($m[1]);
276 275
             } else {
277 276
                 $key = count($this->headers[$this->lastHeader]) - 1;
278
-                $this->headers[$this->lastHeader][$key] .= ' ' . trim($m[1]);
277
+                $this->headers[$this->lastHeader][$key] .= ' '.trim($m[1]);
279 278
             }
280 279
         }
281 280
     }
@@ -400,7 +399,7 @@  discard block
 block discarded – undo
400 399
             return $this->headers;
401 400
         } else {
402 401
             $headerName = strtolower($headerName);
403
-            return isset($this->headers[$headerName])? $this->headers[$headerName]: null;
402
+            return isset($this->headers[$headerName]) ? $this->headers[$headerName] : null;
404 403
         }
405 404
     }
406 405
 
@@ -625,7 +624,7 @@  discard block
 block discarded – undo
625 624
         // We should check for presence of zlib header and use gzuncompress() or
626 625
         // gzinflate() as needed. See bug #15305
627 626
         $header = unpack('n', substr($data, 0, 2));
628
-        return (0 == $header[1] % 31)? gzuncompress($data): gzinflate($data);
627
+        return (0 == $header[1] % 31) ? gzuncompress($data) : gzinflate($data);
629 628
     }
630 629
 }
631 630
 ?>
632 631
\ No newline at end of file
Please login to merge, or discard this patch.
libs/PEAR.1.9.5/HTTP/Request2/SOCKS5.php 3 patches
Switch Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -68,14 +68,14 @@
 block discarded – undo
68 68
             );
69 69
         }
70 70
         switch ($response['method']) {
71
-        case 2:
72
-            $this->performAuthentication($username, $password);
73
-        case 0:
74
-            break;
75
-        default:
76
-            throw new HTTP_Request2_ConnectionException(
77
-                "Connection rejected by proxy due to unsupported auth method"
78
-            );
71
+        	case 2:
72
+            	$this->performAuthentication($username, $password);
73
+        	case 0:
74
+            	break;
75
+        	default:
76
+            	throw new HTTP_Request2_ConnectionException(
77
+                	"Connection rejected by proxy due to unsupported auth method"
78
+            	);
79 79
         }
80 80
     }
81 81
 
Please login to merge, or discard this patch.
Indentation   +91 added lines, -91 removed lines patch added patch discarded remove patch
@@ -35,101 +35,101 @@
 block discarded – undo
35 35
  */
36 36
 class HTTP_Request2_SOCKS5 extends HTTP_Request2_SocketWrapper
37 37
 {
38
-    /**
39
-     * Constructor, tries to connect and authenticate to a SOCKS5 proxy
40
-     *
41
-     * @param string $address        Proxy address, e.g. 'tcp://localhost:1080'
42
-     * @param int    $timeout        Connection timeout (seconds)
43
-     * @param array  $contextOptions Stream context options
44
-     * @param string $username       Proxy user name
45
-     * @param string $password       Proxy password
46
-     *
47
-     * @throws HTTP_Request2_LogicException
48
-     * @throws HTTP_Request2_ConnectionException
49
-     * @throws HTTP_Request2_MessageException
50
-     */
51
-    public function __construct(
52
-        $address, $timeout = 10, array $contextOptions = array(),
53
-        $username = null, $password = null
54
-    ) {
55
-        parent::__construct($address, $timeout, $contextOptions);
38
+	/**
39
+	 * Constructor, tries to connect and authenticate to a SOCKS5 proxy
40
+	 *
41
+	 * @param string $address        Proxy address, e.g. 'tcp://localhost:1080'
42
+	 * @param int    $timeout        Connection timeout (seconds)
43
+	 * @param array  $contextOptions Stream context options
44
+	 * @param string $username       Proxy user name
45
+	 * @param string $password       Proxy password
46
+	 *
47
+	 * @throws HTTP_Request2_LogicException
48
+	 * @throws HTTP_Request2_ConnectionException
49
+	 * @throws HTTP_Request2_MessageException
50
+	 */
51
+	public function __construct(
52
+		$address, $timeout = 10, array $contextOptions = array(),
53
+		$username = null, $password = null
54
+	) {
55
+		parent::__construct($address, $timeout, $contextOptions);
56 56
 
57
-        if (strlen($username)) {
58
-            $request = pack('C4', 5, 2, 0, 2);
59
-        } else {
60
-            $request = pack('C3', 5, 1, 0);
61
-        }
62
-        $this->write($request);
63
-        $response = unpack('Cversion/Cmethod', $this->read(3));
64
-        if (5 != $response['version']) {
65
-            throw new HTTP_Request2_MessageException(
66
-                'Invalid version received from SOCKS5 proxy: ' . $response['version'],
67
-                HTTP_Request2_Exception::MALFORMED_RESPONSE
68
-            );
69
-        }
70
-        switch ($response['method']) {
71
-        case 2:
72
-            $this->performAuthentication($username, $password);
73
-        case 0:
74
-            break;
75
-        default:
76
-            throw new HTTP_Request2_ConnectionException(
77
-                "Connection rejected by proxy due to unsupported auth method"
78
-            );
79
-        }
80
-    }
57
+		if (strlen($username)) {
58
+			$request = pack('C4', 5, 2, 0, 2);
59
+		} else {
60
+			$request = pack('C3', 5, 1, 0);
61
+		}
62
+		$this->write($request);
63
+		$response = unpack('Cversion/Cmethod', $this->read(3));
64
+		if (5 != $response['version']) {
65
+			throw new HTTP_Request2_MessageException(
66
+				'Invalid version received from SOCKS5 proxy: ' . $response['version'],
67
+				HTTP_Request2_Exception::MALFORMED_RESPONSE
68
+			);
69
+		}
70
+		switch ($response['method']) {
71
+		case 2:
72
+			$this->performAuthentication($username, $password);
73
+		case 0:
74
+			break;
75
+		default:
76
+			throw new HTTP_Request2_ConnectionException(
77
+				"Connection rejected by proxy due to unsupported auth method"
78
+			);
79
+		}
80
+	}
81 81
 
82
-    /**
83
-     * Performs username/password authentication for SOCKS5
84
-     *
85
-     * @param string $username Proxy user name
86
-     * @param string $password Proxy password
87
-     *
88
-     * @throws HTTP_Request2_ConnectionException
89
-     * @throws HTTP_Request2_MessageException
90
-     * @link http://tools.ietf.org/html/rfc1929
91
-     */
92
-    protected function performAuthentication($username, $password)
93
-    {
94
-        $request  = pack('C2', 1, strlen($username)) . $username
95
-                    . pack('C', strlen($password)) . $password;
82
+	/**
83
+	 * Performs username/password authentication for SOCKS5
84
+	 *
85
+	 * @param string $username Proxy user name
86
+	 * @param string $password Proxy password
87
+	 *
88
+	 * @throws HTTP_Request2_ConnectionException
89
+	 * @throws HTTP_Request2_MessageException
90
+	 * @link http://tools.ietf.org/html/rfc1929
91
+	 */
92
+	protected function performAuthentication($username, $password)
93
+	{
94
+		$request  = pack('C2', 1, strlen($username)) . $username
95
+					. pack('C', strlen($password)) . $password;
96 96
 
97
-        $this->write($request);
98
-        $response = unpack('Cvn/Cstatus', $this->read(3));
99
-        if (1 != $response['vn'] || 0 != $response['status']) {
100
-            throw new HTTP_Request2_ConnectionException(
101
-                'Connection rejected by proxy due to invalid username and/or password'
102
-            );
103
-        }
104
-    }
97
+		$this->write($request);
98
+		$response = unpack('Cvn/Cstatus', $this->read(3));
99
+		if (1 != $response['vn'] || 0 != $response['status']) {
100
+			throw new HTTP_Request2_ConnectionException(
101
+				'Connection rejected by proxy due to invalid username and/or password'
102
+			);
103
+		}
104
+	}
105 105
 
106
-    /**
107
-     * Connects to a remote host via proxy
108
-     *
109
-     * @param string $remoteHost Remote host
110
-     * @param int    $remotePort Remote port
111
-     *
112
-     * @throws HTTP_Request2_ConnectionException
113
-     * @throws HTTP_Request2_MessageException
114
-     */
115
-    public function connect($remoteHost, $remotePort)
116
-    {
117
-        $request = pack('C5', 0x05, 0x01, 0x00, 0x03, strlen($remoteHost))
118
-                   . $remoteHost . pack('n', $remotePort);
106
+	/**
107
+	 * Connects to a remote host via proxy
108
+	 *
109
+	 * @param string $remoteHost Remote host
110
+	 * @param int    $remotePort Remote port
111
+	 *
112
+	 * @throws HTTP_Request2_ConnectionException
113
+	 * @throws HTTP_Request2_MessageException
114
+	 */
115
+	public function connect($remoteHost, $remotePort)
116
+	{
117
+		$request = pack('C5', 0x05, 0x01, 0x00, 0x03, strlen($remoteHost))
118
+				   . $remoteHost . pack('n', $remotePort);
119 119
 
120
-        $this->write($request);
121
-        $response = unpack('Cversion/Creply/Creserved', $this->read(1024));
122
-        if (5 != $response['version'] || 0 != $response['reserved']) {
123
-            throw new HTTP_Request2_MessageException(
124
-                'Invalid response received from SOCKS5 proxy',
125
-                HTTP_Request2_Exception::MALFORMED_RESPONSE
126
-            );
127
-        } elseif (0 != $response['reply']) {
128
-            throw new HTTP_Request2_ConnectionException(
129
-                "Unable to connect to {$remoteHost}:{$remotePort} through SOCKS5 proxy",
130
-                0, $response['reply']
131
-            );
132
-        }
133
-    }
120
+		$this->write($request);
121
+		$response = unpack('Cversion/Creply/Creserved', $this->read(1024));
122
+		if (5 != $response['version'] || 0 != $response['reserved']) {
123
+			throw new HTTP_Request2_MessageException(
124
+				'Invalid response received from SOCKS5 proxy',
125
+				HTTP_Request2_Exception::MALFORMED_RESPONSE
126
+			);
127
+		} elseif (0 != $response['reply']) {
128
+			throw new HTTP_Request2_ConnectionException(
129
+				"Unable to connect to {$remoteHost}:{$remotePort} through SOCKS5 proxy",
130
+				0, $response['reply']
131
+			);
132
+		}
133
+	}
134 134
 }
135 135
 ?>
136 136
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -63,7 +63,7 @@  discard block
 block discarded – undo
63 63
         $response = unpack('Cversion/Cmethod', $this->read(3));
64 64
         if (5 != $response['version']) {
65 65
             throw new HTTP_Request2_MessageException(
66
-                'Invalid version received from SOCKS5 proxy: ' . $response['version'],
66
+                'Invalid version received from SOCKS5 proxy: '.$response['version'],
67 67
                 HTTP_Request2_Exception::MALFORMED_RESPONSE
68 68
             );
69 69
         }
@@ -91,8 +91,8 @@  discard block
 block discarded – undo
91 91
      */
92 92
     protected function performAuthentication($username, $password)
93 93
     {
94
-        $request  = pack('C2', 1, strlen($username)) . $username
95
-                    . pack('C', strlen($password)) . $password;
94
+        $request = pack('C2', 1, strlen($username)).$username
95
+                    . pack('C', strlen($password)).$password;
96 96
 
97 97
         $this->write($request);
98 98
         $response = unpack('Cvn/Cstatus', $this->read(3));
@@ -115,7 +115,7 @@  discard block
 block discarded – undo
115 115
     public function connect($remoteHost, $remotePort)
116 116
     {
117 117
         $request = pack('C5', 0x05, 0x01, 0x00, 0x03, strlen($remoteHost))
118
-                   . $remoteHost . pack('n', $remotePort);
118
+                   . $remoteHost.pack('n', $remotePort);
119 119
 
120 120
         $this->write($request);
121 121
         $response = unpack('Cversion/Creply/Creserved', $this->read(1024));
Please login to merge, or discard this patch.