ILIAS  release_4-4 Revision
All Data Structures Namespaces Files Functions Variables Modules Pages
HTTP_Response Class Reference
+ Collaboration diagram for HTTP_Response:

Public Member Functions

 HTTP_Response (&$sock, &$listeners)
 Constructor. More...
 
 process ($saveBody=true, $canHaveBody=true)
 Processes a HTTP response. More...
 
 _processHeader ($header)
 Processes the response header. More...
 
 _parseCookie ($headervalue)
 Parse a Set-Cookie header to fill $_cookies array. More...
 
 _readChunked ()
 Read a part of response body encoded with chunked Transfer-Encoding. More...
 
 _notify ($event, $data=null)
 Notifies all registered listeners of an event. More...
 
 _decodeGzip ($data)
 Decodes the message-body encoded by gzip. More...
 

Data Fields

 $_sock
 
 $_protocol
 
 $_code
 
 $_reason
 
 $_headers
 
 $_cookies
 
 $_body = ''
 
 $_chunkLength = 0
 
 $_listeners = array()
 
 $_toRead
 

Detailed Description

Definition at line 1130 of file Request.php.

Member Function Documentation

◆ _decodeGzip()

HTTP_Response::_decodeGzip (   $data)

Decodes the message-body encoded by gzip.

The real decoding work is done by gzinflate() built-in function, this method only parses the header and checks data for compliance with RFC 1952

private

Parameters
stringgzip-encoded data
Returns
string decoded data

Definition at line 1433 of file Request.php.

References $data, HTTP_REQUEST_ERROR_GZIP_CRC, HTTP_REQUEST_ERROR_GZIP_DATA, HTTP_REQUEST_ERROR_GZIP_METHOD, HTTP_REQUEST_ERROR_GZIP_READ, and PEAR\raiseError().

1434  {
1435  if (HTTP_REQUEST_MBSTRING) {
1436  $oldEncoding = mb_internal_encoding();
1437  mb_internal_encoding('iso-8859-1');
1438  }
1439  $length = strlen($data);
1440  // If it doesn't look like gzip-encoded data, don't bother
1441  if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) {
1442  return $data;
1443  }
1444  $method = ord(substr($data, 2, 1));
1445  if (8 != $method) {
1446  return PEAR::raiseError('_decodeGzip(): unknown compression method', HTTP_REQUEST_ERROR_GZIP_METHOD);
1447  }
1448  $flags = ord(substr($data, 3, 1));
1449  if ($flags & 224) {
1450  return PEAR::raiseError('_decodeGzip(): reserved bits are set', HTTP_REQUEST_ERROR_GZIP_DATA);
1451  }
1452 
1453  // header is 10 bytes minimum. may be longer, though.
1454  $headerLength = 10;
1455  // extra fields, need to skip 'em
1456  if ($flags & 4) {
1457  if ($length - $headerLength - 2 < 8) {
1458  return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1459  }
1460  $extraLength = unpack('v', substr($data, 10, 2));
1461  if ($length - $headerLength - 2 - $extraLength[1] < 8) {
1462  return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1463  }
1464  $headerLength += $extraLength[1] + 2;
1465  }
1466  // file name, need to skip that
1467  if ($flags & 8) {
1468  if ($length - $headerLength - 1 < 8) {
1469  return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1470  }
1471  $filenameLength = strpos(substr($data, $headerLength), chr(0));
1472  if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) {
1473  return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1474  }
1475  $headerLength += $filenameLength + 1;
1476  }
1477  // comment, need to skip that also
1478  if ($flags & 16) {
1479  if ($length - $headerLength - 1 < 8) {
1480  return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1481  }
1482  $commentLength = strpos(substr($data, $headerLength), chr(0));
1483  if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) {
1484  return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1485  }
1486  $headerLength += $commentLength + 1;
1487  }
1488  // have a CRC for header. let's check
1489  if ($flags & 1) {
1490  if ($length - $headerLength - 2 < 8) {
1491  return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1492  }
1493  $crcReal = 0xffff & crc32(substr($data, 0, $headerLength));
1494  $crcStored = unpack('v', substr($data, $headerLength, 2));
1495  if ($crcReal != $crcStored[1]) {
1496  return PEAR::raiseError('_decodeGzip(): header CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC);
1497  }
1498  $headerLength += 2;
1499  }
1500  // unpacked data CRC and size at the end of encoded data
1501  $tmp = unpack('V2', substr($data, -8));
1502  $dataCrc = $tmp[1];
1503  $dataSize = $tmp[2];
1504 
1505  // finally, call the gzinflate() function
1506  // don't pass $dataSize to gzinflate, see bugs #13135, #14370
1507  $unpacked = gzinflate(substr($data, $headerLength, -8));
1508  if (false === $unpacked) {
1509  return PEAR::raiseError('_decodeGzip(): gzinflate() call failed', HTTP_REQUEST_ERROR_GZIP_READ);
1510  } elseif ($dataSize != strlen($unpacked)) {
1511  return PEAR::raiseError('_decodeGzip(): data size check failed', HTTP_REQUEST_ERROR_GZIP_READ);
1512  } elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) {
1513  return PEAR::raiseError('_decodeGzip(): data CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC);
1514  }
1515  if (HTTP_REQUEST_MBSTRING) {
1516  mb_internal_encoding($oldEncoding);
1517  }
1518  return $unpacked;
1519  }
const HTTP_REQUEST_ERROR_GZIP_READ
Definition: Request.php:81
const HTTP_REQUEST_ERROR_GZIP_DATA
Definition: Request.php:82
const HTTP_REQUEST_ERROR_GZIP_CRC
Definition: Request.php:83
const HTTP_REQUEST_ERROR_GZIP_METHOD
Definition: Request.php:80
while($lm_rec=$ilDB->fetchAssoc($lm_set)) $data
& raiseError($message=null, $code=null, $mode=null, $options=null, $userinfo=null, $error_class=null, $skipmsg=false)
This method is a wrapper that returns an instance of the configured error class with this object&#39;s de...
Definition: PEAR.php:524
+ Here is the call graph for this function:

