/** * Sets extra headers on successful responses. * * @param Symfony\Component\HttpKernel\Event\FilterResponseEvent $event * The event to process. */ public function onRespond(FilterResponseEvent $event) { if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) { return; } $request = $event->getRequest(); $response = $event->getResponse(); // Set the X-UA-Compatible HTTP header to force IE to use the most recent // rendering engine or use Chrome's frame rendering engine if available. $response->headers->set('X-UA-Compatible', 'IE=edge,chrome=1', FALSE); // Set the Content-language header. $response->headers->set('Content-language', $this->languageManager->getCurrentLanguage()->id); // Attach globally-declared headers to the response object so that Symfony // can send them for us correctly. // @todo remove this once we have removed all drupal_add_http_header() // calls. $headers = drupal_get_http_header(); foreach ($headers as $name => $value) { $response->headers->set($name, $value, FALSE); } $is_cacheable = drupal_page_is_cacheable(); // Add headers necessary to specify whether the response should be cached by // proxies and/or the browser. if ($is_cacheable && $this->config->get('cache.page.max_age') > 0) { if (!$this->isCacheControlCustomized($response)) { $this->setResponseCacheable($response, $request); } } else { $this->setResponseNotCacheable($response, $request); } // Currently it is not possible to cache some types of responses. Therefore // exclude binary file responses (generated files, e.g. images with image // styles) and streamed responses (files directly read from the disk). // see: https://github.com/symfony/symfony/issues/9128#issuecomment-25088678 if ($is_cacheable && $this->config->get('cache.page.use_internal') && !$response instanceof BinaryFileResponse && !$response instanceof StreamedResponse) { // Store the response in the internal page cache. drupal_page_set_cache($response, $request); $response->headers->set('X-Drupal-Cache', 'MISS'); drupal_serve_page_from_cache($response, $request); } }
/** * Allow other modules to modify $children & $elements before they are rendered. * * @param $children * An array of children elements. * @param $elements * A render array containing: * - #items: The JavaScript items as returned by drupal_add_js() and * altered by drupal_get_js(). * - #group_callback: A function to call to group #items. Following * this function, #aggregate_callback is called to aggregate items within * the same group into a single file. * - #aggregate_callback: A function to call to aggregate the items within * the groups arranged by the #group_callback function. * * @see advagg_modify_js_pre_render() * @see advagg_js_compress_advagg_modify_js_pre_render_alter() */ function hook_advagg_modify_js_pre_render_alter(&$children, &$elements) { // Get variables. $aggregate_settings['variables']['advagg_js_compressor'] = variable_get('advagg_js_inline_compressor', ADVAGG_JS_INLINE_COMPRESSOR); $aggregate_settings['variables']['advagg_js_max_compress_ratio'] = variable_get('advagg_js_max_compress_ratio', ADVAGG_JS_MAX_COMPRESS_RATIO); // Do nothing if the compressor is disabled. if (empty($aggregate_settings['variables']['advagg_js_compressor'])) { return; } // Do nothing if the page is not cacheable and inline compress if not // cacheable is not checked. if (!variable_get('advagg_js_inline_compress_if_not_cacheable', ADVAGG_JS_INLINE_COMPRESS_IF_NOT_CACHEABLE) && !drupal_page_is_cacheable()) { return; } // Compress any inline JS. module_load_include('inc', 'advagg_js_compress', 'advagg_js_compress.advagg'); foreach ($children as $key => &$values) { if (!empty($values['#value'])) { $contents = $values['#value']; $filename = drupal_hash_base64($contents); advagg_js_compress_prep($contents, $filename, $aggregate_settings, FALSE); $values['#value'] = $contents; } } }
/** * Get the user account for the request. * * @param array $request * The request. * @param string $method * The HTTP method. * @param boolean $cache * Boolean indicating if the resolved user should be cached for next calls. * * @throws RestfulUnauthorizedException * @return \stdClass * The user object. */ public function getAccount(array $request = array(), $method = \RestfulInterface::GET, $cache = TRUE) { global $user; // Return the previously resolved user, if any. if (!empty($this->account)) { return $this->account; } // Resolve the user based on the providers in the manager. $account = NULL; foreach ($this as $provider) { if ($provider->applies($request, $method) && $account = $provider->authenticate($request, $method)) { // The account has been loaded, we can stop looking. break; } } if (!$account) { if ($this->count() && !$this->getIsOptional()) { // Allow caching pages for anonymous users. drupal_page_is_cacheable(variable_get('restful_page_cache', FALSE)); // User didn't authenticate against any provider, so we throw an error. throw new \RestfulUnauthorizedException('Bad credentials'); } // If the account could not be authenticated default to the global user. // Most of the cases the cookie provider will do this for us. $account = drupal_anonymous_user(); if (empty($request['__application']['rest_call'])) { // If we are using the API from within Drupal and we have not tried to // authenticate using the 'cookie' provider, then we expect to be logged // in using the cookie authentication as a last resort. $account = $user->uid ? user_load($user->uid) : $account; } } if ($cache) { $this->setAccount($account); } // Disable page caching for security reasons so that an authenticated user // response never gets into the page cache for anonymous users. // This is necessary because the page cache system only looks at session // cookies, but not at HTTP Basic Auth headers. drupal_page_is_cacheable(!$account->uid && variable_get('restful_page_cache', FALSE)); // Record the access time of this request. $this->setAccessTime($account); return $account; }
/** * Get kernel * * @return KernelInterface */ private function getKernel() { if (!$this->kernel) { if (!self::$bootstrapped) { // Avoid Drupal attempt to return a cached page while we are // actually unit testing it drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); $GLOBALS['conf']['cache'] = 0; drupal_page_is_cacheable(false); drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); self::$bootstrapped = true; } $this->kernel = $this->createKernelInstance(uniqid('test_')); $this->kernel->boot(); $this->kernel->getContainer()->get('request_stack')->push(\MakinaCorpus\Drupal\Sf\Http\Request::createFromGlobals()); \Drupal::_setKernel($this->kernel); } return $this->kernel; }
/** * Default constructor. */ public function __construct() { global $user, $is_https; $this->httpsEnabled = $this->handleHttps() && $is_https; $this->sessionName = session_name(); if ($this->httpsEnabled) { $this->sessionNameUnsecure = substr(session_name(), 1); } if (!empty($_COOKIE[$this->sessionName]) || $this->httpsEnabled && !empty($_COOKIE[$this->sessionNameUnsecure])) { // If a session cookie exists, initialize the session. Otherwise the // session is only started on demand in drupal_session_commit(), making // anonymous users not use a session cookie unless something is stored in // $_SESSION. This allows HTTP proxies to cache anonymous page views. $this->start(); $this->sessionIdentifier = session_id(); $this->refreshAfterSessionChange(); if ($user->uid || !$this->sessionIsEmpty()) { drupal_page_is_cacheable(FALSE); } } else { // Set a session identifier for this request. This is necessary because // we lazily start sessions at the end of this request, and some // processes (like drupal_get_token()) needs to know the future // session ID in advance. $user = drupal_anonymous_user(); $this->generateSessionIdentifier(); $this->refreshAfterSessionChange(); } }
/** * Generates a derivative, given a style and image path. * * After generating an image, transfer it to the requesting agent. * * @param \Symfony\Component\HttpFoundation\Request $request * The request object. * @param string $scheme * The file scheme, defaults to 'private'. * @param \Drupal\image\ImageStyleInterface $image_style * The image style to deliver. * * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException * Thrown when the user does not have access to the file. * @throws \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException * Thrown when the file is still being generated. * * @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Symfony\Component\HttpFoundation\Response * The transferred file as response or some error response. */ public function deliver(Request $request, $scheme, ImageStyleInterface $image_style) { $target = $request->query->get('file'); $image_uri = $scheme . '://' . $target; // Check that the style is defined, the scheme is valid, and the image // derivative token is valid. Sites which require image derivatives to be // generated without a token can set the // 'image.settings:allow_insecure_derivatives' configuration to TRUE to // bypass the latter check, but this will increase the site's vulnerability // to denial-of-service attacks. $valid = !empty($image_style) && file_stream_wrapper_valid_scheme($scheme); if (!$this->config('image.settings')->get('allow_insecure_derivatives')) { $valid &= $request->query->get(IMAGE_DERIVATIVE_TOKEN) === $image_style->getPathToken($image_uri); } if (!$valid) { throw new AccessDeniedHttpException(); } $derivative_uri = $image_style->buildUri($image_uri); $headers = array(); // If using the private scheme, let other modules provide headers and // control access to the file. if ($scheme == 'private') { if (file_exists($derivative_uri)) { return parent::download($request, $scheme); } else { $headers = $this->moduleHandler()->invokeAll('file_download', array($image_uri)); if (in_array(-1, $headers) || empty($headers)) { throw new AccessDeniedHttpException(); } } } // Don't try to generate file if source is missing. if (!file_exists($image_uri)) { watchdog('image', 'Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', array('%source_image_path' => $image_uri, '%derivative_path' => $derivative_uri)); return new Response($this->t('Error generating image, missing source file.'), 404); } // Don't start generating the image if the derivative already exists or if // generation is in progress in another thread. $lock_name = 'image_style_deliver:' . $image_style->id() . ':' . Crypt::hashBase64($image_uri); if (!file_exists($derivative_uri)) { $lock_acquired = $this->lock->acquire($lock_name); if (!$lock_acquired) { // Tell client to retry again in 3 seconds. Currently no browsers are // known to support Retry-After. throw new ServiceUnavailableHttpException(3, $this->t('Image generation in progress. Try again shortly.')); } } // Try to generate the image, unless another thread just did it while we // were acquiring the lock. $success = file_exists($derivative_uri) || $image_style->createDerivative($image_uri, $derivative_uri); if (!empty($lock_acquired)) { $this->lock->release($lock_name); } if ($success) { drupal_page_is_cacheable(FALSE); $image = $this->imageFactory->get($derivative_uri); $uri = $image->getSource(); $headers += array('Content-Type' => $image->getMimeType(), 'Content-Length' => $image->getFileSize()); return new BinaryFileResponse($uri, 200, $headers); } else { watchdog('image', 'Unable to generate the derived image located at %path.', array('%path' => $derivative_uri)); return new Response($this->t('Error generating image.'), 500); } }
/** * {@inheritdoc} */ public function startLazy() { global $user; if (($this->started || $this->startedLazy) && !$this->closed) { return $this->started; } $is_https = $this->requestStack->getCurrentRequest()->isSecure(); $cookies = $this->requestStack->getCurrentRequest()->cookies; $insecure_session_name = $this->getInsecureName(); if ($cookies->has($this->getName()) && ($session_name = $cookies->get($this->getName())) || $is_https && $this->isMixedMode() && ($cookies->has($insecure_session_name) && ($session_name = $cookies->get($insecure_session_name)))) { // If a session cookie exists, initialize the session. Otherwise the // session is only started on demand in save(), making // anonymous users not use a session cookie unless something is stored in // $_SESSION. This allows HTTP proxies to cache anonymous pageviews. $result = $this->start(); if ($user->isAuthenticated() || !$this->isSessionObsolete()) { drupal_page_is_cacheable(FALSE); } } else { // Set a session identifier for this request. This is necessary because // we lazily start sessions at the end of this request, and some // processes (like \Drupal::csrfToken()) needs to know the future // session ID in advance. $user = new AnonymousUserSession(); $this->setId(Crypt::randomBytesBase64()); if ($is_https && $this->isMixedMode()) { $session_id = Crypt::randomBytesBase64(); $cookies->set($insecure_session_name, $session_id); } $result = FALSE; } date_default_timezone_set(drupal_get_user_timezone()); $this->startedLazy = TRUE; return $result; }
/** * {@inheritdoc} * * @todo Invoke proper request/response/terminate events. */ public function handlePageCache(Request $request) { $this->boot(); $this->initializeCookieGlobals($request); // Check for a cache mode force from settings.php. if (Settings::get('page_cache_without_database')) { $cache_enabled = TRUE; } else { $config = $this->getContainer()->get('config.factory')->get('system.performance'); $cache_enabled = $config->get('cache.page.use_internal'); } // If there is no session cookie and cache is enabled (or forced), try to // serve a cached page. if (!$request->cookies->has(session_name()) && $cache_enabled && drupal_page_is_cacheable()) { // Get the page from the cache. $response = drupal_page_get_cache($request); // If there is a cached page, display it. if ($response) { $response->headers->set('X-Drupal-Cache', 'HIT'); drupal_serve_page_from_cache($response, $request); // We are done. $response->prepare($request); $response->send(); exit; } } return $this; }