diff --git a/Cargo.lock b/Cargo.lock
index 95d8175e20044dae16458ad848fed16fbb86d772..20ec430d0b31bcabad08e876effff098151690c8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1973,18 +1973,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 
 [[package]]
 name = "serde"
-version = "1.0.131"
+version = "1.0.132"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1"
+checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.131"
+version = "1.0.132"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2"
+checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/Cargo.toml b/Cargo.toml
index 5f908aab2c50accf79b6613abd0dc33e956289b6..d9228585e5c98028f32737dde25a12f5b61eeaa5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,4 +23,4 @@ serde_json = "1"
 log = "^0.4.14"
 url = "2.2.2"
 simple-logging = { version = "^2.0.2" }
-sqlx = { version = "0.5", features = [  "runtime-async-std-native-tls", "sqlite" ] }
\ No newline at end of file
+sqlx = { version = "0.5", features = ["runtime-async-std-native-tls", "sqlite"] }
\ No newline at end of file
diff --git a/src/config.rs b/src/config.rs
index 810ab5b74703cb37c17b32a52d0d9e49246482d0..6d0377285eb48504bd5dca17ceb31f45922f9345 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -16,10 +16,10 @@ pub struct StorageOptions {
     /// This directory is used to store files
     /// for all *file_storage storages.
     #[structopt(
-    long,
-    default_value = "./data",
-    required_if("storage", "file_storage"),
-    required_if("storage", "sqlite_file_storage")
+        long,
+        default_value = "./data",
+        required_if("storage", "file_storage"),
+        required_if("storage", "sqlite_file_storage")
     )]
     pub data: PathBuf,
 
@@ -28,9 +28,9 @@ pub struct StorageOptions {
     /// This file is used to
     /// store information about uploaded files.
     #[structopt(
-    long,
-    default_value = "data/info.sqlite3",
-    required_if("storage", "sqlite_file_storage")
+        long,
+        default_value = "data/info.sqlite3",
+        required_if("storage", "sqlite_file_storage")
     )]
     pub sqlite_dsn: PathBuf,
 }
@@ -64,9 +64,9 @@ pub struct TuserConf {
 
     /// Enabled extensions for TUS protocol.
     #[structopt(
-    long,
-    default_value = "creation,creation-with-upload",
-    env = "TUSER_EXTENSIONS"
+        long,
+        default_value = "creation,creation-with-upload,getting",
+        env = "TUSER_EXTENSIONS"
     )]
     pub extensions: String,
 
@@ -80,6 +80,7 @@ pub enum ProtocolExtensions {
     CreationWithUpload,
     Creation,
     Termination,
+    Getting,
 }
 
 impl TryFrom<String> for ProtocolExtensions {
@@ -93,6 +94,7 @@ impl TryFrom<String> for ProtocolExtensions {
             "creation" => Ok(ProtocolExtensions::Creation),
             "creation-with-upload" => Ok(ProtocolExtensions::CreationWithUpload),
             "termination" => Ok(ProtocolExtensions::Termination),
+            "getting" => Ok(ProtocolExtensions::Getting),
             _ => Err(TuserError::UnknownExtension(value.clone())),
         }
     }
@@ -103,9 +105,10 @@ impl From<ProtocolExtensions> for String {
     /// original names.
     fn from(ext: ProtocolExtensions) -> Self {
         match ext {
-            ProtocolExtensions::Creation => Self::from("creation"),
-            ProtocolExtensions::CreationWithUpload => Self::from("creation-with-upload"),
-            ProtocolExtensions::Termination => Self::from("termination"),
+            ProtocolExtensions::Creation => "creation".into(),
+            ProtocolExtensions::CreationWithUpload => "creation-with-upload".into(),
+            ProtocolExtensions::Termination => "termination".into(),
+            ProtocolExtensions::Getting => "getting".into(),
         }
     }
 }