◆ _notify()

HTTP_Response::_notify (   $event,
  $data = null 
)

Notifies all registered listeners of an event.

Parameters
stringEvent name
mixedAdditional data private
See also
HTTP_Request::_notify()

Definition at line 1414 of file Request.php.

References $data.

1415  {
1416  foreach (array_keys($this->_listeners) as $id) {
1417  $this->_listeners[$id]->update($this, $event, $data);
1418  }
1419  }
while($lm_rec=$ilDB->fetchAssoc($lm_set)) $data

◆ _parseCookie()

HTTP_Response::_parseCookie (   $headervalue)

Parse a Set-Cookie header to fill $_cookies array.

private

Parameters
stringvalue of Set-Cookie header

Definition at line 1330 of file Request.php.

1331  {
1332  $cookie = array(
1333  'expires' => null,
1334  'domain' => null,
1335  'path' => null,
1336  'secure' => false
1337  );
1338 
1339  // Only a name=value pair
1340  if (!strpos($headervalue, ';')) {
1341  $pos = strpos($headervalue, '=');
1342  $cookie['name'] = trim(substr($headervalue, 0, $pos));
1343  $cookie['value'] = trim(substr($headervalue, $pos + 1));
1344 
1345  // Some optional parameters are supplied
1346  } else {
1347  $elements = explode(';', $headervalue);
1348  $pos = strpos($elements[0], '=');
1349  $cookie['name'] = trim(substr($elements[0], 0, $pos));
1350  $cookie['value'] = trim(substr($elements[0], $pos + 1));
1351 
1352  for ($i = 1; $i < count($elements); $i++) {
1353  if (false === strpos($elements[$i], '=')) {
1354  $elName = trim($elements[$i]);
1355  $elValue = null;
1356  } else {
1357  list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i]));
1358  }
1359  $elName = strtolower($elName);
1360  if ('secure' == $elName) {
1361  $cookie['secure'] = true;
1362  } elseif ('expires' == $elName) {
1363  $cookie['expires'] = str_replace('"', '', $elValue);
1364  } elseif ('path' == $elName || 'domain' == $elName) {
1365  $cookie[$elName] = urldecode($elValue);
1366  } else {
1367  $cookie[$elName] = $elValue;
1368  }
1369  }
1370  }
1371  $this->_cookies[] = $cookie;
1372  }

