You are here

function advagg_install_check_via_http in Advanced CSS/JS Aggregation 7.2

Make sure http requests to css/js files work correctly.

Parameters

array $requirements: Array of requirements used in hook_requirements().

1 call to advagg_install_check_via_http()
advagg_requirements in ./advagg.install
Implements hook_requirements().

File

./advagg.install, line 1346
Handles Advanced Aggregation installation and upgrade tasks.

Code

function advagg_install_check_via_http(array &$requirements) {

  // If other checks have not passed, do not test this.
  if (!empty($requirements)) {
    return;
  }

  // Ensure translations don't break at install time.
  $t = get_t();

  // Setup some variables.
  list($css_path, $js_path) = advagg_get_root_files_dir();
  $types = array(
    'css',
    'js',
  );
  $config_path = advagg_admin_config_root_path();

  // Get s3fs no_rewrite_cssjs setting.
  $s3fs_no_rewrite_cssjs = advagg_get_s3fs_config('no_rewrite_cssjs');

  // Make sure we get an advagg fast 404.
  $mod_url = FALSE;
  if (!variable_get('maintenance_mode', FALSE) && !variable_get('advagg_skip_404_check', FALSE)) {
    foreach ($types as $type) {
      if ($type === 'css') {
        $url_path = $css_path[0];
        $file_path = $css_path[1];
      }
      elseif ($type === 'js') {
        $url_path = $js_path[0];
        $file_path = $js_path[1];
      }

      // Set arguments for drupal_http_request().
      // Make a 404 request to the advagg menu callback.
      $url = file_create_url($url_path . '/' . $type . ADVAGG_SPACE . REQUEST_TIME . '.' . $type);
      $options = array(
        'timeout' => 8,
      );
      if (empty($url)) {
        $filename_path = !is_null($s3fs_no_rewrite_cssjs) && empty($s3fs_no_rewrite_cssjs) ? $url_path : $file_path;
        $filename = advagg_install_get_first_advagg_file($filename_path, $type);
        $url = file_create_url($url_path . '/' . $filename);
        $end = strpos($url, $filename);
        if ($end !== FALSE) {
          $url = substr($url, 0, $end) . $type . ADVAGG_SPACE . REQUEST_TIME . '.' . $type;
        }
        else {
          $requirements['advagg_self_request'] = array(
            'title' => $t('Adv CSS/JS Agg - Self Request Failure'),
            'severity' => REQUIREMENT_ERROR,
            'value' => $t('The uri: %url can not be converted to a url.', array(
              '%url' => $url_path . '/' . $type . ADVAGG_SPACE . REQUEST_TIME . '.' . $type,
            )),
            'description' => $t('If you are using a non default stream wrapper this might be the issue.'),
          );
          continue;
        }
      }

      // Send request.
      advagg_install_url_mod($url, $options, $mod_url);
      $request = drupal_http_request($url, $options);

      // Try an alt URL if the request code is not positive.
      if ($request->code < 0) {
        $mod_url = TRUE;
        advagg_install_url_mod($url, $options, $mod_url);
        $new_request = drupal_http_request($url, $options);
        if ($new_request->code < 0) {
          $description = '';
          if (!module_exists('httprl')) {
            $description = t('Enabling the <a href="!httprl">HTTP Parallel Request and Threading Library</a> module might be able to fix this as AdvAgg will use HTTPRL to build the URL if it is enabled.', array(
              '!httprl' => 'https://drupal.org/project/httprl',
            ));
          }
          $requirements['advagg_self_request'] = array(
            'title' => $t('Adv CSS/JS Agg - Self Request Failure'),
            'severity' => REQUIREMENT_ERROR,
            'value' => $t('HTTP loopback requests to this server are returning a non positive response code of %code', array(
              '%code' => $new_request->code,
            )),
            'description' => $t('If you have manually verified that AdvAgg is working correctly you can set the advagg_skip_404_check variable to TRUE in your settings.php. Editing the servers hosts file so the host name points to the localhost might also fix this (127.0.0.1 !hostname). To manually check go to <a href="@url">@url</a>, view the source (press ctrl+u on your keyboard) and check for this string <code>@string</code>. If that string is in the source, you can safely add this to your settings.php file <code>@code</code>', array(
              '!hostname' => $_SERVER['HTTP_HOST'],
              '@url' => $url,
              '@string' => '<!-- advagg_missing_fast404 -->',
              '@code' => '$conf[\'advagg_skip_404_check\'] = TRUE;',
            )) . ' ' . $description,
          );

          // Skip the rest of the advagg checks as they will all fail.
          $types = array();
          break;
        }
        else {
          $request = $new_request;
        }
      }

      // Try request without https.
      if ($request->code == 0 && isset($request->error) && stripos($request->error, 'Error opening socket ssl://') !== FALSE) {
        $url = advagg_force_http_path($url);
        $request = drupal_http_request($url, $options);
      }

      // Try request to 127.0.0.1.
      if ($request->code == 0 && isset($request->error) && stripos($request->error, 'getaddrinfo failed') !== FALSE) {
        $parts = @parse_url($url);
        if ($parts['host'] !== '127.0.0.1') {
          $options['headers']['Host'] = $parts['host'];
          $parts['host'] = '127.0.0.1';
          $url = advagg_glue_url($parts);
          $request = drupal_http_request($url, $options);
        }
      }

      // Check response. Report an error if
      // - Not a 404 OR
      // - No data returned OR
      // -  Headers do not contain "x-advagg" AND
      // -  Body does not contain "advagg_missing_fast404".
      if ($request->code != 404 || empty($request->data) || empty($request->headers['x-advagg']) && strpos($request->data, '<!-- advagg_missing_fast404 -->') === FALSE) {

        // Fast 404 check.
        $url_path_404 = parse_url($url, PHP_URL_PATH);
        $exclude_paths = variable_get('404_fast_paths_exclude', FALSE);
        $fast_404_html = variable_get('404_fast_html', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>');

        // Replace @path in the variable with the page path.
        $fast_404_html = trim(strtr($fast_404_html, array(
          '@path' => check_plain($url_path_404),
        )));
        if (!empty($request->data) && $fast_404_html == trim($request->data) && !empty($exclude_paths) && strpos($exclude_paths, 'advagg_') === FALSE) {
          $pos_a = strpos($exclude_paths, '(?:styles)');
          $pos_b = strpos($exclude_paths, '(?:styles|');
          if ($exclude_paths === '/\\/(?:styles)\\//') {
            $description = $t('Change it from <code> %value </code> to <code>/\\/(?:styles|advagg_(cs|j)s)\\//</code>', array(
              '%value' => $exclude_paths,
            ));
          }
          elseif ($pos_a !== FALSE) {
            $description = $t('Change it from <code> %value </code> to <code> %code </code>', array(
              '%value' => $exclude_paths,
              '%code' => str_replace('(?:styles)', '(?:styles|advagg_(cs|j)s)', $exclude_paths),
            ));
          }
          elseif ($pos_b !== FALSE) {
            $description = $t('Change it from <code> %value </code> to <code> %code </code>', array(
              '%value' => $exclude_paths,
              '%code' => str_replace('(?:styles|', '(?:styles|advagg_(cs|j)s|', $exclude_paths),
            ));
          }
          else {
            $description = $t('Add in <code>advagg_(cs|j)s</code> into the regex. Current value: %value', array(
              '%value' => $exclude_paths,
            ));
          }
          $requirements['advagg_404_fast_' . $type . '_generation'] = array(
            'title' => $t('Adv CSS/JS Agg - Fast 404: HTTP Request'),
            'severity' => REQUIREMENT_ERROR,
            'value' => $t('HTTP requests to advagg for ' . $type . ' files are not getting through.'),
            'description' => $t('If you have fast 404 enabled in your settings.php file, you need to change the <code>404_fast_paths_exclude</code> setting so advagg will work.') . ' ' . $description,
          );
        }
        elseif (module_exists('fast_404') && defined('FAST_404_EXT_CHECKED') && !in_array('/advagg_', variable_get('fast_404_string_whitelisting', array())) && strpos(variable_get('fast_404_exts', '/^(?!robots).*\\.(txt|png|gif|jpe?g|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$/i'), $type) !== FALSE) {
          $requirements['advagg_fast_404_module_' . $type . '_generation'] = array(
            'title' => $t('Adv CSS/JS Agg - Fast 404: HTTP Request'),
            'severity' => REQUIREMENT_ERROR,
            'value' => $t('HTTP requests to advagg for ' . $type . ' files are not getting through.'),
            'description' => $t('The fast 404 module is enabled. You need to change the <code>fast_404_string_whitelisting</code> setting so advagg will work. In your settings.php file add in the code below: <pre>@code</pre>', array(
              '@code' => '$conf[\'fast_404_string_whitelisting\'][] = \'/advagg_\';',
            )),
          );
        }
        elseif (module_exists('stage_file_proxy') && variable_get('stage_file_proxy_origin', NULL) && strpos(advagg_file_get_contents(drupal_get_path('module', 'stage_file_proxy') . '/stage_file_proxy.module'), 'advagg') === FALSE) {

          // Stage File Proxy patch is missing.
          $requirements['advagg_stage_file_proxy_' . $type . '_generation'] = array(
            'title' => $t('Adv CSS/JS Agg - Fast 404: HTTP Request'),
            'severity' => REQUIREMENT_ERROR,
            'value' => $t('HTTP requests to advagg for ' . $type . ' files are not getting through.'),
            'description' => $t('If you have the <a href="@module">Stage File Proxy</a> module enabled, make sure <a href="@patch">this patch</a> has been applied.', array(
              '@patch' => 'https://drupal.org/node/1977170#comment-7331810',
              '@module' => 'https://drupal.org/project/stage_file_proxy',
            )),
          );
        }
        elseif (!variable_get('clean_url', 0)) {
          $requirements['advagg_clean_url'] = array(
            'title' => $t('Adv CSS/JS Agg - Clean URLs'),
            'value' => $t('HTTP requests to advagg for ' . $type . ' files are not getting through.'),
            'severity' => REQUIREMENT_ERROR,
            'description' => $t('Go to the <a href="@settings">clean URL settings page</a> and enable Clean URLs.', array(
              '@settings' => url('admin/config/search/clean-urls'),
            )),
          );
        }
        elseif ($request->code == 401) {
          $requirements['advagg_set_user_pass'] = array(
            'title' => $t('Adv CSS/JS Agg - Set Basic Auth'),
            'value' => $t('HTTP requests to advagg for @type files are not getting through.', array(
              '@type' => $type,
            )),
            'severity' => REQUIREMENT_ERROR,
            'description' => $t('Authorization is required when accessing your site. In order to test that the @type files are working you will need to add the following code in your settings.php file: <p><code>@code1</code><br><code>@code2</code></p> filling in the correct username and password needed to access this site.', array(
              '@code1' => '$conf[\'advagg_auth_basic_user\'] = \'\'; ',
              '@code2' => '$conf[\'advagg_auth_basic_pass\'] = \'\';',
              '@type' => $type,
            )),
          );
        }
        elseif ($request->code == 403) {
          $requirements['advagg_' . $type . '_server_permissions'] = array(
            'title' => $t('Adv CSS/JS Agg - Webserver can not access files'),
            'value' => $t('HTTP requests to advagg for @type files are not getting through.', array(
              '@type' => $type,
            )),
            'severity' => REQUIREMENT_ERROR,
            'description' => $t('Your webserver can not access @type advagg files. This is usually a server permissions issue. Raw request info: <pre>@request</pre>', array(
              '@type' => $type,
              '@request' => var_export($request, TRUE),
            )),
          );
        }
        elseif (isset($request->data) && stripos($request->data, 'nginx')) {
          $config_location = '';
          if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
            $config_location = ' ' . $t('You might be able to find the nginx configuration file by running <pre>@command_1</pre> or <pre>@command_2</pre>', array(
              '@command_1' => 'ps -o args -C nginx',
              '@command_2' => 'nginx -t',
            ));
          }
          $requirements['advagg_' . $type . '_nginx_config'] = array(
            'title' => $t('Adv CSS/JS Agg - Nginx not sending 404 to Drupal.'),
            'value' => $t('HTTP requests to advagg for @type files are not getting through.', array(
              '@type' => $type,
            )),
            'severity' => REQUIREMENT_ERROR,
            'description' => $t('Your nginx webserver is not sending 404s to drupal. Please make sure that your nginx configuration has something like this in it: <p><pre><code>@code</code></pre></p> Note that @drupal (last line of code above) might be @rewrite or @rewrites depending on your servers configuration. If there are image style rules in your Nginx configuration add this right below that. !config_location Raw request info: <pre>@request</pre>', array(
              '@request' => var_export($request, TRUE),
              '@code' => '
###
### advagg_css and advagg_js support
###
location ~* files/advagg_(?:css|js)/ {
  gzip_static on;
  access_log  off;
  expires     max;
  add_header  ETag "";
  add_header  Cache-Control "max-age=31449600, no-transform, public";
  try_files   $uri $uri/ @drupal;
}',
              '!config_location' => $config_location,
            )),
          );
        }
        elseif (!advagg_install_htaccess_errordocument($type)) {
          $parsed_base_url = parse_url($GLOBALS['base_url']);
          if (isset($parsed_base_url['scheme'])) {
            unset($parsed_base_url['scheme']);
          }
          if ($type === 'css') {
            $location = $css_path[1] . '/.htaccess';
          }
          if ($type === 'js') {
            $location = $js_path[1] . '/.htaccess';
          }
          $requirements['advagg_' . $type . '_errordoc_404'] = array(
            'title' => $t('Adv CSS/JS Agg - HTTP Request'),
            'severity' => REQUIREMENT_WARNING,
            'value' => $t('HTTP requests to advagg for ' . $type . ' files are not getting through. The .htaccess needs to be rebuilt.'),
            'description' => $t('The .htaccess file generated by AdvAgg has the incorrect errordoc location. This can happen if Drush is used incorrectly or if the site has been moved to a different directory structure. If you are currently using drush this is how to access it correctly: <p><code>@drush</code></p> Odds are you will need to fix the errordoc location. Go to the <a href="@url">AdvAgg: Operations</a> page and under Regenerate .htaccess files press the Recreate htaccess files button. If you wish to manually edit the file go to the <code>@htaccess_loc</code> file and make sure the following line is in there near the top and any other ErrorDocument 404 statements have been removed. <p><code>@code</code></p>', array(
              '@drush' => 'drush --root=' . DRUPAL_ROOT . '/ --uri=' . advagg_glue_url($parsed_base_url) . ' ',
              '@url' => url($config_path . '/advagg/operations', array(
                'fragment' => 'edit-htaccess',
              )),
              '@htaccess_loc' => $location,
              '@code' => "  ErrorDocument 404 {$GLOBALS['base_path']}index.php",
            )),
          );
        }
        elseif (!is_null($s3fs_no_rewrite_cssjs) && !empty($s3fs_no_rewrite_cssjs) && !empty($request->headers['server']) && $request->headers['server'] === 'AmazonS3') {
          $severity = REQUIREMENT_WARNING;
          if (module_exists('httprl') && variable_get('advagg_use_httprl', ADVAGG_USE_HTTPRL)) {
            $severity = REQUIREMENT_ERROR;
          }

          // S3 doesn't do origin pull.
          $requirements['advagg_' . $type . '_generation'] = array(
            'title' => $t('Adv CSS/JS Agg - HTTP Request'),
            'severity' => $severity,
            'value' => $t('HTTP requests to advagg for ' . $type . ' files are not getting through.'),
            'description' => $t('AdvAgg will issue a request for a file that does not exist inside of the AdvAgg directory. If AdvAgg sends a 404, everything is ok; if something else sends a 404 then that means that AdvAgg will not be able to generate an aggregate if it is missing as something else is handling the 404 before AdvAgg has a chance to do it. If you are reading this, it means that something else is handling the 404 before AdvAgg can. In this case the <a href="@url">s3fs Advanced Configuration Option "Don\'t render proxied CSS/JS file paths"</a> should be disabled. Raw request info: <pre>@request</pre>', array(
              '@request' => var_export($request, TRUE),
              '@url' => url('admin/config/media/s3fs', array(
                'fragment' => 'edit-s3fs-no-rewrite-cssjs',
              )),
            )),
          );
        }
        else {

          // Menu callback failed.
          $requirements['advagg_' . $type . '_generation'] = array(
            'title' => $t('Adv CSS/JS Agg - HTTP Request'),
            'severity' => REQUIREMENT_ERROR,
            'value' => $t('HTTP requests to advagg for ' . $type . ' files are not getting through.'),
            'description' => $t('AdvAgg will issue a request for a file that does not exist inside of the AdvAgg directory. If AdvAgg sends a 404, everything is ok; if something else sends a 404 then that means that AdvAgg will not be able to generate an aggregate if it is missing as something else is handling the 404 before AdvAgg has a chance to do it. If you are reading this, it means that something else is handling the 404 before AdvAgg can. In some cases this can sometimes be a false report; go here: <a href="@url">@url</a> and check if the source (press ctrl+u on your keyboard) has an html comment that says "advagg_missing_fast404"; if it does, this is a false report, add this <code>$conf[\'advagg_skip_404_check\'] = TRUE;</code> to your settings.php file. Raw request info: <pre>@request</pre>', array(
              '@request' => var_export($request, TRUE),
              '@url' => $url,
            )),
          );
        }
      }
    }
  }
  elseif (variable_get('maintenance_mode', FALSE)) {
    $requirements['advagg_maintenance_mode'] = array(
      'title' => $t('Adv CSS/JS Agg - HTTP Request'),
      'severity' => REQUIREMENT_WARNING,
      'value' => $t("HTTP requests to advagg's 404 handler can not be tested currently."),
      'description' => $t('This can not be tested while the site is in <a href="@maintenance">maintenance mode</a>', array(
        '@maintenance' => url('admin/config/development/maintenance'),
      )),
    );
  }

  // Check gzip encoding.
  foreach ($types as $type) {
    if ($type === 'css') {
      $url_path = $css_path[0];
      $file_path = $css_path[1];
    }
    elseif ($type === 'js') {
      $url_path = $js_path[0];
      $file_path = $js_path[1];
    }

    // Get filename.
    $filename_path = !is_null($s3fs_no_rewrite_cssjs) && empty($s3fs_no_rewrite_cssjs) ? $url_path : $file_path;
    $filename = advagg_install_get_first_advagg_file($filename_path, $type);

    // Skip if filename is empty.
    if (empty($filename)) {
      continue;
    }
    $urls = array();
    $url = file_create_url($url_path . '/' . $filename);
    if (empty($url)) {
      continue;
    }
    $urls[] = $url;
    if (module_exists('cdn')) {

      // Get CDN defaults.
      $blacklist = variable_get(CDN_EXCEPTION_DRUPAL_PATH_BLACKLIST_VARIABLE, CDN_EXCEPTION_DRUPAL_PATH_BLACKLIST_DEFAULT);
      $auth_blacklist = variable_get(CDN_EXCEPTION_AUTH_USERS_BLACKLIST_VARIABLE, CDN_EXCEPTION_AUTH_USERS_BLACKLIST_DEFAULT);

      // Set CDN blacklists to be empty.
      $GLOBALS['conf'][CDN_EXCEPTION_DRUPAL_PATH_BLACKLIST_VARIABLE] = '';
      $GLOBALS['conf'][CDN_EXCEPTION_AUTH_USERS_BLACKLIST_VARIABLE] = '';

      // Create URL.
      $urls[] = file_create_url($url_path . '/' . $filename);

      // Set CDN blacklist back to the original value.
      $GLOBALS['conf'][CDN_EXCEPTION_DRUPAL_PATH_BLACKLIST_VARIABLE] = $blacklist;
      $GLOBALS['conf'][CDN_EXCEPTION_AUTH_USERS_BLACKLIST_VARIABLE] = $auth_blacklist;
    }
    $urls = array_unique($urls);

    // Set arguments for drupal_http_request().
    $options = array(
      'headers' => array(
        'Accept-Encoding' => 'gzip, deflate',
      ),
      'version' => '1.0',
      '#advagg_path' => "{$file_path}/{$filename}",
      'timeout' => 8,
    );

    // Test http 1.0.
    $old_requirements = $requirements;
    advagg_install_chk_urls($requirements, $urls, $options, $mod_url, $type, $url_path, $file_path, $filename);

    // Test http 1.1
    // If Drupal version is >= 7.22 and httprl_override_core exists.
    if (defined('VERSION') && floatval(VERSION) >= 7.22 && is_callable('httprl_override_core')) {
      $old = variable_get('drupal_http_request_function', FALSE);
      $GLOBALS['conf']['drupal_http_request_function'] = 'httprl_override_core';

      // Only test 1.1; 1.0 is rarely used these days.
      $requirements = $old_requirements;
      $options['version'] = '1.1';
      advagg_install_chk_urls($requirements, $urls, $options, $mod_url, $type, $url_path, $file_path, $filename);
      $GLOBALS['conf']['drupal_http_request_function'] = $old;
    }
    if (function_exists('brotli_compress') && defined('BROTLI_TEXT') && variable_get('advagg_brotli', ADVAGG_BROTLI)) {

      // Set arguments for drupal_http_request().
      $options = array(
        'headers' => array(
          'Accept-Encoding' => 'br',
        ),
        'version' => '1.0',
        'timeout' => 8,
      );

      // Test http 1.0.
      $old_requirements = $requirements;
      advagg_install_chk_urls($requirements, $urls, $options, $mod_url, $type, $url_path, $file_path, $filename);

      // Test http 1.1
      // If Drupal version is >= 7.22 and httprl_override_core exists.
      if (defined('VERSION') && floatval(VERSION) >= 7.22 && is_callable('httprl_override_core')) {
        $old = variable_get('drupal_http_request_function', FALSE);
        $GLOBALS['conf']['drupal_http_request_function'] = 'httprl_override_core';

        // Only test 1.1; 1.0 is rarely used these days.
        $requirements = $old_requirements;
        $options['version'] = '1.1';
        advagg_install_chk_urls($requirements, $urls, $options, $mod_url, $type, $url_path, $file_path, $filename);
        $GLOBALS['conf']['drupal_http_request_function'] = $old;
      }
    }
  }
}