ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
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

@access private

Parameters
stringgzip-encoded data
Returns
string decoded data

Definition at line 1433 of file Request.php.

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_CRC
Definition: Request.php:83
const HTTP_REQUEST_ERROR_GZIP_METHOD
Definition: Request.php:80
const HTTP_REQUEST_ERROR_GZIP_DATA
Definition: Request.php:82
const HTTP_REQUEST_ERROR_GZIP_READ
Definition: Request.php:81
& 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's de...
Definition: PEAR.php:524
$data

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().

Referenced by process().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _notify()

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

Notifies all registered listeners of an event.

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

Definition at line 1414 of file Request.php.

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

References $data.

Referenced by process().

+ Here is the caller graph for this function:

◆ _parseCookie()

HTTP_Response::_parseCookie (   $headervalue)

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

@access 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 }

Referenced by _processHeader().

+ Here is the caller graph for this function:

◆ _processHeader()

HTTP_Response::_processHeader (   $header)

Processes the response header.

@access 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
$header

References $header, and _parseCookie().

Referenced by process().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _readChunked()

HTTP_Response::_readChunked ( )

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

@access private

Returns
string

Definition at line 1381 of file Request.php.

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 }

References $data.

Referenced by process().

+ Here is the caller graph for this function:

◆ 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

@access 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.

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
_decodeGzip($data)
Decodes the message-body encoded by gzip.
Definition: Request.php:1433
_readChunked()
Read a part of response body encoded with chunked Transfer-Encoding.
Definition: Request.php:1381
isError($data, $code=null)
Tell whether a value is a PEAR error.
Definition: PEAR.php:279

References $_toRead, $data, $header, _decodeGzip(), _notify(), _processHeader(), _readChunked(), HTTP_REQUEST_ERROR_RESPONSE, PEAR\isError(), and PEAR\raiseError().

+ 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.

Referenced by process().


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