◆ _processHeader()

HTTP_Response::_processHeader (   $header)

Processes the response header.

private

Parameters
stringHTTP header

Definition at line 1303 of file Request.php.

1304  {
1305  if (false === strpos($header, ':')) {
1306  return;
1307  }
1308  list($headername, $headervalue) = explode(':', $header, 2);
1309  $headername = strtolower($headername);
1310  $headervalue = ltrim($headervalue);
1311 
1312  if ('set-cookie' != $headername) {
1313  if (isset($this->_headers[$headername])) {
1314  $this->_headers[$headername] .= ',' . $headervalue;
1315  } else {
1316  $this->_headers[$headername] = $headervalue;
1317  }
1318  } else {
1319  $this->_parseCookie($headervalue);
1320  }
1321  }
_parseCookie($headervalue)
Parse a Set-Cookie header to fill $_cookies array.
Definition: Request.php:1330

◆ _readChunked()

HTTP_Response::_readChunked ( )

Read a part of response body encoded with chunked Transfer-Encoding.

private

Returns
string

Definition at line 1381 of file Request.php.

References $data.

1382  {
1383  // at start of the next chunk?
1384  if (0 == $this->_chunkLength) {
1385  $line = $this->_sock->readLine();
1386  if (preg_match('/^([0-9a-f]+)/i', $line, $matches)) {
1387  $this->_chunkLength = hexdec($matches[1]);
1388  // Chunk with zero length indicates the end
1389  if (0 == $this->_chunkLength) {
1390  $this->_sock->readLine(); // make this an eof()
1391  return '';
1392  }
1393  } else {
1394  return '';
1395  }
1396  }
1397  $data = $this->_sock->read($this->_chunkLength);
1398  $this->_chunkLength -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data);
1399  if (0 == $this->_chunkLength) {
1400  $this->_sock->readLine(); // Trailing CRLF
1401  }
1402  return $data;
1403  }
while($lm_rec=$ilDB->fetchAssoc($lm_set)) $data

◆ HTTP_Response()

HTTP_Response::HTTP_Response ( $sock,
$listeners 
)

Constructor.

Parameters
Net_Socketsocket to read the response from
arraylisteners attached to request

Definition at line 1198 of file Request.php.

1199  {
1200  $this->_sock =& $sock;
1201  $this->_listeners =& $listeners;
1202  }

◆ process()

HTTP_Response::process (   $saveBody = true,
  $canHaveBody = true 
)

Processes a HTTP response.

This extracts response code, headers, cookies and decodes body if it was encoded in some way

public

Parameters
boolWhether to store response body in object property, set this to false if downloading a LARGE file and using a Listener. This is assumed to be true if body is gzip-encoded.
boolWhether the response can actually have a message-body. Will be set to false for HEAD requests.
Exceptions
PEAR_Error
Returns
mixed true on success, PEAR_Error in case of malformed response

Definition at line 1220 of file Request.php.

References $data, HTTP_Request\_notify(), HTTP_REQUEST_ERROR_RESPONSE, PEAR\isError(), and PEAR\raiseError().

