diff --git a/core/includes/file.inc b/core/includes/file.inc
index 26dfb64..7599aa0 100644
--- a/core/includes/file.inc
+++ b/core/includes/file.inc
@@ -1320,9 +1320,11 @@ function file_unmanaged_save_data($data, $destination = NULL, $replace = FILE_EX
  *   An array of HTTP headers to send along with file.
  */
 function file_transfer($uri, $headers) {
-  return new StreamedResponse(function() use ($uri) {
+  return new StreamedResponse(function() use ($uri, $headers) {
     // Transfer file in 1024 byte chunks to save memory usage.
     if (file_exists($uri) && $fd = fopen($uri, 'rb')) {
+      // Notify other modules that file transfer started.
+      module_invoke_all('file_transferring', $uri, $headers);
       while (!feof($fd)) {
         print fread($fd, 1024);
       }
diff --git a/core/modules/file/file.api.php b/core/modules/file/file.api.php
index fb59229..ea0ea63 100644
--- a/core/modules/file/file.api.php
+++ b/core/modules/file/file.api.php
@@ -71,6 +71,22 @@ function hook_file_presave(Drupal\file\File $file) {
 }
 
 /**
+ * Act on begin of file transfer.
+ *
+ * This hook is called when a file has begun transferring.
+ *
+ * @param $uri
+ *   String specifying the file path to transfer.
+ * @param $headers
+ *   An array of HTTP headers to send along with file.
+ *
+ * @see file_transfer()
+ */
+function hook_file_transferring($source, $headers) {
+  watchdog('file', 'File transfer started', array(), WATCHDOG_DEBUG);
+}
+
+/**
  * Respond to a file being added.
  *
  * This hook is called after a file has been added to the database. The hook
diff --git a/core/modules/file/lib/Drupal/file/Tests/DownloadTest.php b/core/modules/file/lib/Drupal/file/Tests/DownloadTest.php
index 0763507..2fba7ba 100644
--- a/core/modules/file/lib/Drupal/file/Tests/DownloadTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/DownloadTest.php
@@ -66,6 +66,9 @@ function testPrivateFileTransfer() {
     $this->assertEqual($headers['x-foo'], 'Bar', t('Found header set by file_test module on private download.'));
     $this->assertResponse(200, t('Correctly allowed access to a file when file_test provides headers.'));
 
+    // Check whether required hooks were called.
+    $this->assertFileHooksCalled(array('load', 'download', 'transferring'));
+
     // Test that the file transfered correctly.
     $this->assertEqual($contents, $this->content, t('Contents of the file are correct.'));
 
diff --git a/core/modules/file/tests/file_test/file_test.module b/core/modules/file/tests/file_test/file_test.module
index 20039e7..279a7a5 100644
--- a/core/modules/file/tests/file_test/file_test.module
+++ b/core/modules/file/tests/file_test/file_test.module
@@ -147,6 +147,7 @@ function file_test_reset() {
     'load' => array(),
     'validate' => array(),
     'download' => array(),
+    'transferring' => array(),
     'insert' => array(),
     'update' => array(),
     'copy' => array(),
@@ -169,7 +170,7 @@ function file_test_reset() {
  *
  * @param $op
  *   One of the hook_file_* operations: 'load', 'validate', 'download',
- *   'insert', 'update', 'copy', 'move', 'delete'.
+ *   'insert', 'update', 'copy', 'move', 'delete', 'transferring'.
  *
  * @return
  *   Array of the parameters passed to each call.
@@ -199,7 +200,7 @@ function file_test_get_all_calls() {
  *
  * @param $op
  *   One of the hook_file_* operations: 'load', 'validate', 'download',
- *   'insert', 'update', 'copy', 'move', 'delete'.
+ *   'insert', 'update', 'copy', 'move', 'delete', 'transferring'.
  * @param $args
  *   Values passed to hook.
  *
@@ -419,6 +420,13 @@ function file_test_file_mimetype_mapping_alter(&$mapping) {
 }
 
 /**
+ * Implements hook_file_transferring().
+ */
+function file_test_file_transferring($uri, $headers) {
+  _file_test_log_call('transferring', array($uri, $headers));
+}
+
+/**
  * Helper validator that returns the $errors parameter.
  */
 function file_test_validator(File $file, $errors) {