diff --git a/src/errors.rs b/src/errors.rs
index 60851b687f79b284261d3ae3d2a88bd5a621bc21..173b3feaa61d3d0634b35daad6a437032e2375ab 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -8,8 +8,8 @@ pub type TuserResult<T> = Result<T, TuserError>;
 
 #[derive(thiserror::Error, Debug)]
 pub enum TuserError {
-    #[error("File with id {0} was not found")]
-    FileNotFound(String),
+    #[error("Not found")]
+    FileNotFound,
     #[error("File with id {0} already exists")]
     FileAlreadyExists(String),
     #[error("Given offset is incorrect.")]
@@ -40,12 +40,14 @@ impl From<TuserError> for Error {
 
 impl ResponseError for TuserError {
     fn error_response(&self) -> HttpResponse {
-        HttpResponseBuilder::new(self.status_code()).body(format!("{}", self))
+        HttpResponseBuilder::new(self.status_code())
+            .set_header("Content-Type", "text/html; charset=utf-8")
+            .body(format!("{}", self))
     }
 
     fn status_code(&self) -> StatusCode {
         match self {
-            TuserError::FileNotFound(_) => StatusCode::NOT_FOUND,
+            TuserError::FileNotFound => StatusCode::NOT_FOUND,
             TuserError::WrongOffset => StatusCode::CONFLICT,
             _ => StatusCode::INTERNAL_SERVER_ERROR,
         }
diff --git a/src/protocol/core/routes.rs b/src/protocol/core/routes.rs
index 87e769bbb080bdef5a3678114233595e0f61ad47..9b5662244077758df94b8f30028853c0721f170a 100644
--- a/src/protocol/core/routes.rs
+++ b/src/protocol/core/routes.rs
@@ -30,6 +30,7 @@ pub async fn get_file_info(
         HttpResponseBuilder::new(StatusCode::OK)
             .set_header("Upload-Offset", file_info.offset.to_string())
             .set_header("Upload-Length", file_info.length.to_string())
+            .set_header("Content-Length", file_info.offset.to_string())
             .body("")
     } else {
         HttpResponseBuilder::new(StatusCode::NOT_FOUND).body("")
diff --git a/src/protocol/getting/mod.rs b/src/protocol/getting/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a63ceb7935f12dbbd98feb7034a6bf00b3c75f5b
--- /dev/null
+++ b/src/protocol/getting/mod.rs
@@ -0,0 +1,21 @@
+use actix_web::{guard, web};
+
+use crate::TuserConf;
+
+mod routes;
+
+/// Add getting extension.
+///
+/// This extension allows you
+/// to get uploaded file.
+///
+/// This is unofficial extension.
+pub fn add_extension(web_app: &mut web::ServiceConfig, app_conf: &TuserConf) {
+    web_app.service(
+        // GET /base/file
+        web::resource(app_conf.file_url().as_str())
+            .name("getting:get")
+            .guard(guard::Get())
+            .to(routes::get_file),
+    );
+}
diff --git a/src/protocol/getting/routes.rs b/src/protocol/getting/routes.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cdcebaff5f64a48cefc3c87b719fe7d5275d11be
--- /dev/null
+++ b/src/protocol/getting/routes.rs
@@ -0,0 +1,16 @@
+use actix_web::{HttpRequest, Responder, web};
+
+use crate::errors::TuserError;
+use crate::Storage;
+
+pub async fn get_file(
+    request: HttpRequest,
+    storage: web::Data<Box<dyn Storage + Send + Sync>>,
+) -> impl Responder {
+    let file_id_opt = request.match_info().get("file_id").map(String::from);
+    if let Some(file_id) = file_id_opt {
+        storage.get_contents(file_id.as_str()).await
+    } else {
+        Err(TuserError::FileNotFound)
+    }
+}
diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs
index ae3cd98d6729c610683c89e462c3fa675e4a45c3..64faf840ed90ce251826e7944e2d321ad7d6008f 100644
--- a/src/protocol/mod.rs
+++ b/src/protocol/mod.rs
@@ -6,6 +6,7 @@ use crate::TuserConf;
 mod core;
 mod creation;
 mod creation_with_upload;
+mod getting;
 mod termination;
 
 /// Configure TUS web application.
@@ -23,6 +24,9 @@ pub fn setup(app_conf: TuserConf) -> Box<dyn Fn(&mut web::ServiceConfig)> {
                 ProtocolExtensions::Termination => {
                     termination::add_extension(web_app, &app_conf);
                 }
+                ProtocolExtensions::Getting => {
+                    getting::add_extension(web_app, &app_conf);
+                }
             }
         }
         core::add_extension(web_app, &app_conf);
diff --git a/src/routes.rs b/src/routes.rs
index d510bfea02e86dffdb06c5a81b196876b01755e2..ce07d5828e87df3474b2f54be73ce62fde16385a 100644
--- a/src/routes.rs
+++ b/src/routes.rs
@@ -1,10 +1,9 @@
-use actix_web::dev::HttpResponseBuilder;
-use actix_web::http::StatusCode;
 use actix_web::HttpResponse;
 
+use crate::errors::{TuserError, TuserResult};
+
 /// Default response to all unknown URLs.
-pub fn not_found() -> HttpResponse {
-    HttpResponseBuilder::new(StatusCode::NOT_FOUND)
-        .set_header("Content-Type", "text/html; charset=utf-8")
-        .body("Not found")
+#[allow(clippy::unused_async)]
+pub async fn not_found() -> TuserResult<HttpResponse> {
+    Err(TuserError::FileNotFound)
 }
diff --git a/src/storages/file_storage.rs b/src/storages/file_storage.rs
index 433033f687ca5bdf72e5c7cd3c8eaeac45ff0894..26d1fc77393f50726277c60941374d7449bd7928 100644
--- a/src/storages/file_storage.rs
+++ b/src/storages/file_storage.rs
@@ -49,7 +49,7 @@ impl Storage for FileStorage {
     async fn get_file_info(&self, file_id: &str) -> TuserResult<FileInfo> {
         let info_path = self.info_file_path(file_id);
         if !info_path.exists() {
-            return Err(TuserError::FileNotFound(String::from(file_id)));
+            return Err(TuserError::FileNotFound);
         }
         let contents = read_to_string(info_path).await.map_err(|err| {
             error!("{:?}", err);
@@ -83,7 +83,10 @@ impl Storage for FileStorage {
     }
 
     async fn get_contents(&self, file_id: &str) -> TuserResult<NamedFile> {
-        Err(TuserError::FileNotFound(String::from(file_id)))
+        NamedFile::open(self.data_file_path(file_id)).map_err(|err| {
+            error!("{:?}", err);
+            TuserError::FileNotFound
+        })
     }
 
     async fn add_bytes(
@@ -162,11 +165,11 @@ impl Storage for FileStorage {
     async fn remove_file(&self, file_id: &str) -> TuserResult<()> {
         let info_path = self.info_file_path(file_id);
         if !info_path.exists() {
-            return Err(TuserError::FileNotFound(String::from(file_id)));
+            return Err(TuserError::FileNotFound);
         }
         let data_path = self.data_file_path(file_id);
         if !data_path.exists() {
-            return Err(TuserError::FileNotFound(String::from(file_id)));
+            return Err(TuserError::FileNotFound);
         }
         remove_file(info_path).await.map_err(|err| {
             error!("{:?}", err);
diff --git a/src/storages/mod.rs b/src/storages/mod.rs
index afeb42ace6b409b1d047a9b271c836a7cd019e09..ee35ba3963d43da13534665b5d3e214507d6ad4f 100644
--- a/src/storages/mod.rs
+++ b/src/storages/mod.rs
@@ -3,8 +3,8 @@ use std::str::FromStr;
 
 use actix_files::NamedFile;
 use async_trait::async_trait;
-use chrono::{DateTime, Utc};
 use chrono::serde::ts_seconds;
+use chrono::{DateTime, Utc};
 use derive_more::{Display, From};
 use serde::{Deserialize, Serialize};
 use sqlx::FromRow;
diff --git a/src/storages/sqlite_file_storage.rs b/src/storages/sqlite_file_storage.rs
index d0039dc514067fa1ab609b216d054409f534b9be..fcd401d3a56201868d83c36317eb10887a214da8 100644
--- a/src/storages/sqlite_file_storage.rs
+++ b/src/storages/sqlite_file_storage.rs
@@ -47,13 +47,23 @@ impl Storage for SQLiteFileStorage {
                 .map_err(|err| TuserError::UnableToPrepareStorage(err.to_string()))?;
         }
         if !self.app_conf.storage_opts.sqlite_dsn.exists() {
-            File::create(self.app_conf.storage_opts.sqlite_dsn.clone()).await.map_err(|err| {
-                TuserError::UnableToPrepareStorage(err.to_string())
-            })?;
+            File::create(self.app_conf.storage_opts.sqlite_dsn.clone())
+                .await
+                .map_err(|err| TuserError::UnableToPrepareStorage(err.to_string()))?;
         }
         let pool = SqlitePoolOptions::new()
             .max_connections(10)
-            .connect(format!("sqlite://{}", self.app_conf.storage_opts.sqlite_dsn.as_display().to_string()).as_str())
+            .connect(
+                format!(
+                    "sqlite://{}",
+                    self.app_conf
+                        .storage_opts
+                        .sqlite_dsn
+                        .as_display()
+                        .to_string()
+                )
+                .as_str(),
+            )
             .await
             .map_err(TuserError::from)?;
         sqlx::query(
@@ -67,7 +77,9 @@ impl Storage for SQLiteFileStorage {
                     deferred_size BOOLEAN, \
                     metadata TEXT\
                );",
-        ).execute(&pool).await?;
+        )
+        .execute(&pool)
+        .await?;
         self.pool = Some(pool);
         Ok(())
     }