@@ -30,6 +30,12 @@ if (!defined('E_DEPRECATED')) {
3030 define ('E_DEPRECATED ' , 8192 );
3131}
3232
33+ /**
34+ * Error code indicating that the request made by drupal_http_request() exceeded
35+ * the specified timeout.
36+ */
37+ define ('HTTP_REQUEST_TIMEOUT ' , -1 );
38+
3339/**
3440 * Set content for a specified region.
3541 *
@@ -347,7 +353,7 @@ function drupal_goto($path = '', $query = NULL, $fragment = NULL, $http_response
347353 */
348354function drupal_site_offline () {
349355 drupal_maintenance_theme ();
350- drupal_set_header (' HTTP/1.1 503 Service unavailable ' );
356+ drupal_set_header ($ _SERVER [ ' SERVER_PROTOCOL ' ] . ' 503 Service unavailable ' );
351357 drupal_set_title (t ('Site off-line ' ));
352358 print theme ('maintenance_page ' , filter_xss_admin (variable_get ('site_offline_message ' ,
353359 t ('@site is currently under maintenance. We should be back shortly. Thank you for your patience. ' , array ('@site ' => variable_get ('site_name ' , 'Pressflow ' ))))));
@@ -357,7 +363,7 @@ function drupal_site_offline() {
357363 * Generates a 404 error if the request can not be handled.
358364 */
359365function drupal_not_found () {
360- drupal_set_header (' HTTP/1.1 404 Not Found ' );
366+ drupal_set_header ($ _SERVER [ ' SERVER_PROTOCOL ' ] . ' 404 Not Found ' );
361367
362368 watchdog ('page not found ' , check_plain ($ _GET ['q ' ]), NULL , WATCHDOG_WARNING );
363369
@@ -387,7 +393,7 @@ function drupal_not_found() {
387393 * Generates a 403 error if the request is not allowed.
388394 */
389395function drupal_access_denied () {
390- drupal_set_header (' HTTP/1.1 403 Forbidden ' );
396+ drupal_set_header ($ _SERVER [ ' SERVER_PROTOCOL ' ] . ' 403 Forbidden ' );
391397
392398 watchdog ('access denied ' , check_plain ($ _GET ['q ' ]), NULL , WATCHDOG_WARNING );
393399
@@ -428,11 +434,15 @@ function drupal_access_denied() {
428434 * @param $retry
429435 * An integer representing how many times to retry the request in case of a
430436 * redirect.
437+ * @param $timeout
438+ * A float representing the maximum number of seconds the function call may
439+ * take. The default is 30 seconds. If a timeout occurs, the error code is set
440+ * to the HTTP_REQUEST_TIMEOUT constant.
431441 * @return
432442 * An object containing the HTTP request headers, response code, protocol,
433443 * status message, headers, data and redirect status.
434444 */
435- function drupal_http_request ($ url , $ headers = array (), $ method = 'GET ' , $ data = NULL , $ retry = 3 ) {
445+ function drupal_http_request ($ url , $ headers = array (), $ method = 'GET ' , $ data = NULL , $ retry = 3 , $ timeout = 30.0 ) {
436446 global $ db_prefix ;
437447
438448 $ result = new stdClass ();
@@ -452,18 +462,20 @@ function drupal_http_request($url, $headers = array(), $method = 'GET', $data =
452462 return $ result ;
453463 }
454464
465+ timer_start (__FUNCTION__ );
466+
455467 switch ($ uri ['scheme ' ]) {
456468 case 'http ' :
457469 case 'feed ' :
458470 $ port = isset ($ uri ['port ' ]) ? $ uri ['port ' ] : 80 ;
459471 $ host = $ uri ['host ' ] . ($ port != 80 ? ': ' . $ port : '' );
460- $ fp = @fsockopen ($ uri ['host ' ], $ port , $ errno , $ errstr , 15 );
472+ $ fp = @fsockopen ($ uri ['host ' ], $ port , $ errno , $ errstr , $ timeout );
461473 break ;
462474 case 'https ' :
463475 // Note: Only works for PHP 4.3 compiled with OpenSSL.
464476 $ port = isset ($ uri ['port ' ]) ? $ uri ['port ' ] : 443 ;
465477 $ host = $ uri ['host ' ] . ($ port != 443 ? ': ' . $ port : '' );
466- $ fp = @fsockopen ('ssl:// ' . $ uri ['host ' ], $ port , $ errno , $ errstr , 20 );
478+ $ fp = @fsockopen ('ssl:// ' . $ uri ['host ' ], $ port , $ errno , $ errstr , $ timeout );
467479 break ;
468480 default :
469481 $ result ->error = 'invalid schema ' . $ uri ['scheme ' ];
@@ -537,11 +549,25 @@ function drupal_http_request($url, $headers = array(), $method = 'GET', $data =
537549
538550 $ result ->request = $ request ;
539551
540- fwrite ($ fp , $ request );
552+ // Calculate how much time is left of the original timeout value.
553+ $ time_left = $ timeout - timer_read (__FUNCTION__ ) / 1000 ;
554+ if ($ time_left > 0 ) {
555+ stream_set_timeout ($ fp , floor ($ time_left ), floor (1000000 * fmod ($ time_left , 1 )));
556+ fwrite ($ fp , $ request );
557+ }
541558
542559 // Fetch response.
543560 $ response = '' ;
544- while (!feof ($ fp ) && $ chunk = fread ($ fp , 1024 )) {
561+ while (!feof ($ fp )) {
562+ // Calculate how much time is left of the original timeout value.
563+ $ time_left = $ timeout - timer_read (__FUNCTION__ ) / 1000 ;
564+ if ($ time_left <= 0 ) {
565+ $ result ->code = HTTP_REQUEST_TIMEOUT ;
566+ $ result ->error = 'request timed out ' ;
567+ return $ result ;
568+ }
569+ stream_set_timeout ($ fp , floor ($ time_left ), floor (1000000 * fmod ($ time_left , 1 )));
570+ $ chunk = fread ($ fp , 1024 );
545571 $ response .= $ chunk ;
546572 }
547573 fclose ($ fp );
@@ -590,9 +616,13 @@ function drupal_http_request($url, $headers = array(), $method = 'GET', $data =
590616 case 302 : // Moved temporarily
591617 case 307 : // Moved temporarily
592618 $ location = $ result ->headers ['Location ' ];
593-
594- if ($ retry ) {
595- $ result = drupal_http_request ($ result ->headers ['Location ' ], $ headers , $ method , $ data , --$ retry );
619+ $ timeout -= timer_read (__FUNCTION__ ) / 1000 ;
620+ if ($ timeout <= 0 ) {
621+ $ result ->code = HTTP_REQUEST_TIMEOUT ;
622+ $ result ->error = 'request timed out ' ;
623+ }
624+ elseif ($ retry ) {
625+ $ result = drupal_http_request ($ result ->headers ['Location ' ], $ headers , $ method , $ data , --$ retry , $ timeout );
596626 $ result ->redirect_code = $ result ->code ;
597627 }
598628 $ result ->redirect_url = $ location ;
@@ -623,7 +653,7 @@ function drupal_error_handler($errno, $message, $filename, $line, $context) {
623653 return ;
624654 }
625655
626- if ($ errno & (E_ALL ^ E_DEPRECATED ^ E_NOTICE )) {
656+ if ($ errno & (E_ALL ^ E_DEPRECATED )) {
627657 $ types = array (1 => 'error ' , 2 => 'warning ' , 4 => 'parse error ' , 8 => 'notice ' , 16 => 'core error ' , 32 => 'core warning ' , 64 => 'compile error ' , 128 => 'compile warning ' , 256 => 'user error ' , 512 => 'user warning ' , 1024 => 'user notice ' , 2048 => 'strict warning ' , 4096 => 'recoverable fatal error ' );
628658
629659 // For database errors, we want the line number/file name of the place that
@@ -645,7 +675,9 @@ function drupal_error_handler($errno, $message, $filename, $line, $context) {
645675 }
646676 }
647677
648- $ entry = check_plain ($ types [$ errno ]) .': ' . filter_xss ($ message ) .' in ' . check_plain ($ filename ) .' on line ' . check_plain ($ line ) .'. ' ;
678+ // Try to use filter_xss(). If it's too early in the bootstrap process for
679+ // filter_xss() to be loaded, use check_plain() instead.
680+ $ entry = check_plain ($ types [$ errno ]) .': ' . (function_exists ('filter_xss ' ) ? filter_xss ($ message ) : check_plain ($ message )) .' in ' . check_plain ($ filename ) .' on line ' . check_plain ($ line ) .'. ' ;
649681
650682 // Force display of error messages in update.php.
651683 if (variable_get ('error_level ' , 1 ) == 1 || strstr ($ _SERVER ['SCRIPT_NAME ' ], 'update.php ' )) {
@@ -1789,8 +1821,11 @@ function drupal_add_link($attributes) {
17891821 *
17901822 * Typical candidates for caching are for example styles for nodes across
17911823 * the site, or used in the theme.
1824+ *
17921825 * @return
17931826 * An array of CSS files.
1827+ *
1828+ * @see drupal_get_css()
17941829 */
17951830function drupal_add_css ($ path = NULL , $ type = 'module ' , $ media = 'all ' , $ preprocess = TRUE ) {
17961831 static $ css = array ();
@@ -1836,8 +1871,11 @@ function drupal_add_css($path = NULL, $type = 'module', $media = 'all', $preproc
18361871 * @param $css
18371872 * (optional) An array of CSS files. If no array is provided, the default
18381873 * stylesheets array is used instead.
1874+ *
18391875 * @return
18401876 * A string of XHTML CSS tags.
1877+ *
1878+ * @see drupal_add_css()
18411879 */
18421880function drupal_get_css ($ css = NULL ) {
18431881 $ output = '' ;
0 commit comments