1221  {
1222  do {
1223  $line = $this->_sock->readLine();
1224  if (!preg_match('!^(HTTP/\d\.\d) (\d{3})(?: (.+))?!', $line, $s)) {
1225  return PEAR::raiseError('Malformed response', HTTP_REQUEST_ERROR_RESPONSE);
1226  } else {
1227  $this->_protocol = $s[1];
1228  $this->_code = intval($s[2]);
1229  $this->_reason = empty($s[3])? null: $s[3];
1230  }
1231  while ('' !== ($header = $this->_sock->readLine())) {
1232  $this->_processHeader($header);
1233  }
1234  } while (100 == $this->_code);
1235 
1236  $this->_notify('gotHeaders', $this->_headers);
1237 
1238  // RFC 2616, section 4.4:
1239  // 1. Any response message which "MUST NOT" include a message-body ...
1240  // is always terminated by the first empty line after the header fields
1241  // 3. ... If a message is received with both a
1242  // Transfer-Encoding header field and a Content-Length header field,
1243  // the latter MUST be ignored.
1244  $canHaveBody = $canHaveBody && $this->_code >= 200 &&
1245  $this->_code != 204 && $this->_code != 304;
1246 
1247  // If response body is present, read it and decode
1248  $chunked = isset($this->_headers['transfer-encoding']) && ('chunked' == $this->_headers['transfer-encoding']);
1249  $gzipped = isset($this->_headers['content-encoding']) && ('gzip' == $this->_headers['content-encoding']);
1250  $hasBody = false;
1251  if ($canHaveBody && ($chunked || !isset($this->_headers['content-length']) ||
1252  0 != $this->_headers['content-length']))
1253  {
1254  if ($chunked || !isset($this->_headers['content-length'])) {
1255  $this->_toRead = null;
1256  } else {
1257  $this->_toRead = $this->_headers['content-length'];
1258  }
1259  while (!$this->_sock->eof() && (is_null($this->_toRead) || 0 < $this->_toRead)) {
1260  if ($chunked) {
1261  $data = $this->_readChunked();
1262  } elseif (is_null($this->_toRead)) {
1263  $data = $this->_sock->read(4096);
1264  } else {
1265  $data = $this->_sock->read(min(4096, $this->_toRead));
1266  $this->_toRead -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data);
1267  }
1268  if ('' == $data && (!$this->_chunkLength || $this->_sock->eof())) {
1269  break;
1270  } else {
1271  $hasBody = true;
1272  if ($saveBody || $gzipped) {
1273  $this->_body .= $data;
1274  }
1275  $this->_notify($gzipped? 'gzTick': 'tick', $data);
1276  }
1277  }
1278  }
1279 
1280  if ($hasBody) {
1281  // Uncompress the body if needed
1282  if ($gzipped) {
1283  $body = $this->_decodeGzip($this->_body);
1284  if (PEAR::isError($body)) {
1285  return $body;
1286  }
1287  $this->_body = $body;
1288  $this->_notify('gotBody', $this->_body);
1289  } else {
1290  $this->_notify('gotBody');
1291  }
1292  }
1293  return true;
1294  }
const HTTP_REQUEST_ERROR_RESPONSE
Definition: Request.php:79
_processHeader($header)
Processes the response header.
Definition: Request.php:1303
_notify($event, $data=null)
Notifies all registered listeners of an event.
Definition: Request.php:1414
_readChunked()
Read a part of response body encoded with chunked Transfer-Encoding.
Definition: Request.php:1381
while($lm_rec=$ilDB->fetchAssoc($lm_set)) $data
& raiseError($message=null, $code=null, $mode=null, $options=null, $userinfo=null, $error_class=null, $skipmsg=false)
This method is a wrapper that returns an instance of the configured error class with this object&#39;s de...
Definition: PEAR.php:524
_decodeGzip($data)
Decodes the message-body encoded by gzip.
Definition: Request.php:1433
isError($data, $code=null)
Tell whether a value is a PEAR error.
Definition: PEAR.php:279
+ Here is the call graph for this function:

Field Documentation

◆ $_body

HTTP_Response::$_body = ''

Definition at line 1172 of file Request.php.

◆ $_chunkLength

HTTP_Response::$_chunkLength = 0

Definition at line 1178 of file Request.php.

◆ $_code

HTTP_Response::$_code

Definition at line 1148 of file Request.php.

◆ $_cookies

HTTP_Response::$_cookies

Definition at line 1166 of file Request.php.

◆ $_headers

HTTP_Response::$_headers

Definition at line 1160 of file Request.php.

◆ $_listeners

HTTP_Response::$_listeners = array()

Definition at line 1184 of file Request.php.

◆ $_protocol

HTTP_Response::$_protocol

Definition at line 1142 of file Request.php.

◆ $_reason

HTTP_Response::$_reason

Definition at line 1154 of file Request.php.

◆ $_sock

HTTP_Response::$_sock

Definition at line 1136 of file Request.php.

◆ $_toRead

HTTP_Response::$_toRead

Definition at line 1190 of file Request.php.


The documentation for this class was generated from the following file: